Skip to content

Instantly share code, notes, and snippets.

@eugeneglova
Last active December 30, 2015 07:29
Show Gist options
  • Save eugeneglova/7796458 to your computer and use it in GitHub Desktop.
Save eugeneglova/7796458 to your computer and use it in GitHub Desktop.
html2canvas php proxy
<?php
/**
* html2canvas proxy script
*
* Provides proxy service for html2canvas.js lib.
* Responsible for output javascript callback with image url
* to provide work around for the same origin limitation.
*
* Used to ensure that project images are included in the export PNGs,
* as a client side JS request for the file will trip up on CORS issues.
*
* This script is locked down to certain origins and works only with images.
*
* The origin of the request should come from either:
* - *.typecast.com
* - *.frontinternal.net (our dev vhosts)
*
* Only images are allowed to be proxied through the script.
*
* Images are detected by content type header.
*
* @author Eugene Glova
*/
class Html2CanvasProxy {
// Reference to the url
private $url;
// Reference to the callback name
private $callback_name;
// List of the allowed origins
private $allowed_origins = array(
'typecast.com',
'frontinternal.net'
);
/**
* __construct
*
* Constructor. Accepts url and callback name
*
* @param string $url
* @param string $callback_name
* @return Html2CanvasProxy
*/
public function __construct($url, $callback_name) {
// Check url
if ( ! is_string($url) || strlen($url) < 1) return false;
// Check callback_name
if ( ! is_string($callback_name) || strlen($callback_name) < 1) return false;
// Check for origin
if ( ! $this->isAllowedOrigin()) return false;
// Set url
$this->url = $url;
// Set callback name
$this->callback_name = $callback_name;
return $this;
}
/**
* getContent
*
* Returns javascript callback with argument
*
* @return string
*/
public function getContent() {
// Set http headers
$this->setHeaders();
// Get callback with content
return $this->getCallback();
}
/**
* isAllowedOrigin
*
* Returns true if the http referer is in list of allowed origins
*
* @return boolean
*/
private function isAllowedOrigin() {
// Get http referer host
$host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
// Loop through allowed origins
foreach ($this->allowed_origins as $allowed_host) {
// Compare referer host with allowed origins
if (strstr($host, $allowed_host) === $allowed_host) return true;
}
return false;
}
/**
* setHeaders
*
* Sets application/javascript content type http header
*
* @return boolean
*/
private function setHeaders() {
// Set content type header for the output
header('Content-Type: application/javascript');
return true;
}
/**
* getImageBase64DataUrl
*
* Downloads image data by provided url
* and returns base64 encoded data url like
* data:image/png;base64,...
*
* @param string $url
* @return string
*/
private function getImageBase64DataUrl() {
// Get url scheme
$scheme = parse_url($this->url, PHP_URL_SCHEME);
// Check url scheme
if (strpos($scheme, 'http') !== 0) return false;
// Get data by url
$data = file_get_contents($this->url);
// Check data
if ( ! is_string($data) || strlen($data) < 1) return false;
// Get content type
foreach ($http_response_header as $header) {
// Check for image content type
if ( ! $this->isImageContentTypeHeader($header)) continue;
// Get content type
$content_type = $this->getContentTypeByHeader($header);
break;
}
// Check content type
if ( ! is_string($content_type) || strlen($content_type) < 1) return false;
return 'data:' . $content_type . ';base64,' . base64_encode($data);
}
/**
* isImageContentTypeHeader
*
* Returns true if 'Content-type' header is like 'image/jpeg'
*
* @param string $header
* @return boolean
*/
private function isImageContentTypeHeader($header) {
// Check header
if ( ! is_string($header) || strlen($header) < 1) return false;
// Check content type for image
if ( ! preg_match('/^content-type:\s*image\/\w+/i', $header)) return false;
return true;
}
/**
* getContentTypeByHeader
*
* Returns сontent type like 'image/jpeg'
*
* @param string $header
* @return string
*/
private function getContentTypeByHeader($header) {
// Check header
if ( ! is_string($header) || strlen($header) < 1) return false;
// Check for type and get it
if ( ! preg_match('/^content-type:\s*(\w+\/\w+)/i', $header, $matches)) return false;
return $matches[1];
}
/**
* getCallback
*
* Returns javascript callback
*
* @return string
*/
private function getCallback() {
return $this->callback_name . '(' . json_encode($this->getImageBase64DataUrl()) . ')';
}
}
// Create an instance of the class
$proxy = new Html2CanvasProxy($_GET['url'], $_GET['callback']);
// Output content
echo $proxy->getContent();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment