2016-12-27 14:30:54 +13:00
< ? php
/**
* @ package WP Static HTML Output
*
* Copyright ( c ) 2011 Leon Stafford
*/
/**
* WP Static HTML Output Plugin
*/
2017-03-11 14:50:49 +13:00
class StaticHtmlOutput {
2017-03-11 21:33:36 +13:00
const VERSION = '1.2.2' ;
2016-12-27 14:30:54 +13:00
const OPTIONS_KEY = 'wp-static-html-output-options' ;
/**
* The hook used in all actions and filters
*/
const HOOK = 'wp-static-html-output' ;
/**
* Singleton instance
* @ var StaticHtmlOutput
*/
protected static $_instance = null ;
/**
* An instance of the options structure containing all options for this plugin
* @ var StaticHtmlOutput_Options
*/
protected $_options = null ;
/**
* View object
* @ var StaticHtmlOutput_View
*/
protected $_view = null ;
/**
* Export log ( list of processed urls )
* @ var array
*/
protected $_exportLog = array ();
/**
* Singleton pattern implementation makes " new " unavailable
* @ return void
*/
2017-03-11 14:50:49 +13:00
protected function __construct () {}
2016-12-27 14:30:54 +13:00
/**
* Singleton pattern implementation makes " clone " unavailable
* @ return void
*/
2017-03-11 14:50:49 +13:00
protected function __clone () {}
2016-12-27 14:30:54 +13:00
/**
* Returns an instance of WP Static HTML Output Plugin
* Singleton pattern implementation
* @ return StaticHtmlOutput
*/
2017-03-11 14:50:49 +13:00
public static function getInstance () {
if ( null === self :: $_instance ) {
2016-12-27 14:30:54 +13:00
self :: $_instance = new self ();
self :: $_instance -> _options = new StaticHtmlOutput_Options ( self :: OPTIONS_KEY );
self :: $_instance -> _view = new StaticHtmlOutput_View ();
}
return self :: $_instance ;
}
/**
* Initializes singleton instance and assigns hooks callbacks
* @ param string $bootstrapFile
* @ return StaticHtmlOutput
*/
2017-03-11 14:50:49 +13:00
public static function init ( $bootstrapFile ) {
2016-12-27 14:30:54 +13:00
$instance = self :: getInstance ();
register_activation_hook ( $bootstrapFile , array ( $instance , 'activate' ));
2017-03-11 14:50:49 +13:00
if ( is_admin ()) {
2016-12-27 14:30:54 +13:00
add_action ( 'admin_menu' , array ( $instance , 'registerOptionsPage' ));
add_action ( self :: HOOK . '-saveOptions' , array ( $instance , 'saveOptions' ));
}
return $instance ;
}
2017-03-11 14:50:49 +13:00
public function activate () {
if ( null === $this -> _options -> getOption ( 'version' )) {
2016-12-27 14:30:54 +13:00
$this -> _options
-> setOption ( 'version' , self :: VERSION )
2017-03-07 12:13:28 +13:00
-> setOption ( 'static_export_settings' , self :: VERSION )
2016-12-27 14:30:54 +13:00
-> save ();
}
}
2017-03-11 14:50:49 +13:00
public function registerOptionsPage () {
2016-12-27 14:30:54 +13:00
$page = add_submenu_page ( 'tools.php' , __ ( 'WP Static HTML Output' , 'static-html-output-plugin' ), __ ( 'WP Static HTML Output' , 'static-html-output-plugin' ), 'manage_options' , self :: HOOK . '-options' , array ( $this , 'renderOptionsPage' ));
add_action ( 'admin_print_styles-' . $page , array ( $this , 'enqueueAdminStyles' ));
}
2017-03-11 14:50:49 +13:00
public function enqueueAdminStyles () {
2016-12-27 14:30:54 +13:00
$pluginDirUrl = plugin_dir_url ( dirname ( __FILE__ ));
wp_enqueue_style ( self :: HOOK . '-admin' , $pluginDirUrl . '/css/wp-static-html-output.css' );
}
/**
* Renders the general options page .
* Fires saveOptions action hook .
* @ return void
*/
2017-03-11 14:50:49 +13:00
public function renderOptionsPage () {
2016-12-27 14:30:54 +13:00
// Check system requirements
$uploadDir = wp_upload_dir ();
$uploadsFolderWritable = $uploadDir && is_writable ( $uploadDir [ 'path' ]);
$supportsZipArchives = extension_loaded ( 'zip' );
$permalinksStructureDefined = strlen ( get_option ( 'permalink_structure' ));
2017-03-11 14:50:49 +13:00
if ( ! $uploadsFolderWritable || ! $supportsZipArchives || ! $permalinksStructureDefined ) {
2016-12-27 14:30:54 +13:00
$this -> _view
-> setTemplate ( 'system-requirements' )
-> assign ( 'uploadsFolderWritable' , $uploadsFolderWritable )
-> assign ( 'supportsZipArchives' , $supportsZipArchives )
-> assign ( 'permalinksStructureDefined' , $permalinksStructureDefined )
2016-12-27 20:19:22 +13:00
-> assign ( 'uploadsFolder' , $uploadDir )
2016-12-27 14:30:54 +13:00
-> render ();
2017-03-11 14:50:49 +13:00
} else {
2017-03-07 13:26:34 +13:00
2016-12-27 14:30:54 +13:00
do_action ( self :: HOOK . '-saveOptions' );
2016-12-29 16:20:49 +13:00
$this -> _view
-> setTemplate ( 'options-page' )
-> assign ( 'exportLog' , $this -> _exportLog )
2017-03-07 13:26:34 +13:00
-> assign ( 'staticExportSettings' , $this -> _options -> getOption ( 'static-export-settings' ))
2016-12-29 16:20:49 +13:00
-> assign ( 'onceAction' , self :: HOOK . '-options' )
-> render ();
2016-12-27 14:30:54 +13:00
}
}
2017-03-11 14:50:49 +13:00
public function saveOptions () {
if ( ! isset ( $_POST [ 'action' ]) || 'generate' != $_POST [ 'action' ]) {
2017-03-07 13:26:34 +13:00
error_log ( 'didnt detect the generate action' );
2016-12-27 14:30:54 +13:00
return ;
}
2017-03-11 14:50:49 +13:00
if ( ! check_admin_referer ( self :: HOOK . '-options' ) || ! current_user_can ( 'manage_options' )) {
2017-03-07 13:26:34 +13:00
error_log ( 'user didnt have permissions to change options' );
2016-12-27 14:30:54 +13:00
exit ( 'You cannot change WP Static HTML Output Plugin options.' );
}
2017-03-07 13:26:34 +13:00
2016-12-27 14:30:54 +13:00
$this -> _options
2017-03-07 12:13:28 +13:00
-> setOption ( 'static-export-settings' , filter_input ( INPUT_POST , 'staticExportSettings' , FILTER_SANITIZE_URL ))
2016-12-27 14:30:54 +13:00
-> save ();
2016-12-29 14:45:16 +13:00
2017-03-07 13:26:34 +13:00
error_log ( 'saving options!!!' );
2016-12-29 14:45:16 +13:00
$message = 'Options have been updated successfully.' ;
$this -> _view -> setTemplate ( 'message' )
-> assign ( 'message' , $message )
-> render ();
2016-12-29 16:20:49 +13:00
}
2016-12-29 14:45:16 +13:00
2017-03-11 14:50:49 +13:00
public function genArch () {
2016-12-27 14:30:54 +13:00
$archiveUrl = $this -> _generateArchive ();
2017-03-11 14:50:49 +13:00
if ( is_wp_error ( $archiveUrl )) {
2016-12-27 14:30:54 +13:00
$message = 'Error: ' . $archiveUrl -> get_error_code ;
2017-03-11 14:50:49 +13:00
} else {
2016-12-27 14:30:54 +13:00
$message = sprintf ( 'Archive created successfully: <a href="%s">Download archive</a>' , $archiveUrl );
if ( $this -> _options -> getOption ( 'retainStaticFiles' ) == 1 )
{
$message .= sprintf ( '<br />Static files retained at: %s/' , str_replace ( home_url (), '' , substr ( $archiveUrl , 0 , - 4 )));
}
}
$this -> _view -> setTemplate ( 'message' )
-> assign ( 'message' , $message )
2016-12-29 17:22:51 +13:00
-> assign ( 'exportLog' , $this -> _exportLog )
2016-12-27 14:30:54 +13:00
-> render ();
2016-12-29 16:20:49 +13:00
}
2016-12-27 14:30:54 +13:00
/**
* Generates ZIP archive
* @ return string | WP_Error
*/
protected function _generateArchive ()
{
global $blog_id ;
set_time_limit ( 0 );
2017-02-20 23:54:03 +13:00
2016-12-27 14:30:54 +13:00
$uploadDir = wp_upload_dir ();
$exporter = wp_get_current_user ();
$archiveName = $uploadDir [ 'path' ] . '/' . self :: HOOK . '-' . $blog_id . '-' . time () . '-' . $exporter -> user_login ;
$archiveDir = $archiveName . '/' ;
if ( ! file_exists ( $archiveDir ))
{
wp_mkdir_p ( $archiveDir );
}
2017-02-20 23:54:03 +13:00
2016-12-27 14:30:54 +13:00
$baseUrl = untrailingslashit ( home_url ());
2017-02-20 23:54:03 +13:00
$newBaseUrl = untrailingslashit ( filter_input ( INPUT_POST , 'baseUrl' , FILTER_SANITIZE_URL ));
2016-12-27 14:30:54 +13:00
$urlsQueue = array_unique ( array_merge (
array ( trailingslashit ( $baseUrl )),
$this -> _getListOfLocalFilesByUrl ( array ( get_template_directory_uri ())),
2017-02-20 23:54:03 +13:00
$this -> _getListOfLocalFilesByUrl ( explode ( " \n " , filter_input ( INPUT_POST , 'additionalUrls' )))
2016-12-27 14:30:54 +13:00
));
$this -> _exportLog = array ();
while ( count ( $urlsQueue ))
{
$currentUrl = array_shift ( $urlsQueue );
//echo "Processing ". $currentUrl."<br />";
2017-02-20 23:54:03 +13:00
$urlResponse = new StaticHtmlOutput_UrlRequest ( $currentUrl , filter_input ( INPUT_POST , 'cleanMeta' ));
2016-12-27 14:30:54 +13:00
$urlResponse -> cleanup ();
// Add current url to the list of processed urls
$this -> _exportLog [ $currentUrl ] = true ;
2017-03-11 14:50:49 +13:00
foreach ( $urlResponse -> extractAllUrls ( $baseUrl ) as $newUrl ) {
if ( ! isset ( $this -> _exportLog [ $newUrl ]) && $newUrl != $currentUrl && ! in_array ( $newUrl , $urlsQueue )) {
2016-12-27 14:30:54 +13:00
//echo "Adding ".$newUrl." to the list<br />";
$urlsQueue [] = $newUrl ;
}
}
$urlResponse -> replaceBaseUlr ( $baseUrl , $newBaseUrl );
$this -> _saveUrlData ( $urlResponse , $archiveDir );
}
$tempZip = $archiveName . '.tmp' ;
$zipArchive = new ZipArchive ();
2017-03-11 14:50:49 +13:00
if ( $zipArchive -> open ( $tempZip , ZIPARCHIVE :: CREATE ) !== true ) {
2016-12-27 14:30:54 +13:00
return new WP_Error ( 'Could not create archive' );
}
$iterator = new RecursiveIteratorIterator ( new RecursiveDirectoryIterator ( $archiveDir ));
2017-03-11 14:50:49 +13:00
foreach ( $iterator as $fileName => $fileObject ) {
2016-12-27 14:30:54 +13:00
$baseName = basename ( $fileName );
2017-03-11 14:50:49 +13:00
if ( $baseName != '.' && $baseName != '..' ) {
if ( ! $zipArchive -> addFile ( realpath ( $fileName ), str_replace ( $archiveDir , '' , $fileName ))) {
2016-12-27 14:30:54 +13:00
return new WP_Error ( 'Could not add file: ' . $fileName );
}
}
}
$zipArchive -> close ();
rename ( $tempZip , $archiveName . '.zip' );
2017-03-10 15:25:19 +13:00
2017-03-11 14:50:49 +13:00
if ( filter_input ( INPUT_POST , 'sendViaFTP' ) == 1 ) {
2017-03-10 15:25:19 +13:00
require_once ( __DIR__ . '/FTP/FtpClient.php' );
require_once ( __DIR__ . '/FTP/FtpException.php' );
require_once ( __DIR__ . '/FTP/FtpWrapper.php' );
$ftp = new \FtpClient\FtpClient ();
$ftp -> connect ( filter_input ( INPUT_POST , 'ftpServer' ));
$ftp -> login ( filter_input ( INPUT_POST , 'ftpUsername' ), filter_input ( INPUT_POST , 'ftpPassword' ));
2017-03-10 22:37:53 +13:00
$ftp -> pasv ( true );
2017-03-11 16:20:16 +13:00
if ( ! $ftp -> isdir ( filter_input ( INPUT_POST , 'ftpRemotePath' ))) {
$ftp -> mkdir ( filter_input ( INPUT_POST , 'ftpRemotePath' ), true );
}
2017-03-10 15:25:19 +13:00
$ftp -> putAll ( $archiveName . '/' , filter_input ( INPUT_POST , 'ftpRemotePath' ));
2017-03-11 14:50:49 +13:00
// TODO: error handling when not connected/unable to put, etc
2016-12-27 14:30:54 +13:00
unset ( $ftp );
}
2016-12-29 13:25:40 +13:00
2017-03-11 21:25:38 +13:00
if ( filter_input ( INPUT_POST , 'sendViaS3' ) == 1 ) {
require_once ( __DIR__ . '/aws/aws-autoloader.php' );
$credentials = new Aws\Credentials\Credentials ( filter_input ( INPUT_POST , 's3Key' ), filter_input ( INPUT_POST , 's3Secret' ));
$s3Client = new Aws\S3\S3Client ([
'version' => 'latest' ,
'region' => filter_input ( INPUT_POST , 's3Region' ),
'credentials' => $credentials
]);
# available regions http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
// Where the files will be source from
$source = $archiveName . '/' ;
// Where the files will be transferred to
$dest = 's3://' . filter_input ( INPUT_POST , 's3Bucket' );
error_log ( $source );
error_log ( $dest );
// Create a transfer object.
$manager = new \Aws\S3\Transfer ( $s3Client , $source , $dest );
// Perform the transfer synchronously.
$manager -> transfer ();
}
2016-12-29 13:25:40 +13:00
// TODO: keep copy of last export folder for incremental addition
2016-12-27 14:30:54 +13:00
// Remove temporary files unless user requested to keep or needed for FTP transfer
2017-03-11 14:50:49 +13:00
if ( $this -> _options -> getOption ( 'retainStaticFiles' ) != 1 ) {
2016-12-27 14:30:54 +13:00
$iterator = new RecursiveIteratorIterator ( new RecursiveDirectoryIterator ( $archiveDir ), RecursiveIteratorIterator :: CHILD_FIRST );
2017-03-11 14:50:49 +13:00
foreach ( $iterator as $fileName => $fileObject ) {
2016-12-27 14:30:54 +13:00
// Remove file
2017-03-11 14:50:49 +13:00
if ( $fileObject -> isDir ()) {
2016-12-27 14:30:54 +13:00
// Ignore special dirs
$dirName = basename ( $fileName );
if ( $dirName != '.' && $dirName != '..' ) {
rmdir ( $fileName );
}
2017-03-11 14:50:49 +13:00
} else {
2016-12-27 14:30:54 +13:00
unlink ( $fileName );
}
}
rmdir ( $archiveDir );
}
return str_replace ( ABSPATH , trailingslashit ( home_url ()), $archiveName . '.zip' );
}
/**
* Returns the list of local files
* @ param array $urls
* @ return array
*/
protected function _getListOfLocalFilesByUrl ( array $urls )
{
$files = array ();
2017-03-11 14:50:49 +13:00
foreach ( $urls as $url ) {
2016-12-27 14:30:54 +13:00
$directory = str_replace ( home_url ( '/' ), ABSPATH , $url );
2017-03-11 14:50:49 +13:00
if ( stripos ( $url , home_url ( '/' )) === 0 && is_dir ( $directory )) {
2016-12-27 14:30:54 +13:00
$iterator = new RecursiveIteratorIterator ( new RecursiveDirectoryIterator ( $directory ));
2017-03-11 14:50:49 +13:00
foreach ( $iterator as $fileName => $fileObject ) {
if ( is_file ( $fileName )) {
2016-12-27 14:30:54 +13:00
$pathinfo = pathinfo ( $fileName );
2017-03-11 14:50:49 +13:00
if ( isset ( $pathinfo [ 'extension' ]) && ! in_array ( $pathinfo [ 'extension' ], array ( 'php' , 'phtml' , 'tpl' ))) {
2016-12-27 14:30:54 +13:00
array_push ( $files , home_url ( str_replace ( ABSPATH , '' , $fileName )));
}
}
}
}
}
return $files ;
}
/**
* Saves url data in temporary archive directory
* @ param StaticHtmlOutput_UrlRequest $url
* @ param string $archiveDir
* @ return void
*/
2017-03-11 14:50:49 +13:00
protected function _saveUrlData ( StaticHtmlOutput_UrlRequest $url , $archiveDir ) {
2016-12-27 14:30:54 +13:00
$urlInfo = parse_url ( $url -> getUrl ());
$pathInfo = pathinfo ( isset ( $urlInfo [ 'path' ]) && $urlInfo [ 'path' ] != '/' ? $urlInfo [ 'path' ] : 'index.html' );
// Prepare file directory and create it if it doesn't exist
$fileDir = $archiveDir . ( isset ( $pathInfo [ 'dirname' ]) ? $pathInfo [ 'dirname' ] : '' );
2017-03-11 14:50:49 +13:00
if ( empty ( $pathInfo [ 'extension' ]) && $pathInfo [ 'basename' ] == $pathInfo [ 'filename' ]) {
2016-12-27 14:30:54 +13:00
$fileDir .= '/' . $pathInfo [ 'basename' ];
$pathInfo [ 'filename' ] = 'index' ;
}
2017-03-11 14:50:49 +13:00
if ( ! file_exists ( $fileDir )) {
2016-12-27 14:30:54 +13:00
wp_mkdir_p ( $fileDir );
}
$fileExtension = ( $url -> isHtml () || ! isset ( $pathInfo [ 'extension' ]) ? 'html' : $pathInfo [ 'extension' ]);
$fileName = $fileDir . '/' . $pathInfo [ 'filename' ] . '.' . $fileExtension ;
file_put_contents ( $fileName , $url -> getResponseBody ());
}
}