You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
12 KiB

<?php
// Copyright 2014-2016 RealFaviconGenerator
define( 'RFG_PACKAGE_URL', 'package_url' );
define( 'RFG_COMPRESSION', 'compression' );
define( 'RFG_HTML_CODE', 'html_code' );
define( 'RFG_FILES_URLS', 'files_url' );
define( 'RFG_FILES_IN_ROOT', 'files_in_root' );
define( 'RFG_FILES_PATH', 'files_path' );
define( 'RFG_PREVIEW_PICTURE_URL', 'preview_picture_url' );
define( 'RFG_CUSTOM_PARAMETER', 'custom_parameter' );
define( 'RFG_VERSION', 'version' );
define( 'RFG_NON_INTERACTIVE_API_REQUEST', 'non_interactive_api_request' );
define( 'RFG_FAVICON_PRODUCTION_PACKAGE_PATH', 'favicon_production_package_path' );
define( 'RFG_FAVICON_COMPRESSED_PACKAGE_PATH', 'favicon_compressed_package_path' );
define( 'RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH', 'favicon_uncompressed_package_path' );
define( 'RFG_PREVIEW_PATH', 'preview_path' );
class Favicon_By_RealFaviconGenerator_Api_Response {
private $params = array();
public function __construct( $json ) {
if ( $json == NULL ) {
throw new InvalidArgumentException( "No response from RealFaviconGenerator" );
}
$response = json_decode( $json, true );
if ( $response == NULL ) {
throw new InvalidArgumentException( "JSON could not be parsed" );
}
$response = $this->getParam( $response, 'favicon_generation_result' );
$result = $this->getParam( $response, 'result' );
$status = $this->getParam( $result, 'status' );
if ( $status != 'success' ) {
$msg = $this->getParam( $result, 'error_message', false );
$msg = $msg != NULL ? $msg : 'An error occured';
throw new InvalidArgumentException( $msg );
}
$favicon = $this->getParam( $response, 'favicon' );
$this->params[RFG_PACKAGE_URL] = $this->getParam( $favicon, 'package_url' );
$this->params[RFG_COMPRESSION] = $this->getParam( $favicon, 'compression' ) == 'true';
$this->params[RFG_HTML_CODE] = $this->getParam( $favicon, 'html_code' );
$this->params[RFG_FILES_URLS] = $this->getParam( $favicon, 'files_urls' );
$filesLoc = $this->getParam( $response, 'files_location' );
$this->params[RFG_FILES_IN_ROOT] = $this->getParam( $filesLoc, 'type' ) == 'root';
$this->params[RFG_FILES_PATH] = $this->params[RFG_FILES_IN_ROOT] ? '/' : $this->getParam( $filesLoc, 'path' );
$this->params[RFG_PREVIEW_PICTURE_URL] = $this->getParam( $response, 'preview_picture_url', false );
$this->params[RFG_CUSTOM_PARAMETER] = $this->getParam( $response, 'custom_parameter', false );
$this->params[RFG_VERSION] = $this->getParam($response, 'version', false );
$this->params[RFG_NON_INTERACTIVE_API_REQUEST] = $this->getParam($response, 'non_interactive_request', false );
}
/**
* For example: <code>"http://realfavicongenerator.net/files/1234f5d2s34f3ds2/package.zip"</code>
*/
public function getPackageUrl() {
return $this->params[RFG_PACKAGE_URL];
}
/**
* For example: <code>array( "http://realfavicongenerator.net/files/1234f5d2s34f3ds2/apple-touch-icon.png", ... )</code>
*/
public function getFilesURLs() {
return $this->params[RFG_FILES_URLS];
}
/**
* For example: <code>"&lt;link ..."</code>
*/
public function getHtmlCode() {
return $this->params[RFG_HTML_CODE];
}
/**
* <code>true</code> if the user chose to compress the pictures, <code>false</code> otherwise.
*/
public function isCompressed() {
return $this->params[RFG_COMPRESSION];
}
/**
* <code>true</code> if the favicon files are to be stored in the root directory of the target web site, <code>false</code> otherwise.
*/
public function isFilesInRoot() {
return $this->params[RFG_FILES_IN_ROOT];
}
/**
* Indicate where the favicon files should be stored in the target web site. For example: <code>"/"</code>, <code>"/path/to/icons"</code>.
*/
public function getFilesLocation() {
return $this->params[RFG_FILES_PATH];
}
/**
* For example: <code>"http://realfavicongenerator.net/files/1234f5d2s34f3ds2/preview.png"</code>
*/
public function getPreviewUrl() {
return $this->params[RFG_PREVIEW_PICTURE_URL];
}
/**
* Return the customer parameter, as it was transmitted during the invocation of the API.
*/
public function getCustomParameter() {
return $this->params[RFG_CUSTOM_PARAMETER];
}
/**
* Return version of RealFaviconGenerator used to generate the favicon. Save this value to later check for updates.
*/
public function getVersion() {
return $this->params[RFG_VERSION];
}
/**
* Return the non-interactive API request that matches the current interactive request.
*/
public function getNonInteractiveAPIRequest() {
return $this->params[RFG_NON_INTERACTIVE_API_REQUEST];
}
private function getParam( $params, $paramName, $throwIfNotFound = true ) {
if ( isset( $params[$paramName] ) ) {
return $params[$paramName];
}
else if ( $throwIfNotFound ) {
throw new InvalidArgumentException( "Cannot find parameter " . $paramName );
}
}
/**
* Download and extract the files referenced by the response sent back by RealFaviconGenerator.
*
* Warning: as this method does HTTP accesses, calling it can take a few seconds. Better invoke it
* in an Ajax call, to not slow down the user experience.
*/
public function downloadAndUnpack( $outputDirectory = NULL ) {
global $wp_filesystem;
if ( $outputDirectory == NULL ) {
$outputDirectory = get_temp_dir();
}
$outputDirectory = $this->append_directory_separator( $outputDirectory );
if ( $this->getPackageUrl() != NULL ) {
$extractedPath = $outputDirectory . 'favicon_package';
if ( ! file_exists( $extractedPath ) ) {
if ( mkdir( $extractedPath, 0755, true ) !== true ) {
throw new InvalidArgumentException(
sprintf( __( 'Cannot create directory %s to store the favicon package content', FBRFG_PLUGIN_SLUG), $extractedPath ) );
}
}
try {
$this->downloadZipFile( $outputDirectory, $extractedPath, $this->getPackageUrl() );
}
catch(Exception $e) {
// Zip file download failed, try getting files directly
$this->downloadFilesDirectly( $extractedPath, array() );
}
}
if ( $this->getPreviewUrl() != NULL ) {
$previewPath = $outputDirectory . 'favicon_preview.png';
$this->downloadFile( $previewPath, $this->getPreviewUrl() );
$this->params[RFG_PREVIEW_PATH] = $previewPath;
}
}
public function downloadFilesDirectly( $outputDirectory, $filesURLs ) {
foreach($this->getFilesURLs() as $fileURL ) {
$parts = parse_url( $fileURL );
$filePath = $outputDirectory . DIRECTORY_SEPARATOR .
basename( $parts['path'] );
$this->downloadFile( $filePath, $fileURL );
}
$this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH] = $outputDirectory;
if ( $this->isCompressed() ) {
$this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = $extractedPath;
$this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = NULL;
}
else {
$this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = NULL;
$this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath;
}
}
public function downloadZipFile( $packageDirectory, $extractedPath, $packageUrl ) {
$packagePath = $packageDirectory . 'favicon_package.zip';
$this->downloadFile( $packagePath, $packageUrl );
$ret = WP_Filesystem();
$result = unzip_file( $packagePath, $extractedPath );
if ( $result !== true ) {
$explanation = ( is_wp_error( $result ) )
? $result->get_error_message()
: __( 'Unknown reason', Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG );
if ( get_class($wp_filesystem) != 'WP_Filesystem_Direct' ) {
$explanation .= ' ' . __( "Apparently WordPress has no direct access to the file system (it uses another mean such as FTP). " .
"This may be the root cause of this issue.", Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG );
}
throw new InvalidArgumentException(
sprintf( __( 'Error while unziping the favicon package %s to directory %s', Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG ),
$packagePath, $extractedPath ) . ': ' . $explanation );
}
if ( $this->isCompressed() ) {
// As of today, when the user chooses the compress the picture,
// the package is provided in two flavors, in two distinct directories.
// Later, only the compressed version will be provided. Thus, the following code
// handles both scenarios.
if ( is_dir( $extractedPath . DIRECTORY_SEPARATOR . 'compressed' ) ) {
$this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = $extractedPath .
DIRECTORY_SEPARATOR . 'compressed';
} else {
$this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = $extractedPath;
}
if ( is_dir( $extractedPath . DIRECTORY_SEPARATOR . 'uncompressed' ) ) {
$this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath .
DIRECTORY_SEPARATOR . 'uncompressed';
} else {
$this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath;
}
$this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH] = $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH];
}
else {
$this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH] = NULL;
$this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH] = $extractedPath;
$this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH] = $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH];
}
}
/**
* Directory where the compressed files are stored. Method <code>downloadAndUnpack</code> must be called first in order to populate this field.
* Can be <code>NULL</code>.
*/
public function getCompressedPackagePath() {
return $this->params[RFG_FAVICON_COMPRESSED_PACKAGE_PATH];
}
/**
* Directory where the uncompressed files are stored. Method <code>downloadAndUnpack</code> must be called first in order to populate this field.
* Can be <code>NULL</code>.
*/
public function getUncompressedPackagePath() {
return $this->params[RFG_FAVICON_UNCOMPRESSED_PACKAGE_PATH];
}
/**
* Directory where the production favicon files are stored.
* These are the files to deployed to the targeted web site. When the user asked for compression,
* this is the path to the compressed folder. Else, this is the path to the regular files folder.
* Method <code>downloadAndUnpack</code> must be called first in order to populate this field.
*/
public function getProductionPackagePath() {
return $this->params[RFG_FAVICON_PRODUCTION_PACKAGE_PATH];
}
/**
* Path to the preview picture.
*/
public function getPreviewPath() {
return $this->params[RFG_PREVIEW_PATH];
}
private function downloadFile( $localPath, $url ) {
$resp = wp_remote_get( $url, array( 'filename' => $localPath, 'stream' => true ) );
if ( ( $resp == NULL ) || ( $resp == false ) || ( is_wp_error( $resp ) ) || ( $resp['response'] == NULL ) ||
( $resp['response']['code'] == NULL ) || ( $resp['response']['code'] != 200 ) ) {
$explanation = is_wp_error( $resp ) ? ( ': ' . $resp->get_error_message() ) : '' ;
throw new InvalidArgumentException(
sprintf( __( 'Cannot download file at %s', Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG ), $url ) . $explanation );
}
if ( ( ! file_exists( $localPath ) ) || ( filesize( $localPath ) <= 0 ) ) {
throw new InvalidArgumentException( __( 'Cannot store downloaded file locally', Favicon_By_RealFaviconGenerator_Common::PLUGIN_SLUG ) );
}
}
public function append_directory_separator( $filename ) {
return $filename .
( ( $this->ends_with( $filename, DIRECTORY_SEPARATOR ))
? ''
: DIRECTORY_SEPARATOR );
}
// See http://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php#answer-10473026
public function ends_with( $haystack, $needle ) {
return $needle === "" ||
( ( $temp = strlen( $haystack ) - strlen( $needle ) ) >= 0
&& strpos( $haystack, $needle, $temp ) !== false );
}
}