Screenshots von Webseiten erstellen mit PHP
Einen einfachen manuellen Screenshot von einer Webseite zu erstellen ist einfach, brauche ich hier wohl nicht extra erläutern. Wenn man allerdings aus seiner PHP-Applikation Screenshots von Webseiten erstellen möchte oder keine Lust hat auf manuelles Zusammenkopieren weil die Webseite sehr lang oder breit ist, hilft das Projekt wkhtmltopdf. Dieses Kommandozeilentool gibt es für Windows, Linux und Mac, und es läuft auch auf Servern ohne grafische Oberfläche. Auf der Webseite des Projekts findet man sowohl wkhtmltopdf als auch wkhtmltoimage. wk steht dabei für die Webkit Render Engine, die aus einem gegebenen HTML-Input entweder ein PDF oder ein Bild (jpg, png, tiff) erstellt.
Ich werde hier zeigen wie man Bilder erstellt, die Installation ist einfach: Man lädt sich die passende Version herunter, in meinem Fall für einen Debian-Server ist das wkhtmltoimage-0.10.0_rc2-static-i386.tar.bz2 . Die darin enthaltene Datei kopiere ich nach /usr/local/bin , falls bei euch open_basedir aktiv ist muss es natürlich irgendwo in ein erlaubtes Verzeichnis.
wget http://wkhtmltopdf.googlecode.com/files/wkhtmltoimage-0.10.0_rc2-static-i386.tar.bz2 tar -xjvf wkhtmltoimage-0.10.0_rc2-static-i386.tar.bz2 mv wkhtmltoimage-i386 /usr/local/bin/
Ein erster kleiner Test von der Konsole:
wkhtmltoimage-i386 http://www.phpgangsta.de phpgangsta.de.jpg
Hier das Ergebnis (klicken für das Original Bild):
Gar nicht schlecht! Schauen wir uns als nächstes den Aufruf aus PHP heraus an.
<? passthru('/usr/local/bin/wkhtmltoimage-i386 http://www.phpgangsta.de phpgangsta.de.jpg');
So einfach kann es sein! Natürlich möchte man dies variabel machen, sodass man von jeder beliebigen Webseite Screenshots erstellen kann, und auch das Format oder die Qualität wählen kann. Bei der Arbeit mit Aufrufen wie passthru() oder auch shell_exec(), exec() etc. sollte man immer aufpassen dass man die übergebenen Parameter gut prüft und entschärft (escapeshellcmd und escapeshellarg)
Auf dieser Webseite kann die Funktionalität übrigens getestet werden:
http://screenshot.phpgangsta.de
Ich habe auf GitHub die Klasse WebsiteToImage angelegt mit der die Screenshoterstellung gekapselt und vereinfacht wird. Ich freue mich natürlich über weitere implementierte Features und Pull Requests!
Aktuell sieht die Klasse so aus:
<?php class WebsiteToImage { const FORMAT_JPG = 'jpg'; const FORMAT_JPEG = 'jpeg'; const FORMAT_PNG = 'png'; const FORMAT_TIF = 'tif'; const FORMAT_TIFF = 'tiff'; protected $_programPath; protected $_outputFile; protected $_url; protected $_format = self::FORMAT_JPG; protected $_quality = 90; public function start() { $programPath = escapeshellcmd($this->_programPath); $outputFile = escapeshellarg($this->_outputFile); $url = escapeshellarg($this->_url); $format = escapeshellarg($this->_format); $quality = escapeshellarg($this->_quality); $command = "$programPath --format $format --quality $quality $url $outputFile"; exec($command); } public function setOutputFile($outputFile) { clearstatcache(); if (!is_writable(dirname($outputFile))) { throw new Exception('output file not writable'); } $this->_outputFile = $outputFile; return $this; } public function getOutputFile() { return $this->_outputFile; } public function setProgramPath($programPath) { $this->_programPath = $programPath; return $this; } public function getProgramPath() { return $this->_programPath; } public function setFormat($format) { $this->_format = $format; return $this; } public function getFormat() { return $this->_format; } public function setQuality($quality) { $this->_quality = (int)$quality; return $this; } public function getQuality() { return $this->_quality; } public function setUrl($url) { $this->_url = $url; return $this; } public function getUrl() { return $this->_url; } }
Und so wird sie benutzt:
<?php require_once 'WebsiteToImage.php'; $websiteToImage = new WebsiteToImage(); $websiteToImage->setProgramPath('/usr/local/bin/wkhtmltoimage-i386') ->setOutputFile('www.phpgangsta.de.jpg') ->setQuality(70) ->setUrl('http://www.phpgangsta.de') ->start(); $websiteToImage->setFormat(WebsiteToImage::FORMAT_PNG) ->setOutputFile('www.phpgangsta.de.png') ->start();
wkhtmltoimage hat viele interessante Funktionalitäten, beispielsweise kann man nur einen bestimmten Bereich ausschneiden, die Höhe und die Breite einstellen, die Qualität und das Format ändern. Aber es geht noch sehr viel mehr wie man unten sieht, man kann Javascript deaktivieren, Bilder auf der Webseite nicht laden, ein HTTP Authentifizierungspasswort angeben falls benötigt, einen Proxy einstellen, einen Zoomfaktor wählen und vieles mehr.
Hier die “erweiterte Hilfe”:
wkhtmltoimage-i386 -H Name: wkhtmltoimage 0.10.0 rc2 Synopsis: wkhtmltoimage [OPTIONS]... <input file> <output file> Description: Converts an HTML page into an image, General Options: --allow <path> Allow the file or files from the specified folder to be loaded (repeatable) --checkbox-checked-svg <path> Use this SVG file when rendering checked checkboxes --checkbox-svg <path> Use this SVG file when rendering unchecked checkboxes --cookie <name> <value> Set an additional cookie (repeatable) --cookie-jar <path> Read and write cookies from and to the supplied cookie jar file --crop-h <int> Set height for croping --crop-w <int> Set width for croping --crop-x <int> Set x coordinate for croping --crop-y <int> Set y coordinate for croping --custom-header <name> <value> Set an additional HTTP header (repeatable) --custom-header-propagation Add HTTP headers specified by --custom-header for each resource request. --no-custom-header-propagation Do not add HTTP headers specified by --custom-header for each resource request. --debug-javascript Show javascript debugging output --no-debug-javascript Do not show javascript debugging output (default) --encoding <encoding> Set the default text encoding, for input -H, --extended-help Display more extensive help, detailing less common command switches -f, --format <format> Output file format (default is jpg) --height <int> Set screen height (default is calculated from page content) (default 0) -h, --help Display help --htmldoc Output program html help --images Do load or print images (default) --no-images Do not load or print images -n, --disable-javascript Do not allow web pages to run javascript --enable-javascript Do allow web pages to run javascript (default) --javascript-delay <msec> Wait some milliseconds for javascript finish (default 200) --load-error-handling <handler> Specify how to handle pages that fail to load: abort, ignore or skip (default abort) --disable-local-file-access Do not allowed conversion of a local file to read in other local files, unless explecitily allowed with --allow --enable-local-file-access Allowed conversion of a local file to read in other local files. (default) --manpage Output program man page --minimum-font-size <int> Minimum font size --password <password> HTTP Authentication password --disable-plugins Disable installed plugins (default) --enable-plugins Enable installed plugins (plugins will likely not work) --post <name> <value> Add an additional post field (repeatable) --post-file <name> <path> Post an additional file (repeatable) -p, --proxy <proxy> Use a proxy --quality <int> Output image quality (between 0 and 100) (default 94) --radiobutton-checked-svg <path> Use this SVG file when rendering checked radiobuttons --radiobutton-svg <path> Use this SVG file when rendering unchecked radiobuttons --readme Output program readme --run-script <js> Run this additional javascript after the page is done loading (repeatable) -0, --disable-smart-width Use the specified width even if it is not large enough for the content --stop-slow-scripts Stop slow running javascripts (default) --no-stop-slow-scripts Do not Stop slow running javascripts (default) --transparent Make the background transparent in pngs --use-xserver Use the X server (some plugins and other stuff might not work without X11) --user-style-sheet <url> Specify a user style sheet, to load with every page --username <username> HTTP Authentication username -V, --version Output version information an exit --width <int> Set screen width (default is 1024) (default 1024) --window-status <windowStatus> Wait until window.status is equal to this string before rendering page --zoom <float> Use this zoom factor (default 1)
Es gibt auch das PHP-Binding Projekt php-wkhtmltox für die C-Bibliothek libwkhtmltox, sodass man es als PHP-Extension nutzen kann (extension=phpwkhtmltox.so).