|
|
@@ -2,18 +2,20 @@
|
|
|
|
|
|
/*
|
|
|
* This file is part of the php-phantomjs.
|
|
|
- *
|
|
|
+ *
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
* file that was distributed with this source code.
|
|
|
*/
|
|
|
namespace JonnyW\PhantomJs;
|
|
|
|
|
|
-use JonnyW\PhantomJs\ClientInterface;
|
|
|
-use JonnyW\PhantomJs\Exception\NoPhantomJsException;
|
|
|
-use JonnyW\PhantomJs\Exception\CommandFailedException;
|
|
|
-use JonnyW\PhantomJs\Exception\NotWriteableException;
|
|
|
-use JonnyW\PhantomJs\Exception\InvalidUrlException;
|
|
|
-use JonnyW\PhantomJs\Response;
|
|
|
+use JonnyW\PhantomJs\ClientInterface;
|
|
|
+use JonnyW\PhantomJs\Exception\NoPhantomJsException;
|
|
|
+use JonnyW\PhantomJs\Exception\CommandFailedException;
|
|
|
+use JonnyW\PhantomJs\Exception\NotWriteableException;
|
|
|
+use JonnyW\PhantomJs\Message\FactoryInterface;
|
|
|
+use JonnyW\PhantomJs\Message\Factory;
|
|
|
+use JonnyW\PhantomJs\Message\RequestInterface;
|
|
|
+use JonnyW\PhantomJs\Message\ResponseInterface;
|
|
|
|
|
|
/**
|
|
|
* PHP PhantomJs
|
|
|
@@ -22,13 +24,6 @@ use JonnyW\PhantomJs\Response;
|
|
|
*/
|
|
|
class Client implements ClientInterface
|
|
|
{
|
|
|
- /**
|
|
|
- * Path to phantomJS executable
|
|
|
- *
|
|
|
- * @var string
|
|
|
- */
|
|
|
- protected $phantomJS;
|
|
|
-
|
|
|
/**
|
|
|
* Client instance
|
|
|
*
|
|
|
@@ -36,60 +31,110 @@ class Client implements ClientInterface
|
|
|
*/
|
|
|
private static $instance;
|
|
|
|
|
|
+ /**
|
|
|
+ * Message factory instance
|
|
|
+ *
|
|
|
+ * @var JonnyW\PhantomJs\Message\FactoryInterface
|
|
|
+ */
|
|
|
+ protected $factory;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Path to phantomJS executable
|
|
|
+ *
|
|
|
+ * @var string
|
|
|
+ */
|
|
|
+ protected $phantomJS;
|
|
|
+
|
|
|
/**
|
|
|
* Internal constructor
|
|
|
*
|
|
|
+ * @param JonnyW\PhantomJs\Message\FactoryInterface $factory
|
|
|
* @return void
|
|
|
*/
|
|
|
- public function __construct()
|
|
|
+ public function __construct(FactoryInterface $factory = null)
|
|
|
{
|
|
|
- $this->phantomJS = 'bin/phantomjs';
|
|
|
- $this->timeout = 5000;
|
|
|
+ if(!$factory instanceof FactoryInterface) {
|
|
|
+ $factory = Factory::getInstance();
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->factory = $factory;
|
|
|
+ $this->phantomJS = 'bin/phantomjs';
|
|
|
+ $this->timeout = 5000;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Get singleton instance
|
|
|
*
|
|
|
+ * @param JonnyW\PhantomJs\Message\FactoryInterface $factory
|
|
|
* @return JonnyW\PhantomJs\ClientInterface
|
|
|
*/
|
|
|
- public static function getInstance()
|
|
|
+ public static function getInstance(FactoryInterface $factory = null)
|
|
|
{
|
|
|
if(!self::$instance instanceof ClientInterface) {
|
|
|
- self::$instance = new Client();
|
|
|
+ self::$instance = new Client($factory);
|
|
|
}
|
|
|
|
|
|
return self::$instance;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
- * Open page and return HTML
|
|
|
+ * Get message factory instance
|
|
|
*
|
|
|
- * @param string $url
|
|
|
- * @return string
|
|
|
+ * @return JonnyW\PhantomJs\Message\FactoryInterface
|
|
|
*/
|
|
|
- public function open($url)
|
|
|
+ public function getMessageFactory()
|
|
|
{
|
|
|
- return $this->request($url, $this->openCmd);
|
|
|
+ return $this->factory;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
- * Screen capture URL
|
|
|
+ * Send request
|
|
|
*
|
|
|
- * @param string $url
|
|
|
- * @pram string $file
|
|
|
- * @return string
|
|
|
+ * @param JonnyW\PhantomJs\Message\RequestInterface $request
|
|
|
+ * @param JonnyW\PhantomJs\Message\ResponseInterface $response
|
|
|
+ * @param string $file
|
|
|
+ * @return JonnyW\PhantomJs\Message\ResponseInterface
|
|
|
+ */
|
|
|
+ public function send(RequestInterface $request, ResponseInterface $response, $file = null)
|
|
|
+ {
|
|
|
+ if(!is_null($file)) {
|
|
|
+ return $this->capture($request, $response, $file);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $this->open($request, $response);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Open page
|
|
|
+ *
|
|
|
+ * @param JonnyW\PhantomJs\Message\RequestInterface $request
|
|
|
+ * @param JonnyW\PhantomJs\Message\ResponseInterface $response
|
|
|
+ * @return JonnyW\PhantomJs\Message\ResponseInterface
|
|
|
+ */
|
|
|
+ public function open(RequestInterface $request, ResponseInterface $response)
|
|
|
+ {
|
|
|
+ return $this->request($request, $response, $this->openCmd);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Screen capture
|
|
|
+ *
|
|
|
+ * @param JonnyW\PhantomJs\Message\RequestInterface $request
|
|
|
+ * @param JonnyW\PhantomJs\Message\ResponseInterface $response
|
|
|
+ * @param string $file
|
|
|
+ * @return JonnyW\PhantomJs\Message\ResponseInterface
|
|
|
*/
|
|
|
- public function capture($url, $file)
|
|
|
+ public function capture(RequestInterface $request, ResponseInterface $response, $file)
|
|
|
{
|
|
|
if(!is_writable(dirname($file))) {
|
|
|
throw new NotWriteableException(sprintf('Path is not writeable by PhantomJs: %s', $file));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
$cmd = sprintf($this->captureCmd, $file);
|
|
|
-
|
|
|
- return $this->request($url, $cmd);
|
|
|
+
|
|
|
+ return $this->request($request, $response, $cmd);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Set new PhantomJs path
|
|
|
*
|
|
|
@@ -101,12 +146,12 @@ class Client implements ClientInterface
|
|
|
if(!file_exists($path) || !is_executable($path)) {
|
|
|
throw new NoPhantomJsException(sprintf('PhantomJs file does not exist or is not executable: %s', $path));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
$this->phantomJS = $path;
|
|
|
-
|
|
|
+
|
|
|
return $this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Set timeout period (in milliseconds)
|
|
|
*
|
|
|
@@ -116,74 +161,73 @@ class Client implements ClientInterface
|
|
|
public function setTimeout($period)
|
|
|
{
|
|
|
$this->timeout = $period;
|
|
|
-
|
|
|
+
|
|
|
return $this;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Call PhantomJs command
|
|
|
+ * Make PhantomJS request
|
|
|
*
|
|
|
- * @param string $url
|
|
|
+ * @param JonnyW\PhantomJs\Message\RequestInterface $request
|
|
|
+ * @param JonnyW\PhantomJs\Message\ResponseInterface $response
|
|
|
* @param string $cmd
|
|
|
- * @return JonnyW\PhantomJs\Response
|
|
|
+ * @return JonnyW\PhantomJs\Message\ResponseInterface
|
|
|
*/
|
|
|
- protected function request($url, $cmd)
|
|
|
+ protected function request(RequestInterface $request, ResponseInterface $response, $cmd)
|
|
|
{
|
|
|
- // Validate URL
|
|
|
- if(!filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)) {
|
|
|
- throw new InvalidUrlException(sprintf('Invalid URL provided: %s', $url));
|
|
|
- }
|
|
|
-
|
|
|
// Validate PhantomJS executable
|
|
|
if(!file_exists($this->phantomJS) || !is_executable($this->phantomJS)) {
|
|
|
throw new NoPhantomJsException(sprintf('PhantomJs file does not exist or is not executable: %s', $this->phantomJS));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
try {
|
|
|
-
|
|
|
+
|
|
|
$script = false;
|
|
|
-
|
|
|
+
|
|
|
$data = sprintf(
|
|
|
$this->wrapper,
|
|
|
+ $request->getHeaders('json'),
|
|
|
$this->timeout,
|
|
|
- $url,
|
|
|
+ $request->getUrl(),
|
|
|
+ $request->getMethod(),
|
|
|
+ $request->getBody(),
|
|
|
$cmd
|
|
|
);
|
|
|
-
|
|
|
- $script = $this->writeScript($data);
|
|
|
- $cmd = escapeshellcmd(sprintf("%s %s", $this->phantomJS, $script));
|
|
|
-
|
|
|
- $data = shell_exec($cmd);
|
|
|
- $data = $this->parse($data);
|
|
|
-
|
|
|
+
|
|
|
+ $script = $this->writeScript($data);
|
|
|
+ $cmd = escapeshellcmd(sprintf("%s %s", $this->phantomJS, $script));
|
|
|
+
|
|
|
+ $result = shell_exec($cmd);
|
|
|
+ $result = $this->parse($result);
|
|
|
+
|
|
|
$this->removeScript($script);
|
|
|
-
|
|
|
- $response = new Response($data);
|
|
|
+
|
|
|
+ $response->setData($result);
|
|
|
}
|
|
|
catch(NotWriteableException $e) {
|
|
|
throw $e;
|
|
|
}
|
|
|
catch(\Exception $e) {
|
|
|
-
|
|
|
+
|
|
|
$this->removeScript($script);
|
|
|
-
|
|
|
+
|
|
|
throw new CommandFailedException(sprintf('Error when executing PhantomJs command: %s - %s', $cmd, $e->getMessage()));
|
|
|
}
|
|
|
|
|
|
return $response;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Write temporary script file and
|
|
|
* return path to file
|
|
|
- *
|
|
|
+ *
|
|
|
* @param string $data
|
|
|
* @return JonnyW\PhantomJs\ClientInterface
|
|
|
*/
|
|
|
protected function writeScript($data)
|
|
|
{
|
|
|
$file = tempnam('/tmp', 'phantomjs');
|
|
|
-
|
|
|
+
|
|
|
// Could not create tmp file
|
|
|
if(!$file || !is_writable($file)) {
|
|
|
throw new NotWriteableException('Could not create tmp file on system. Please check your tmp directory and make sure it is writeable.');
|
|
|
@@ -191,15 +235,15 @@ class Client implements ClientInterface
|
|
|
|
|
|
// Could not write script data to tmp file
|
|
|
if(file_put_contents($file, $data) === false) {
|
|
|
-
|
|
|
+
|
|
|
$this->removeScript($file);
|
|
|
-
|
|
|
+
|
|
|
throw new NotWriteableException(sprintf('Could not write data to tmp file: %s. Please check your tmp directory and make sure it is writeable.', $file));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return $file;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Remove temporary script file
|
|
|
*
|
|
|
@@ -211,14 +255,14 @@ class Client implements ClientInterface
|
|
|
if($file && file_exists($file)) {
|
|
|
unlink($file);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return $this;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* If data from JSON string format
|
|
|
* and return array
|
|
|
- *
|
|
|
+ *
|
|
|
* @param string $data
|
|
|
* @return array
|
|
|
*/
|
|
|
@@ -228,57 +272,60 @@ class Client implements ClientInterface
|
|
|
if($data === null || !is_string($data)) {
|
|
|
return array();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Not a JSON string
|
|
|
if(substr($data, 0, 1) !== '{') {
|
|
|
return array();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Return decoded JSON string
|
|
|
return (array) json_decode($data, true);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* PhantomJs base wrapper
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
protected $wrapper = <<<EOF
|
|
|
-
|
|
|
+
|
|
|
var page = require('webpage').create(),
|
|
|
- response = {};
|
|
|
+ response = {},
|
|
|
+ headers = %1\$s;
|
|
|
|
|
|
- page.settings.resourceTimeout = %1\$s;
|
|
|
+ page.settings.resourceTimeout = %2\$s;
|
|
|
page.onResourceTimeout = function(e) {
|
|
|
response = e;
|
|
|
response.status = e.errorCode;
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
page.onResourceReceived = function (r) {
|
|
|
if(!response.status) response = r;
|
|
|
};
|
|
|
-
|
|
|
- page.open('%2\$s', function (status) {
|
|
|
-
|
|
|
+
|
|
|
+ page.customHeaders = headers ? headers : {};
|
|
|
+
|
|
|
+ page.open('%3\$s', '%4\$s', '%5\$s', function(status) {
|
|
|
+
|
|
|
if(status === 'success') {
|
|
|
- %3\$s
|
|
|
+ %6\$s
|
|
|
}
|
|
|
|
|
|
console.log(JSON.stringify(response, undefined, 4));
|
|
|
phantom.exit();
|
|
|
});
|
|
|
EOF;
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
- * PhantomJs screen capture
|
|
|
+ * PhantomJs screen capture
|
|
|
* command template
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
protected $captureCmd = <<<EOF
|
|
|
-
|
|
|
+
|
|
|
page.render('%1\$s');
|
|
|
-
|
|
|
+
|
|
|
response.content = page.evaluate(function () {
|
|
|
return document.getElementsByTagName('html')[0].innerHTML
|
|
|
});
|
|
|
@@ -291,7 +338,7 @@ EOF;
|
|
|
* @var string
|
|
|
*/
|
|
|
protected $openCmd = <<<EOF
|
|
|
-
|
|
|
+
|
|
|
response.content = page.evaluate(function () {
|
|
|
return document.getElementsByTagName('html')[0].innerHTML
|
|
|
});
|