diff --git a/.gitignore b/.gitignore index d18c28ba..fbe379d8 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ -cache -jobs +.idea/ + +vendor/ +#composer.lock +jobs/*.js + +/test.jpg diff --git a/bin/LICENSE.BSD b/bin/LICENSE.BSD new file mode 100644 index 00000000..d5dfdd1f --- /dev/null +++ b/bin/LICENSE.BSD @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/bin/README.md b/bin/README.md index c6062f3f..9c2a10c2 100755 --- a/bin/README.md +++ b/bin/README.md @@ -1,10 +1,38 @@ -Those are the required binaries of PhantomJS +# Info -Please download them from here +In this directory you can find the required binaries of [PhantomJS](http://phantomjs.org). +You can update them by downloading the binaries from [phantomjs.org](http://phantomjs.org/download.html). -http://phantomjs.org/download.html +We got all the info from the [Wiki](https://github.com/ariya/phantomjs/wiki/Screen-Capture). +# [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit -We got all the info from here https://github.com/ariya/phantomjs/wiki/Screen-Capture \ No newline at end of file +PhantomJS ([phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript. The latest [stable release](http://phantomjs.org/release-2.0.html) is version 2.0. + +**Note**: Please **do not** create a GitHub pull request **without** reading the [Contribution Guide](https://github.com/ariya/phantomjs/blob/master/CONTRIBUTING.md) first. Failure to do so may result in the rejection of the pull request. + +## Use Cases + +- **Headless web testing**. Lightning-fast testing without the browser is now possible! +- **Page automation**. [Access and manipulate](http://phantomjs.org/page-automation.html) web pages with the standard DOM API, or with usual libraries like jQuery. +- **Screen capture**. Programmatically [capture web contents](http://phantomjs.org/screen-capture.html), including CSS, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer. +- **Network monitoring**. Automate performance analysis, track [page loading](http://phantomjs.org/network-monitoring.html) and export as standard HAR format. + +## Features + +- **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, and other Unices. +- **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, and SVG. No emulation! +- **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, and Iron.io. +- **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes. + +## Questions? + +- Explore the complete [documentation](http://phantomjs.org/documentation/). +- Read tons of [user articles](http://phantomjs.org/buzz.html) on using PhantomJS. +- Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans. + +PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code. + +PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates. diff --git a/bin/_notes/dwsync.xml b/bin/_notes/dwsync.xml deleted file mode 100755 index 27627465..00000000 --- a/bin/_notes/dwsync.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/bin/linux32/phantomjs b/bin/linux32/phantomjs index fe1c9043..2091c115 100755 Binary files a/bin/linux32/phantomjs and b/bin/linux32/phantomjs differ diff --git a/bin/linux64/phantomjs b/bin/linux64/phantomjs index af9e4ab1..d72e801c 100755 Binary files a/bin/linux64/phantomjs and b/bin/linux64/phantomjs differ diff --git a/bin/phantomjs b/bin/phantomjs index af9e4ab1..d72e801c 100755 Binary files a/bin/phantomjs and b/bin/phantomjs differ diff --git a/bin/phantomjs.exe b/bin/phantomjs.exe index fb599db8..c644886c 100644 Binary files a/bin/phantomjs.exe and b/bin/phantomjs.exe differ diff --git a/bin/third-party.txt b/bin/third-party.txt new file mode 100644 index 00000000..48f74c42 --- /dev/null +++ b/bin/third-party.txt @@ -0,0 +1,36 @@ +This document contains the list of Third Party Software included with +PhantomJS, along with the license information. + +Third Party Software may impose additional restrictions and it is the +user's responsibility to ensure that they have met the licensing +requirements of PhantomJS and the relevant license of the Third Party +Software they are using. + +Qt - http://qt-project.org/ +License: GNU Lesser General Public License (LGPL) version 2.1. +Reference: http://qt-project.org/doc/qt-4.8/lgpl.html. + +WebKit - http://www.webkit.org/ +License: GNU Lesser General Public License (LGPL) version 2.1 and BSD. +Reference: http://www.webkit.org/coding/lgpl-license.html and +http://www.webkit.org/coding/bsd-license.html. + +Mongoose - https://github.com/cesanta/mongoose +License: MIT +Reference: https://github.com/cesanta/mongoose/commit/abbf27338ef554cce0281ac157aa71a9c1b82a55 + +OpenSSL - http://www.openssl.org/ +License: OpenSSL License, SSLeay License. +Reference: http://www.openssl.org/source/license.html. + +Linenoise - https://github.com/tadmarshall/linenoise +License: BSD. +Reference: https://github.com/tadmarshall/linenoise/blob/master/linenoise.h. + +QCommandLine - http://xf.iksaif.net/dev/qcommandline.html +License: GNU Lesser General Public License (LGPL) version 2.1. +Reference: http://dev.iksaif.net/projects/qcommandline/repository/revisions/master/entry/COPYING + +wkhtmlpdf - http://code.google.com/p/wkhtmltopdf/ +License: GNU Lesser General Public License (LGPL) +Reference: http://code.google.com/p/wkhtmltopdf/ diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..586e2e9e --- /dev/null +++ b/composer.json @@ -0,0 +1,34 @@ +{ + "name": "microweber/screen", + "description": "A PHP Class to interact with PhantomJs an capture screenshot of a webpage", + "keywords": [ + "phantomjs", + "screen", + "capture", + "print-screen" + ], + "license": "BSD", + "authors": [ + { + "name": "Peter Ivanov", + "email": "peter@microweber.com", + "homepage": "http://microweber.com" + }, + { + "name": "André Filipe", + "email": "andre.r.flip@gmail.com", + "homepage": "http://masnathan.com" + } + ], + "autoload": { + "psr-4": { + "Screen\\": "src/" + } + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "symfony/var-dumper": "~2.6" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..6d153a12 --- /dev/null +++ b/composer.lock @@ -0,0 +1,143 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "f81789fbef946ff667e5fef89237c33a", + "content-hash": "1e33f02fe8931940f01ca51bbb4abd93", + "packages": [], + "packages-dev": [ + { + "name": "symfony/polyfill-mbstring", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "1289d16209491b584839022f29257ad859b8532d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", + "reference": "1289d16209491b584839022f29257ad859b8532d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-01-20 09:13:37" + }, + { + "name": "symfony/var-dumper", + "version": "v2.8.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "ab94426d127ad9e95433778a3a451fe9d18f3d6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ab94426d127ad9e95433778a3a451fe9d18f3d6b", + "reference": "ab94426d127ad9e95433778a3a451fe9d18f3d6b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "twig/twig": "~1.20|~2.0" + }, + "suggest": { + "ext-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2016-01-07 13:38:40" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3" + }, + "platform-dev": [] +} diff --git a/index.php b/index.php index 33e304db..fdab0237 100755 --- a/index.php +++ b/index.php @@ -1,23 +1,23 @@ - -Screenshot - - + + Screenshot + + -
-
- Take a screenshot -
- - + +
+ Take a screenshot +
+ + -
- -
+
+ +

diff --git a/jobs/.gitkeep b/jobs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/shot.php b/shot.php index 2e5dea9a..1cafeab1 100755 --- a/shot.php +++ b/shot.php @@ -1,150 +1,47 @@ '); - -} -if (!is_dir($cache)) { - mkdir($cache); - file_put_contents($cache . 'index.php', ''); +require_once 'vendor/autoload.php'; +if (!isset($_REQUEST['url'])) { + exit; } +$screen = new Screen\Capture($_REQUEST['url']); -$w = 1024; -$h = 768; - -if (isset($_REQUEST['w'])) { - $w = intval($_REQUEST['w']); +if (isset($_REQUEST['w'])) { // Width + $screen->setWidth(intval($_REQUEST['w'])); } -if (isset($_REQUEST['h'])) { - $h = intval($_REQUEST['h']); +if (isset($_REQUEST['h'])) { // Height + $screen->setHeight(intval($_REQUEST['h'])); } -if (isset($_REQUEST['clipw'])) { - $clipw = intval($_REQUEST['clipw']); +if (isset($_REQUEST['clipw'])) { // Clip Width + $screen->setClipWidth(intval($_REQUEST['clipw'])); } -if (isset($_REQUEST['cliph'])) { - $cliph = intval($_REQUEST['cliph']); +if (isset($_REQUEST['cliph'])) { // Clip Height + $screen->setClipHeight(intval($_REQUEST['cliph'])); } if (isset($_REQUEST['download'])) { $download = $_REQUEST['download']; } -$url = strip_tags($url); -$url = str_replace(';', '', $url); -$url = str_replace('"', '', $url); -$url = str_replace('\'', '/', $url); -$url = str_replace('= $cache_life)) { - $refresh = true; - } -} - - -$url = escapeshellcmd($url); - -if (!is_file($cache_job) or $refresh == true) { - $src = " - - var page = require('webpage').create(); - - page.viewportSize = { width: {$w}, height: {$h} }; - - "; - - if (isset($clipw) && isset($cliph)) { - $src .= "page.clipRect = { top: 0, left: 0, width: {$clipw}, height: {$cliph} };"; - } - - $src .= " - - page.open('{$url}', function () { - page.render('{$screen_file}'); - phantom.exit(); - }); - - - "; - - $job_file = $jobs . $url_segs['host'] . crc32($src) . '.js'; - file_put_contents($job_file, $src); - - $exec = $bin_files . 'phantomjs ' . $job_file; - - $escaped_command = escapeshellcmd($exec); - - exec($escaped_command); - - if (is_file($here . $screen_file)) { - rename($here . $screen_file, $cache_job); - } -} - - -if (is_file($cache_job)) { - if ($download != false) { - $file = $cache_job; - $file_name=basename($file); - $type = 'image/jpeg'; - header("Content-disposition: attachment; filename={$file_name}"); - header("Content-type: {$type}"); - readfile($file); - } else { - $file = $cache_job; - $type = 'image/jpeg'; - header('Content-Type:' . $type); - header('Content-Length: ' . filesize($file)); - readfile($file); - } +$fileLocation = 'test.jpg'; +$screen->save($fileLocation); +if (isset($_REQUEST['download']) && $_REQUEST['download']) { + $parsedUrl = parse_url($_REQUEST['url']); + $fileName = 'ScreeCapture-' . $parsedUrl['host'] . '.jpg'; + $type = 'image/jpeg'; + header("Content-disposition: attachment; filename={$fileName}"); + header("Content-type: {$type}"); + readfile($fileLocation); +} else { + $type = 'image/jpeg'; + header('Content-Type:' . $type); + header('Content-Length: ' . filesize($fileLocation)); + readfile($fileLocation); } - - - - - - diff --git a/src/Capture.php b/src/Capture.php new file mode 100644 index 00000000..895310b9 --- /dev/null +++ b/src/Capture.php @@ -0,0 +1,202 @@ +url = $url; + + $this->binPath = realpath(implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), '..', 'bin'))) . DIRECTORY_SEPARATOR; + $this->templatePath = realpath(implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), '..', 'templates'))) . DIRECTORY_SEPARATOR; + $this->jobsPath = implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), '..', 'jobs')); + if (!is_dir($this->jobsPath)) { + mkdir($this->jobsPath, 0755); + } + $this->jobsPath = realpath($this->jobsPath) . DIRECTORY_SEPARATOR; + } + + public function save($imageLocation, $deleteFileIfExists = true) + { + $data = array( + 'url' => $this->url, + 'width' => $this->width, + 'height' => $this->height, + 'clipWidth' => $this->clipWidth, + 'clipHeight' => $this->clipHeight, + 'imageLocation' => $imageLocation, + ); + + if ($deleteFileIfExists && file_exists($imageLocation)) { + unlink($imageLocation); + } + + $jobName = md5(json_encode($data)); + $jobPath = $this->jobsPath . $jobName . '.js'; + + if (!is_file($jobPath)) { + // Now we write the code to a js file + $resultString = $this->getTemplateResult('screen-capture', $data); + file_put_contents($jobPath, $resultString); + } + + $command = sprintf("%sphantomjs %s", $this->binPath, $jobPath); + exec(escapeshellcmd($command)); + + return file_exists($imageLocation); + } + + private function getTemplateResult($templateName, array $args) + { + $templatePath = $this->templatePath . DIRECTORY_SEPARATOR . $templateName . '.php'; + if (!file_exists($templatePath)) { + throw new \Exception("The template {$templateName} does not exist!"); + } + ob_start(); + extract($args); + include_once $this->templatePath . DIRECTORY_SEPARATOR . $templateName . '.php'; + + return ob_get_clean(); + } + + /** + * Sets the page width + * + * @param int $width Page Width + * + * @return Capture + */ + public function setWidth($width) + { + $this->width = $width; + + return $this; + } + + /** + * Sets the page height + * + * @param int $height Page Height + * + * @return Capture + */ + public function setHeight($height) + { + $this->height = $height; + + return $this; + } + + /** + * Sets the width to clip + * + * @param int $clipWidth Page clip width + * + * @return Capture + */ + public function setClipWidth($clipWidth) + { + $this->clipWidth = $clipWidth; + + return $this; + } + + /** + * Sets the height to clip + * + * @param int $clipHeight Page clip height + * + * @return Capture + */ + public function setClipHeight($clipHeight) + { + $this->clipHeight = $clipHeight; + + return $this; + } +} diff --git a/templates/screen-capture.php b/templates/screen-capture.php new file mode 100644 index 00000000..e05afc86 --- /dev/null +++ b/templates/screen-capture.php @@ -0,0 +1,22 @@ +var page = require('webpage').create(); + +page.viewportSize = {width: , height: }; + + +page.clipRect = { + top: 0, + left: 0, + width: , + height: +}; + + +page.open('', function () { + /* This will set the page background color white */ + page.evaluate(function() { + document.body.bgColor = '#FFFFFF'; + }); + + page.render(''); + phantom.exit(); +});