samuelaguilera

class-job.php with date/time place holders fixed

Nov 17th, 2014
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 80.41 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Class in that the BackWPup job runs
  4.  */
  5. final class BackWPup_Job {
  6.  
  7.     /**
  8.      * @var array of the job settings
  9.      */
  10.     public $job = array();
  11.  
  12.     /**
  13.      * @var int The timestamp when the job starts
  14.      */
  15.     public $start_time = 0;
  16.  
  17.     /**
  18.      * @var string the logfile
  19.      */
  20.     public $logfile = '';
  21.     /**
  22.      * @var array for temp values
  23.      */
  24.     public $temp = array();
  25.     /**
  26.      * @var string Folder where is Backup files in
  27.      */
  28.     public $backup_folder = '';
  29.     /**
  30.      * @var string the name of the Backup archive file
  31.      */
  32.     public $backup_file = '';
  33.     /**
  34.      * @var int The size of the Backup archive file
  35.      */
  36.     public $backup_filesize = 0;
  37.     /**
  38.      * @var int PID of script
  39.      */
  40.     public $pid = 0;
  41.     /**
  42.      * @var float Timestamp of last update off .running file
  43.      */
  44.     public $timestamp_last_update = 0;
  45.     /**
  46.      * @var float Timestamp of script start
  47.      */
  48.     private $timestamp_script_start = 0;
  49.     /**
  50.      * @var int Number of warnings
  51.      */
  52.     public $warnings = 0;
  53.     /**
  54.      * @var int Number of errors
  55.      */
  56.     public $errors = 0;
  57.     /**
  58.      * @var string the last log notice message
  59.      */
  60.     public $lastmsg = '';
  61.     /**
  62.      * @var string the last log error/waring message
  63.      */
  64.     public $lasterrormsg = '';
  65.     /**
  66.      * @var array of steps to do
  67.      */
  68.     public $steps_todo = array( 'CREATE' );
  69.     /**
  70.      * @var array of done steps
  71.      */
  72.     public $steps_done = array();
  73.     /**
  74.      * @var array  of steps data
  75.      */
  76.     public $steps_data = array();
  77.     /**
  78.      * @var string working on step
  79.      */
  80.     public $step_working = 'CREATE';
  81.     /**
  82.      * @var int Number of sub steps must do in step
  83.      */
  84.     public $substeps_todo = 0;
  85.     /**
  86.      * @var int Number of sub steps done in step
  87.      */
  88.     public $substeps_done = 0;
  89.     /**
  90.      * @var int Percent of steps done
  91.      */
  92.     public $step_percent = 1;
  93.     /**
  94.      * @var int Percent of sub steps done
  95.      */
  96.     public $substep_percent = 1;
  97.     /**
  98.      * @var array of files to additional to backup
  99.      */
  100.     public $additional_files_to_backup = array();
  101.     /**
  102.      * @var array of files/folder to exclude from backup
  103.      */
  104.     public $exclude_from_backup = array();
  105.     /**
  106.      * @var int count of affected files
  107.      */
  108.     public $count_files = 0;
  109.     /**
  110.      * @var int count of affected file size
  111.      */
  112.     public $count_filesize = 0;
  113.     /**
  114.      * @var int count of affected folders
  115.      */
  116.     public $count_folder = 0;
  117.     /**
  118.      * @var int count of files in a folder
  119.      */
  120.     public $count_files_in_folder = 0;
  121.     /**
  122.      * @var int count of files size in a folder
  123.      */
  124.     public $count_filesize_in_folder = 0;
  125.     /**
  126.      * @var string path to remove from file path
  127.      */
  128.     public $remove_path = '';
  129.  
  130.     /**
  131.      * If job aborted from user
  132.      * @var bool
  133.      */
  134.     public $user_abort = FALSE;
  135.  
  136.     /**
  137.      * Stores data that will only used in a single run
  138.      * @var array
  139.      */
  140.     private $run = array();
  141.  
  142.     /**
  143.      * A uniqid ID uniqid('', true); to identify process
  144.      * @var string
  145.      */
  146.     private $uniqid = '';
  147.  
  148.  
  149.     /**
  150.      * Delete some data on cloned objects
  151.      */
  152.     public function __clone( ) {
  153.  
  154.         $this->temp = array();
  155.         $this->run = array();
  156.     }
  157.  
  158.     /**
  159.      *
  160.      * This starts or restarts the job working
  161.      *
  162.      * @param string $start_type Start types are 'runnow', 'runnowalt', 'cronrun', 'runext', 'runcli'
  163.      * @param array|int $job_settings The id of job or the settings of a job to start
  164.      */
  165.     private function create( $start_type, $job_settings = 0 ) {
  166.         global $wpdb;
  167.         /* @var wpdb $wpdb */
  168.  
  169.         //check startype
  170.         if ( ! in_array( $start_type, array( 'runnow', 'runnowalt', 'cronrun', 'runext', 'runcli' ) ) )
  171.             return;
  172.  
  173.         if ( is_int( $job_settings ) )
  174.             $this->job      = BackWPup_Option::get_job( $job_settings );
  175.         elseif( is_array( $job_settings ) )
  176.             $this->job      = $job_settings;
  177.         else
  178.             return;
  179.         $this->start_time   =  current_time( 'timestamp' );
  180.         $this->lastmsg      = __( 'Starting job', 'backwpup' );
  181.         //set Logfile
  182.         $this->logfile = get_site_option( 'backwpup_cfg_logfolder' ) . 'backwpup_log_' . BackWPup::get_plugin_data( 'hash' ) . '_' . date_i18n( 'Y-m-d_H-i-s' ) . '.html';
  183.         //write settings to job
  184.         if ( ! empty( $this->job[ 'jobid' ] ) ) {
  185.             BackWPup_Option::update( $this->job[ 'jobid' ], 'lastrun', $this->start_time );
  186.             BackWPup_Option::update( $this->job[ 'jobid' ], 'logfile', $this->logfile ); //Set current logfile
  187.             BackWPup_Option::update( $this->job[ 'jobid' ], 'lastbackupdownloadurl', '' );
  188.         }
  189.         //Set needed job values
  190.         $this->timestamp_last_update = microtime( TRUE );
  191.         $this->exclude_from_backup  = explode( ',', trim( $this->job[ 'fileexclude' ] ) );
  192.         $this->exclude_from_backup  = array_unique( $this->exclude_from_backup );
  193.         //create path to remove
  194.         $this->remove_path      = trailingslashit( str_replace( '\\', '/', realpath( ABSPATH ) ) );
  195.         if ( $this->remove_path == '/' )
  196.             $this->remove_path = '';
  197.         //setup job steps
  198.         $this->steps_data[ 'CREATE' ][ 'CALLBACK' ] = '';
  199.         $this->steps_data[ 'CREATE' ][ 'NAME' ]     = __( 'Job Start', 'backwpup' );
  200.         $this->steps_data[ 'CREATE' ][ 'STEP_TRY' ] = 0;
  201.         //ADD Job types file
  202.         /* @var $job_type_class BackWPup_JobTypes */
  203.         $job_need_dest = FALSE;
  204.         if ( $job_types = BackWPup::get_job_types() ) {
  205.             foreach ( $job_types as $id => $job_type_class ) {
  206.                 if ( in_array( $id, $this->job[ 'type' ] ) && $job_type_class->creates_file( ) ) {
  207.                     $this->steps_todo[ ]                            = 'JOB_' . $id;
  208.                     $this->steps_data[ 'JOB_' . $id ][ 'NAME' ]     = $job_type_class->info[ 'description' ];
  209.                     $this->steps_data[ 'JOB_' . $id ][ 'STEP_TRY' ] = 0;
  210.                     $this->steps_data[ 'JOB_' . $id ][ 'SAVE_STEP_TRY' ] = 0;
  211.                     $job_need_dest                                  = TRUE;
  212.                 }
  213.             }
  214.         }
  215.         //add destinations and create archive if a job where files to backup
  216.         if ( $job_need_dest ) {
  217.             //Create manifest file
  218.             $this->steps_todo[ ]                                      = 'CREATE_MANIFEST';
  219.             $this->steps_data[ 'CREATE_MANIFEST' ][ 'NAME' ]          = __( 'Creates manifest file', 'backwpup' );
  220.             $this->steps_data[ 'CREATE_MANIFEST' ][ 'STEP_TRY' ]      = 0;
  221.             $this->steps_data[ 'CREATE_MANIFEST' ][ 'SAVE_STEP_TRY' ] = 0;
  222.             //Add archive creation and backup filename on backup type archive
  223.             if ( $this->job[ 'backuptype' ] == 'archive' ) {
  224.                 //get Backup folder if destination folder set
  225.                 if ( in_array( 'FOLDER', $this->job[ 'destinations' ] ) ) {
  226.                     $this->backup_folder = $this->job[ 'backupdir' ];
  227.                     //check backup folder
  228.                     if ( ! empty( $this->backup_folder ) )
  229.                         self::check_folder( $this->backup_folder, TRUE );
  230.                 }
  231.                 //set temp folder to backup folder if not set because we need one
  232.                 if ( ! $this->backup_folder || $this->backup_folder == '/' )
  233.                     $this->backup_folder = BackWPup::get_plugin_data( 'TEMP' );
  234.                 //Create backup archive full file name
  235.                 $this->backup_file = $this->generate_filename( $this->job[ 'archivename' ], $this->job[ 'archiveformat' ] );
  236.                 //add archive create
  237.                 $this->steps_todo[ ]                                = 'CREATE_ARCHIVE';
  238.                 $this->steps_data[ 'CREATE_ARCHIVE' ][ 'NAME' ]     = __( 'Creates archive', 'backwpup' );
  239.                 $this->steps_data[ 'CREATE_ARCHIVE' ][ 'STEP_TRY' ] = 0;
  240.                 $this->steps_data[ 'CREATE_ARCHIVE' ][ 'SAVE_STEP_TRY' ] = 0;
  241.             }
  242.             //ADD Destinations
  243.             /* @var BackWPup_Destinations $dest_class */
  244.             foreach ( BackWPup::get_registered_destinations() as $id => $dest ) {
  245.                 if ( ! in_array( $id, $this->job[ 'destinations' ] ) || empty( $dest[ 'class' ] ) )
  246.                     continue;
  247.                 $dest_class = BackWPup::get_destination( $id );
  248.                 if ( $dest_class->can_run( $this ) ) {
  249.                     if ( $this->job[ 'backuptype' ] == 'sync' ) {
  250.                         if ( $dest[ 'can_sync' ] ) {
  251.                             $this->steps_todo[]                                   = 'DEST_SYNC_' . $id;
  252.                             $this->steps_data[ 'DEST_SYNC_' . $id ][ 'NAME' ]     = $dest[ 'info' ][ 'description' ];
  253.                             $this->steps_data[ 'DEST_SYNC_' . $id ][ 'STEP_TRY' ] = 0;
  254.                             $this->steps_data[ 'DEST_SYNC_' . $id ][ 'SAVE_STEP_TRY' ] = 0;
  255.                         }
  256.                     } else {
  257.                         $this->steps_todo[]                              = 'DEST_' . $id;
  258.                         $this->steps_data[ 'DEST_' . $id ][ 'NAME' ]     = $dest[ 'info' ][ 'description' ];
  259.                         $this->steps_data[ 'DEST_' . $id ][ 'STEP_TRY' ] = 0;
  260.                         $this->steps_data[ 'DEST_' . $id ][ 'SAVE_STEP_TRY' ] = 0;
  261.                     }
  262.                 }
  263.             }
  264.         }
  265.         //ADD Job type no file
  266.         if ( $job_types = BackWPup::get_job_types() ) {
  267.             foreach ( $job_types as $id => $job_type_class ) {
  268.                 if ( in_array( $id, $this->job[ 'type' ] ) && ! $job_type_class->creates_file() ) {
  269.                     $this->steps_todo[ ]                            = 'JOB_' . $id;
  270.                     $this->steps_data[ 'JOB_' . $id ][ 'NAME' ]     = $job_type_class->info[ 'description' ];
  271.                     $this->steps_data[ 'JOB_' . $id ][ 'STEP_TRY' ] = 0;
  272.                     $this->steps_data[ 'JOB_' . $id ][ 'SAVE_STEP_TRY' ] = 0;
  273.                 }
  274.             }
  275.         }
  276.         $this->steps_todo[]                      = 'END';
  277.         $this->steps_data[ 'END' ][ 'NAME' ]     = __( 'End of Job', 'backwpup' );
  278.         $this->steps_data[ 'END' ][ 'STEP_TRY' ] = 1;
  279.         //must write working data
  280.         $this->write_running_file();
  281.         //create log file
  282.         $head = '';
  283.         $head .= "<!DOCTYPE html>" . PHP_EOL;
  284.         $head .= "<html lang=\"" . str_replace( '_', '-', get_locale() ) . "\">" . PHP_EOL;
  285.         $head .= "<head>" . PHP_EOL;
  286.         $head .= "<meta charset=\"" . get_bloginfo( 'charset' ) . "\" />" . PHP_EOL;
  287.         $head .= "<title>" . sprintf( __( 'BackWPup log for %1$s from %2$s at %3$s', 'backwpup' ), $this->job[ 'name' ], date_i18n( get_option( 'date_format' ) ), date_i18n( get_option( 'time_format' ) ) ) . "</title>" . PHP_EOL;
  288.         $head .= "<meta name=\"robots\" content=\"noindex, nofollow\" />" . PHP_EOL;
  289.         $head .= "<meta name=\"copyright\" content=\"Copyright &copy; 2012 - " . date_i18n( 'Y' ) . " Inpsyde GmbH\" />" . PHP_EOL;
  290.         $head .= "<meta name=\"author\" content=\"Inpsyde GmbH\" />" . PHP_EOL;
  291.         $head .= "<meta name=\"generator\" content=\"BackWPup " . BackWPup::get_plugin_data( 'Version' ) . "\" />" . PHP_EOL;
  292.         $head .= "<meta http-equiv=\"cache-control\" content=\"no-cache\" />" . PHP_EOL;
  293.         $head .= "<meta http-equiv=\"pragma\" content=\"no-cache\" />" . PHP_EOL;
  294.         $head .= "<meta name=\"date\" content=\"" . date( 'c' ) . "\" />" . PHP_EOL;
  295.         $head .= str_pad( '<meta name="backwpup_errors" content="0" />', 100 ) . PHP_EOL;
  296.         $head .= str_pad( '<meta name="backwpup_warnings" content="0" />', 100 ) . PHP_EOL;
  297.         if ( ! empty( $this->job[ 'jobid' ] ) )
  298.             $head .= "<meta name=\"backwpup_jobid\" content=\"" . $this->job[ 'jobid' ] . "\" />" . PHP_EOL;
  299.         $head .= "<meta name=\"backwpup_jobname\" content=\"" . esc_attr( $this->job[ 'name' ] ) . "\" />" . PHP_EOL;
  300.         $head .= "<meta name=\"backwpup_jobtype\" content=\"" . implode( '+', $this->job[ 'type' ] ) . "\" />" . PHP_EOL;
  301.         $head .= str_pad( '<meta name="backwpup_backupfilesize" content="0" />', 100 ) . PHP_EOL;
  302.         $head .= str_pad( '<meta name="backwpup_jobruntime" content="0" />', 100 ) . PHP_EOL;
  303.         $head .= "</head>" . PHP_EOL;
  304.         $head .= "<body style=\"margin:0;padding:3px;font-family:monospace;font-size:12px;line-height:15px;background-color:#000;color:#fff;white-space:nowrap;\">" . PHP_EOL;
  305.         $head .= sprintf( _x( '[INFO] %1$s version %2$s; A project of Inpsyde GmbH', 'Plugin name; Plugin Version','backwpup' ), BackWPup::get_plugin_data( 'name' ) , BackWPup::get_plugin_data( 'Version' ) ) . '<br />' . PHP_EOL;
  306.         $head .= sprintf( _x( '[INFO] WordPress version %s', 'WordPress Version', 'backwpup' ), BackWPup::get_plugin_data( 'wp_version' ) ). '<br />' . PHP_EOL;
  307.         $head .= sprintf( __( '[INFO] Blog url: %s', 'backwpup' ), esc_attr( site_url( '/' ) ) ). '<br />' . PHP_EOL;
  308.         $head .= sprintf( __( '[INFO] BackWPup job: %1$s; %2$s', 'backwpup' ), esc_attr( $this->job[ 'name' ] ) , implode( '+', $this->job[ 'type' ] ) ) . '<br />' . PHP_EOL;
  309.         if ( $this->job[ 'activetype' ] == 'wpcron' ) {
  310.             //check next run
  311.             $cron_next = wp_next_scheduled( 'backwpup_cron', array( 'id' => $this->job[ 'jobid' ] ) );
  312.             if ( ! $cron_next || $cron_next < time() ) {
  313.                 wp_unschedule_event( $cron_next, 'backwpup_cron', array( 'id' => $this->job[ 'jobid' ] ) );
  314.                 $cron_next = BackWPup_Cron::cron_next( $this->job[ 'cron' ] );
  315.                 wp_schedule_single_event( $cron_next, 'backwpup_cron', array( 'id' => $this->job[ 'jobid' ] ) );
  316.                 $cron_next = wp_next_scheduled( 'backwpup_cron', array( 'id' => $this->job[ 'jobid' ] ) );
  317.             }
  318.             //output scheduling
  319.             if ( ! $cron_next )
  320.                 $cron_next = __( 'Not scheduled!', 'backwpup' );
  321.             else
  322.                 $cron_next = date_i18n( 'D, j M Y @ H:i', $cron_next + ( get_option( 'gmt_offset' ) * 3600 ) , TRUE ) ;
  323.             $head .= sprintf( __( '[INFO] BackWPup cron: %s; Next: %s ', 'backwpup' ), $this->job[ 'cron' ] , $cron_next ) . '<br />' . PHP_EOL;
  324.         }
  325.         elseif ( $this->job[ 'activetype' ] == 'link' )
  326.             $head .= __( '[INFO] BackWPup job start with link is active', 'backwpup' ) . '<br />' . PHP_EOL;
  327.         else
  328.             $head .= __( '[INFO] BackWPup no automatic job start configured', 'backwpup' ) . '<br />' . PHP_EOL;
  329.         if ( $start_type == 'cronrun' )
  330.             $head .= __( '[INFO] BackWPup job started from wp-cron', 'backwpup' ) . '<br />' . PHP_EOL;
  331.         elseif ( $start_type == 'runnow' or $start_type == 'runnowalt' )
  332.             $head .= __( '[INFO] BackWPup job started manually', 'backwpup' ) . '<br />' . PHP_EOL;
  333.         elseif ( $start_type == 'runext' )
  334.             $head .= __( '[INFO] BackWPup job started from external url', 'backwpup' ) . '<br />' . PHP_EOL;
  335.         elseif ( $start_type == 'runcli' )
  336.             $head .= __( '[INFO] BackWPup job started form commandline interface', 'backwpup' ) . '<br />' . PHP_EOL;
  337.         $bit = '';
  338.         if ( PHP_INT_SIZE === 4 )
  339.             $bit = ' (32bit)';
  340.         if ( PHP_INT_SIZE === 8 )
  341.             $bit = ' (64bit)';
  342.         $head .= __( '[INFO] PHP ver.:', 'backwpup' ) . ' ' . PHP_VERSION . $bit .'; ' . PHP_SAPI . '; ' . PHP_OS . '<br />' . PHP_EOL;
  343.         $head .= sprintf( __( '[INFO] Maximum PHP script execution time is %1$d seconds', 'backwpup' ), ini_get( 'max_execution_time' ) ) . '<br />' . PHP_EOL;
  344.         if ( php_sapi_name() != 'cli' ) {
  345.             $job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
  346.             if ( ! empty( $job_max_execution_time ) ) {
  347.                 $head .= sprintf( __( '[INFO] Script restart time is configured to %1$d seconds', 'backwpup' ), $job_max_execution_time ) . '<br />' . PHP_EOL;
  348.             }
  349.         }
  350.         $head .= sprintf( __( '[INFO] MySQL ver.: %s', 'backwpup' ), $wpdb->get_var( "SELECT VERSION() AS version" ) ) . '<br />' . PHP_EOL;
  351.         if ( isset( $_SERVER[ 'SERVER_SOFTWARE' ] ) )
  352.             $head .= sprintf( __( '[INFO] Web Server: %s', 'backwpup' ), $_SERVER[ 'SERVER_SOFTWARE' ] ) . '<br />' . PHP_EOL;
  353.         if ( function_exists( 'curl_init' ) ) {
  354.             $curlversion = curl_version();
  355.             $head .= sprintf( __( '[INFO] curl ver.: %1$s; %2$s', 'backwpup' ), $curlversion[ 'version' ], $curlversion[ 'ssl_version' ] ) . '<br />' . PHP_EOL;
  356.         }
  357.         $head .= sprintf( __( '[INFO] Temp folder is: %s', 'backwpup' ), BackWPup::get_plugin_data( 'TEMP' ) ) . '<br />' . PHP_EOL;
  358.         $head .= sprintf( __( '[INFO] Logfile is: %s', 'backwpup' ), $this->logfile ) . '<br />' . PHP_EOL;
  359.         $head .= sprintf( __( '[INFO] Backup type is: %s', 'backwpup' ), $this->job[ 'backuptype' ] ) . '<br />' . PHP_EOL;
  360.         if ( ! empty( $this->backup_file ) && $this->job[ 'backuptype' ] == 'archive' )
  361.             $head .= sprintf( __( '[INFO] Backup file is: %s', 'backwpup' ), $this->backup_folder . $this->backup_file ) . '<br />' . PHP_EOL;
  362.         file_put_contents( $this->logfile, $head, FILE_APPEND );
  363.         //output info on cli
  364.         if ( php_sapi_name() == 'cli' && defined( 'STDOUT' ) )
  365.             fwrite( STDOUT, strip_tags( $head ) ) ;
  366.         //test for destinations
  367.         if ( $job_need_dest ) {
  368.             $desttest = FALSE;
  369.             foreach ( $this->steps_todo as $deststeptest ) {
  370.                 if ( substr( $deststeptest, 0, 5 ) == 'DEST_' ) {
  371.                     $desttest = TRUE;
  372.                     break;
  373.                 }
  374.             }
  375.             if ( ! $desttest )
  376.                 $this->log( __( 'No destination correctly defined for backup! Please correct job settings.', 'backwpup' ), E_USER_ERROR );
  377.         }
  378.         //Set start as done
  379.         $this->steps_done[] = 'CREATE';
  380.     }
  381.  
  382.  
  383.     /**
  384.      *
  385.      * Get a url to run a job of BackWPup
  386.      *
  387.      * @param string     $starttype Start types are 'runnow', 'runnowlink', 'cronrun', 'runext', 'restart', 'test'
  388.      * @param int        $jobid     The id of job to start else 0
  389.      * @return array|object [url] is the job url [header] for auth header or object form wp_remote_get()
  390.      */
  391.     public static function get_jobrun_url( $starttype, $jobid = 0 ) {
  392.  
  393.  
  394.         $wp_admin_user      = get_users( array( 'role' => 'administrator', 'number' => 1 ) );   //get a user for cookie auth
  395.         $url                = site_url( 'wp-cron.php' );
  396.         $header             = array();
  397.         $authurl            = '';
  398.         $query_args         = array( '_nonce' => substr( wp_hash( wp_nonce_tick() . 'backwpup_job_run-' . $starttype, 'nonce' ), - 12, 10 ), 'doing_wp_cron' => sprintf( '%.22F', microtime( true ) ) );
  399.  
  400.         if ( in_array( $starttype, array( 'restart', 'runnow', 'cronrun', 'runext', 'test' ) ) )
  401.             $query_args[ 'backwpup_run' ] = $starttype;
  402.  
  403.         if ( in_array( $starttype, array( 'runnowlink', 'runnow', 'cronrun', 'runext' ) ) && ! empty( $jobid ) )
  404.             $query_args[ 'jobid' ] = $jobid;
  405.  
  406.         if ( get_site_option( 'backwpup_cfg_httpauthuser' ) && get_site_option( 'backwpup_cfg_httpauthpassword' ) ) {
  407.             $header[ 'Authorization' ] = 'Basic ' . base64_encode( get_site_option( 'backwpup_cfg_httpauthuser' ) . ':' . BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_httpauthpassword' ) ) );
  408.             $authurl = get_site_option( 'backwpup_cfg_httpauthuser' ) . ':' . BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_httpauthpassword' ) ) . '@';
  409.         }
  410.  
  411.         if ( $starttype == 'runext' ) {
  412.             $query_args[ '_nonce' ] = get_site_option( 'backwpup_cfg_jobrunauthkey' );
  413.             $query_args[ 'doing_wp_cron' ] = NULL;
  414.             if ( ! empty( $authurl ) ) {
  415.                 $url = str_replace( 'https://', 'https://' . $authurl, $url );
  416.                 $url = str_replace( 'http://', 'http://' . $authurl, $url );
  417.             }
  418.         }
  419.  
  420.         if ( $starttype == 'runnowlink' && ( ! defined( 'ALTERNATE_WP_CRON' ) || ! ALTERNATE_WP_CRON ) ) {
  421.             $url                            = wp_nonce_url( network_admin_url( 'admin.php' ), 'backwpup_job_run-' . $starttype );
  422.             $query_args[ 'page' ]           = 'backwpupjobs';
  423.             $query_args[ 'action' ]         = 'runnow';
  424.             $query_args[ 'doing_wp_cron' ]  = NULL;
  425.             unset( $query_args[ '_nonce' ] );
  426.         }
  427.  
  428.         if ( $starttype == 'runnowlink' && defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
  429.             $query_args[ 'backwpup_run' ] = 'runnowalt';
  430.             $query_args[ '_nonce' ]    = substr( wp_hash( wp_nonce_tick() . 'backwpup_job_run-runnowalt', 'nonce' ), - 12, 10 );
  431.             $query_args[ 'doing_wp_cron' ] = NULL;
  432.         }
  433.  
  434.         //Extra for WP-Cron control
  435.         if ( class_exists( 'WP_Cron_Control' ) && ( $starttype == 'runext' || $starttype == 'runnow' || $starttype == 'restart'  ) ) {
  436.             $wp_cron_control_settings = get_option( 'wpcroncontrol_settings', array() );
  437.             if ( empty( $wp_cron_control_settings[ 'secret_string' ] ) && file_exists( WP_PLUGIN_DIR . '/wp-cron-control/wp-cron-control.php' ) ) {
  438.                 $wp_cron_control_settings[ 'secret_string' ] = md5( realpath( WP_PLUGIN_DIR . '/wp-cron-control/wp-cron-control.php' ) . get_current_blog_id() );
  439.                 $wp_cron_control_settings[ 'enable' ] = 1;
  440.             }
  441.             if ( isset( $wp_cron_control_settings[ 'enable' ] ) && $wp_cron_control_settings[ 'enable' ] == 1 ) {
  442.                 if ( defined( 'WP_CRON_CONTROL_SECRET' ) ) {
  443.                     $wp_cron_control_settings[ 'secret_string' ] = WP_CRON_CONTROL_SECRET;
  444.                 }
  445.                 $query_args[ $wp_cron_control_settings[ 'secret_string' ] ] = '';
  446.                 $query_args[ 'doing_wp_cron' ] = NULL;
  447.             }
  448.         }
  449.  
  450.         $cron_request = apply_filters( 'cron_request', array(
  451.                                                             'url' => add_query_arg( $query_args, $url ),
  452.                                                             'key' => $query_args[ 'doing_wp_cron' ],
  453.                                                             'args' => array(
  454.                                                                 'blocking'      => FALSE,
  455.                                                                 'sslverify'     => apply_filters( 'https_local_ssl_verify', true ),
  456.                                                                 'timeout'       => 0.01,
  457.                                                                 'headers'       => $header,
  458.                                                                 'cookies'       => array(
  459.                                                                     new WP_Http_Cookie( array( 'name' => AUTH_COOKIE, 'value' => wp_generate_auth_cookie( $wp_admin_user[ 0 ]->ID, time() + 300, 'auth' ) ) ),
  460.                                                                     new WP_Http_Cookie( array( 'name' => LOGGED_IN_COOKIE, 'value' => wp_generate_auth_cookie( $wp_admin_user[ 0 ]->ID, time() + 300, 'logged_in' ) ) )
  461.                                                                 ),
  462.                                                                 'user-agent'    => BackWpup::get_plugin_data( 'User-Agent' )
  463.                                                               )
  464.                                                        ) );
  465.  
  466.         if( $starttype == 'test' ) {
  467.             $cron_request[ 'args' ][ 'timeout' ] = 15;
  468.             $cron_request[ 'args' ][ 'blocking' ] = TRUE;
  469.         }
  470.  
  471.         if ( ! in_array( $starttype, array( 'runnowlink', 'runext' ) ) ) {
  472.             set_transient( 'doing_cron', $query_args[ 'doing_wp_cron' ] );
  473.             return wp_remote_post( $cron_request['url'], $cron_request['args'] );
  474.         }
  475.  
  476.         return $cron_request;
  477.     }
  478.  
  479.  
  480.     /**
  481.      *
  482.      */
  483.     public static function start_http( $starttype ) {
  484.  
  485.         //load text domain if needed
  486.         if ( ! is_textdomain_loaded( 'backwpup' ) && ! get_site_option( 'backwpup_cfg_jobnotranslate') )
  487.             load_plugin_textdomain( 'backwpup', FALSE, BackWPup::get_plugin_data( 'BaseName' ) . '/languages' );
  488.  
  489.         if ( $starttype != 'restart' ) {
  490.  
  491.             //check get vars
  492.             if ( isset( $_GET[ 'jobid' ] ) )
  493.                 $jobid = (int)$_GET[ 'jobid' ];
  494.             else
  495.                 $jobid = 0;
  496.  
  497.             //check job id exists
  498.             if ( $jobid != BackWPup_Option::get( $jobid, 'jobid' ) )
  499.                 die( '-1' );
  500.  
  501.             //check folders
  502.             if ( ! self::check_folder( get_site_option( 'backwpup_cfg_logfolder' ) )  || ! self::check_folder( BackWPup::get_plugin_data( 'TEMP' ), TRUE ) )
  503.                 die( '-2' );
  504.         }
  505.  
  506.         // redirect
  507.         if ( $starttype == 'runnowalt' ) {
  508.             ob_start();
  509.             wp_redirect( add_query_arg( array( 'page' => 'backwpupjobs' ), network_admin_url( 'admin.php' ) ) );
  510.             echo ' ';
  511.             while ( @ob_end_flush() );
  512.             flush();
  513.         }
  514.  
  515.         // Should be preventing doubled running job's on http requests
  516.         $random = rand( 1, 9 ) * 100000;
  517.         usleep( $random );
  518.  
  519.         //check running job
  520.         $backwpup_job_object = self::get_working_data();
  521.         //start class
  522.         if ( ! $backwpup_job_object && in_array( $starttype, array( 'runnow', 'runnowalt', 'runext' ) ) && ! empty( $jobid ) ) {
  523.             //schedule restart event
  524.             wp_schedule_single_event( time() + 60, 'backwpup_cron', array( 'id' => 'restart' ) );
  525.             //start job
  526.             $backwpup_job_object = new self();
  527.             $backwpup_job_object->create( $starttype, (int)$jobid );
  528.         }
  529.         if( is_object( $backwpup_job_object ) && $backwpup_job_object instanceof BackWPup_Job )
  530.             $backwpup_job_object->run();
  531.     }
  532.  
  533.     /**
  534.      * @param $jobid
  535.      */
  536.     public static function start_cli( $jobid ) {
  537.  
  538.         if ( php_sapi_name() != 'cli' )
  539.             return;
  540.  
  541.         //define DOING_CRON to prevent caching
  542.         if( ! defined( 'DOING_CRON' ) )
  543.             define( 'DOING_CRON', TRUE );
  544.  
  545.         //load text domain if needed
  546.         if ( ! is_textdomain_loaded( 'backwpup' ) && ! get_site_option( 'backwpup_cfg_jobnotranslate') )
  547.             load_plugin_textdomain( 'backwpup', FALSE, BackWPup::get_plugin_data( 'BaseName' ) . '/languages' );
  548.  
  549.         //check job id exists
  550.         $jobids = BackWPup_Option::get_job_ids();
  551.         if ( ! in_array( $jobid, $jobids ) )
  552.             die( __( 'Wrong BackWPup JobID', 'backwpup' ) );
  553.         //check folders
  554.         if ( ! self::check_folder( get_site_option( 'backwpup_cfg_logfolder' ) ) )
  555.             die( __( 'Log folder does not exist or is not writable for BackWPup', 'backwpup' ) );
  556.         if ( ! self::check_folder( BackWPup::get_plugin_data( 'TEMP' ), TRUE ) )
  557.             die( __( 'Temp folder does not exist or is not writable for BackWPup', 'backwpup' ) );
  558.         //check running job
  559.         if ( file_exists( BackWPup::get_plugin_data( 'running_file' ) ) )
  560.             die( __( 'A BackWPup job is already running', 'backwpup' ) );
  561.  
  562.         //start/restart class
  563.         fwrite( STDOUT, __( 'Job started', 'backwpup' ) . PHP_EOL );
  564.         fwrite( STDOUT, '----------------------------------------------------------------------' . PHP_EOL );
  565.         $backwpup_job_object = new self();
  566.         $backwpup_job_object->create( 'runcli', (int)$jobid );
  567.         $backwpup_job_object->run();
  568.     }
  569.  
  570.     /**
  571.      * @param int $jobid
  572.      */
  573.     public static function start_wp_cron( $jobid = 0 ) {
  574.  
  575.         if ( ! defined( 'DOING_CRON' ) || ! DOING_CRON )
  576.             return;
  577.  
  578.         //load text domain if needed
  579.         if ( ! is_textdomain_loaded( 'backwpup' ) && ! get_site_option( 'backwpup_cfg_jobnotranslate') )
  580.             load_plugin_textdomain( 'backwpup', FALSE, BackWPup::get_plugin_data( 'BaseName' ) . '/languages' );
  581.  
  582.         if ( ! empty( $jobid ) ) {
  583.             //check folders
  584.             if ( ! self::check_folder( get_site_option( 'backwpup_cfg_logfolder' ) ) ||  ! self::check_folder( BackWPup::get_plugin_data( 'TEMP' ), TRUE ) )
  585.                 return;
  586.         }
  587.  
  588.         // Should be preventing doubled running job's on http requests
  589.         $random = rand( 1, 9 ) * 100000;
  590.         usleep( $random );
  591.  
  592.         //get running job
  593.         $backwpup_job_object = self::get_working_data();
  594.         //start/restart class
  595.         if ( empty( $backwpup_job_object ) && ! empty( $jobid ) ) {
  596.             //schedule restart event
  597.             wp_schedule_single_event( time() + 60, 'backwpup_cron', array( 'id' => 'restart' ) );
  598.             //start job
  599.             $backwpup_job_object = new self();
  600.             $backwpup_job_object->create( 'cronrun', (int)$jobid );
  601.         }
  602.         if( is_object( $backwpup_job_object ) && $backwpup_job_object instanceof BackWPup_Job )
  603.             $backwpup_job_object->run();
  604.     }
  605.  
  606.     /**
  607.      * disable caches
  608.      */
  609.     public static function disable_caches() {
  610.  
  611.         //Special settings
  612.         @putenv( 'nokeepalive=1' );
  613.         @ini_set( 'zlib.output_compression', 'Off' );
  614.  
  615.         // deactivate caches
  616.         if ( ! defined( 'DONOTCACHEOBJECT' ) )
  617.             define( 'DONOTCACHEOBJECT', TRUE );
  618.         if ( ! defined( 'DONOTCACHEPAGE' ) )
  619.             define( 'DONOTCACHEPAGE', TRUE );
  620.     }
  621.  
  622.  
  623.     /**
  624.      * Run baby run
  625.      */
  626.     public function run() {
  627.         global $wpdb;
  628.         /* @var wpdb $wpdb */
  629.  
  630.         // Job can't run it is not created
  631.         if ( empty( $this->steps_todo ) )
  632.             return;
  633.  
  634.         //Check double running and inactivity
  635.         $last_update = microtime( TRUE ) - $this->timestamp_last_update;
  636.         if ( ! empty( $this->pid ) && $last_update > 300 ) {
  637.             $this->log( __( 'Job restarts due to inactivity for more than 5 minutes.', 'backwpup' ), E_USER_WARNING );
  638.         }
  639.         elseif ( ! empty( $this->pid ) ) {
  640.             return;
  641.         }
  642.         // set timestamp of script start
  643.         $this->timestamp_script_start = microtime( TRUE );
  644.         //set Pid
  645.         $this->pid = self::get_pid();
  646.         $this->uniqid = uniqid( '', TRUE );
  647.         //Early write new working file
  648.         $this->write_running_file();
  649.         //set function for PHP user defined error handling
  650.         $this->run[ 'PHP' ][ 'INI' ][ 'ERROR_LOG' ]      = ini_get( 'error_log' );
  651.         $this->run[ 'PHP' ][ 'INI' ][ 'ERROR_REPORTING' ]= ini_get( 'error_reporting' );
  652.         $this->run[ 'PHP' ][ 'INI' ][ 'LOG_ERRORS' ]     = ini_get( 'log_errors' );
  653.         $this->run[ 'PHP' ][ 'INI' ][ 'DISPLAY_ERRORS' ] = ini_get( 'display_errors' );
  654.         $this->run[ 'PHP' ][ 'INI' ][ 'HTML_ERRORS' ]    = ini_get( 'html_errors' );
  655.         $this->run[ 'PHP' ][ 'INI' ][ 'REPORT_MEMLEAKS' ]= ini_get( 'report_memleaks' );
  656.         $this->run[ 'PHP' ][ 'INI' ][ 'ZLIB_OUTPUT_COMPRESSION' ]     = ini_get( 'zlib.output_compression' );
  657.         $this->run[ 'PHP' ][ 'INI' ][ 'IMPLICIT_FLUSH' ] = ini_get( 'implicit_flush' );
  658.         @ini_set( 'error_log', $this->logfile );
  659.         if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  660.             error_reporting( -1 );
  661.         } else {
  662.             error_reporting( E_ALL ^ E_NOTICE );
  663.         }
  664.         @ini_set( 'display_errors', 'Off' );
  665.         @ini_set( 'log_errors', 'On' );
  666.         @ini_set( 'html_errors', 'Off' );
  667.         @ini_set( 'report_memleaks', 'On' );
  668.         @ini_set( 'zlib.output_compression', 'Off' );
  669.         @ini_set( 'implicit_flush', 'Off' );
  670.         //increase MySQL timeout
  671.         @ini_set( 'mysql.connect_timeout', '300' );
  672.         $wpdb->query( "SET session wait_timeout = 300" );
  673.         //set temp folder
  674.         $can_set_temp_env = TRUE;
  675.         $protected_env_vars = explode( ',', ini_get( 'safe_mode_protected_env_vars') );
  676.         foreach( $protected_env_vars as $protected_env ) {
  677.             if ( strtoupper( trim( $protected_env ) ) == 'TMPDIR' )
  678.                 $can_set_temp_env = FALSE;
  679.         }
  680.         if ( $can_set_temp_env ) {
  681.             $this->run[ 'PHP' ][ 'ENV' ][ 'TEMPDIR' ] = getenv( 'TMPDIR' );
  682.             @putenv( 'TMPDIR='.BackWPup::get_plugin_data( 'TEMP') );
  683.         }
  684.         //Write Wordpress DB errors to log
  685.         $wpdb->suppress_errors( FALSE );
  686.         $wpdb->hide_errors();
  687.         //set wp max memory limit
  688.         @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
  689.         //set error handler
  690.         if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  691.             set_error_handler( array( $this, 'log' ), -1 );
  692.         } else {
  693.             set_error_handler( array( $this, 'log' ), E_ALL ^ E_NOTICE );
  694.         }
  695.         set_exception_handler( array( $this, 'exception_handler' ) );
  696.         //not loading Textdomains and unload loaded
  697.         if ( get_site_option( 'backwpup_cfg_jobnotranslate' ) ) {
  698.             add_filter( 'override_load_textdomain', create_function( '','return TRUE;') );
  699.             $GLOBALS[ 'l10n' ] = array();
  700.         }
  701.         // execute function on job shutdown  register_shutdown_function( array( $this, 'shutdown' ) );
  702.         add_action( 'shutdown', array( $this, 'shutdown' ) );
  703.         //remove_action('shutdown', array( $this, 'shutdown' ));
  704.         if ( function_exists( 'pcntl_signal' ) ) {
  705.             declare( ticks = 1 ) ; //set ticks
  706.             pcntl_signal( 15, array( $this, 'shutdown' ) ); //SIGTERM
  707.             //pcntl_signal(9, array($this,'shutdown')); //SIGKILL
  708.             pcntl_signal( 2, array( $this, 'shutdown' ) ); //SIGINT
  709.         }
  710.         //clear output buffer
  711.         while( @ob_end_clean() );
  712.         @flush();
  713.         $job_types = BackWPup::get_job_types();
  714.         //go step by step
  715.         foreach ( $this->steps_todo as $this->step_working ) {
  716.             //Check if step already done
  717.             if ( in_array( $this->step_working, $this->steps_done ) )
  718.                 continue;
  719.             //calc step percent
  720.             if ( count( $this->steps_done ) > 0 )
  721.                 $this->step_percent = round( count( $this->steps_done ) / count( $this->steps_todo ) * 100 );
  722.             else
  723.                 $this->step_percent = 1;
  724.             // do step tries
  725.             while ( TRUE ) {
  726.                 if ( $this->steps_data[ $this->step_working ][ 'STEP_TRY' ] >= get_site_option( 'backwpup_cfg_jobstepretry' ) ) {
  727.                     $this->log( __( 'Step aborted: too many attempts!', 'backwpup' ), E_USER_ERROR );
  728.                     $this->temp = array();
  729.                     $this->steps_done[ ] = $this->step_working;
  730.                     $this->substeps_done = 0;
  731.                     $this->substeps_todo = 0;
  732.                     $this->do_restart();
  733.                     break;
  734.                 }
  735.  
  736.                 $this->steps_data[ $this->step_working ][ 'STEP_TRY' ] ++;
  737.                 $done = FALSE;
  738.  
  739.                 //executes the methods of job process
  740.                 if ( $this->step_working == 'CREATE_ARCHIVE' ) {
  741.                     $done = $this->create_archive();
  742.                 }
  743.                 elseif ( $this->step_working == 'CREATE_MANIFEST' ) {
  744.                     $done = $this->create_manifest();
  745.                 }
  746.                 elseif ( $this->step_working == 'END' ) {
  747.                     $this->end();
  748.                     break 2;
  749.                 }
  750.                 elseif ( strstr( $this->step_working, 'JOB_' ) ) {
  751.                     $done = $job_types[ str_replace( 'JOB_', '', $this->step_working ) ]->job_run( $this );
  752.                 }
  753.                 elseif ( strstr( $this->step_working, 'DEST_SYNC_' ) ) {
  754.                     $done = BackWPup::get_destination( str_replace( 'DEST_SYNC_', '', $this->step_working ) )->job_run_sync( $this );
  755.                 }
  756.                 elseif ( strstr( $this->step_working, 'DEST_' ) ) {
  757.                     $done = BackWPup::get_destination( str_replace( 'DEST_', '', $this->step_working ) )->job_run_archive( $this );
  758.                 }
  759.                 elseif ( ! empty( $this->steps_data[ $this->step_working ][ 'CALLBACK' ] ) ) {
  760.                     $done = $this->steps_data[ $this->step_working ][ 'CALLBACK' ]( $this );
  761.                 }
  762.  
  763.                 // set step as done
  764.                 if ( $done === TRUE ) {
  765.                     $this->temp          = array();
  766.                     $this->steps_done[]  = $this->step_working;
  767.                     $this->substeps_done = 0;
  768.                     $this->substeps_todo = 0;
  769.                     $this->write_running_file();
  770.                 }
  771.                 if ( count( $this->steps_done ) < count( $this->steps_todo ) -1 ) {
  772.                     $this->do_restart();
  773.                 }
  774.                 if ( $done === TRUE ) {
  775.                     break;
  776.                 }
  777.             }
  778.         }
  779.     }
  780.  
  781.     /**
  782.      * Do a job restart
  783.      *
  784.      * @param bool $must Restart must done
  785.      * @param bool $msg Log restart message
  786.      */
  787.     public function do_restart( $must = FALSE, $msg = TRUE ) {
  788.  
  789.         //no restart if in end step
  790.         if ( $this->step_working == 'END' || ( count( $this->steps_done ) + 1 ) >= count( $this->steps_todo ) )
  791.             return;
  792.  
  793.         //no restart on cli usage
  794.         if ( php_sapi_name() == 'cli' )
  795.             return;
  796.  
  797.         //no restart when restart was 3 Seconds before
  798.         $execution_time = microtime( TRUE ) - $this->timestamp_script_start;
  799.         if ( ! $must  && $execution_time < 3 )
  800.             return;
  801.  
  802.         //no restart if no working job
  803.         if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) )
  804.             return;
  805.  
  806.         //print message
  807.         if ( $msg )
  808.             $this->log( __( 'Restart will be executed now.', 'backwpup' ) );
  809.  
  810.         //do things for a clean restart
  811.         $this->pid = 0;
  812.         $this->uniqid = '';
  813.         $this->write_running_file();
  814.         remove_action( 'shutdown', array( $this, 'shutdown' ) );
  815.         //do restart
  816.         wp_clear_scheduled_hook( 'backwpup_cron', array( 'id' => 'restart' ) );
  817.         wp_schedule_single_event( time() + 10, 'backwpup_cron', array( 'id' => 'restart' ) );
  818.         self::get_jobrun_url( 'restart' );
  819.  
  820.         exit();
  821.     }
  822.  
  823.     /**
  824.      * Do a job restart
  825.      *
  826.      * @param bool $do_restart_now should time restart now be done
  827.      * @return int remaining time
  828.      */
  829.     public function do_restart_time( $do_restart_now = FALSE ) {
  830.  
  831.         $job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
  832.  
  833.         if ( empty( $job_max_execution_time ) )
  834.             return 300;
  835.  
  836.         $execution_time = microtime( TRUE ) - $this->timestamp_script_start;
  837.  
  838.         // do restart 3 sec. before max. execution time
  839.         if ( $do_restart_now || $execution_time >= ( $job_max_execution_time - 3 ) ) {
  840.             $this->steps_data[ $this->step_working ][ 'SAVE_STEP_TRY' ] = $this->steps_data[ $this->step_working ][ 'STEP_TRY' ];
  841.             $this->steps_data[ $this->step_working ][ 'STEP_TRY' ] -= 1;
  842.             $this->log( sprintf( __( 'Restart after %1$d seconds.', 'backwpup' ), ceil( $execution_time ), $job_max_execution_time ) );
  843.             $this->do_restart( TRUE, FALSE );
  844.         }
  845.  
  846.         return $job_max_execution_time - $execution_time;
  847.  
  848.     }
  849.  
  850.     /**
  851.      * Get job restart time
  852.      *
  853.      * @return int remaining time
  854.      */
  855.     public function get_restart_time() {
  856.         $job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
  857.  
  858.         if ( empty( $job_max_execution_time ) )
  859.             return 300;
  860.  
  861.         $execution_time = microtime( TRUE ) - $this->timestamp_script_start;
  862.         return $job_max_execution_time - $execution_time - 3;
  863.     }
  864.  
  865.     /**
  866.      *
  867.      * Get data off a working job
  868.      *
  869.      * @return bool|object BackWPup_Job Object or Bool if file not exits
  870.      */
  871.     public static function get_working_data() {
  872.  
  873.         if ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
  874.             clearstatcache( TRUE, BackWPup::get_plugin_data( 'running_file' ) );
  875.         } else {
  876.             clearstatcache();
  877.         }
  878.  
  879.         if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) )
  880.             return FALSE;
  881.  
  882.         $file_data = file_get_contents( BackWPup::get_plugin_data( 'running_file' ), FALSE, NULL, 8 );
  883.         if ( $file_data === FALSE )
  884.             return FALSE;
  885.  
  886.         if ( $job_object = unserialize( $file_data ) ) {
  887.             if ( $job_object instanceof BackWPup_Job )
  888.                 return $job_object;
  889.         }
  890.  
  891.         return FALSE;
  892.  
  893.     }
  894.  
  895.     /**
  896.      *
  897.      * Reads a BackWPup logfile header and gives back a array of information
  898.      *
  899.      * @param string $logfile full logfile path
  900.      *
  901.      * @return array|bool
  902.      */
  903.     public static function read_logheader( $logfile ) {
  904.  
  905.         $usedmetas = array(
  906.             "date"                    => "logtime",
  907.             "backwpup_logtime"        => "logtime", //old value of date
  908.             "backwpup_errors"         => "errors",
  909.             "backwpup_warnings"       => "warnings",
  910.             "backwpup_jobid"          => "jobid",
  911.             "backwpup_jobname"        => "name",
  912.             "backwpup_jobtype"        => "type",
  913.             "backwpup_jobruntime"     => "runtime",
  914.             "backwpup_backupfilesize" => "backupfilesize"
  915.         );
  916.  
  917.         //get metadata of logfile
  918.         $metas = array();
  919.         if ( is_readable( $logfile ) ) {
  920.             if (  '.gz' == substr( $logfile, -3 )  )
  921.                 $metas = (array)get_meta_tags( 'compress.zlib://' . $logfile );
  922.             else
  923.                 $metas = (array)get_meta_tags( $logfile );
  924.         }
  925.  
  926.         //only output needed data
  927.         foreach ( $usedmetas as $keyword => $field ) {
  928.             if ( isset( $metas[ $keyword ] ) ) {
  929.                 $joddata[ $field ] = $metas[ $keyword ];
  930.             }
  931.             else {
  932.                 $joddata[ $field ] = '';
  933.             }
  934.         }
  935.  
  936.         //convert date
  937.         if ( isset( $metas[ 'date' ] ) )
  938.             $joddata[ 'logtime' ] = strtotime( $metas[ 'date' ] ) + ( get_option( 'gmt_offset' ) * 3600 );
  939.  
  940.         //use file create date if none
  941.         if ( empty( $joddata[ 'logtime' ] ) )
  942.             $joddata[ 'logtime' ] = filectime( $logfile );
  943.  
  944.         return $joddata;
  945.     }
  946.  
  947.  
  948.     /**
  949.      *
  950.      * Shutdown function is call if script terminates try to make a restart if needed
  951.      *
  952.      * Prepare the job for start
  953.      *
  954.      * @internal param int the signal that terminates the job
  955.      */
  956.     public function shutdown() {
  957.  
  958.         $args = func_get_args();
  959.  
  960.         //nothing on empty
  961.         if ( empty( $this->logfile ) )
  962.             return;
  963.         //Put last error to log if one
  964.         $lasterror = error_get_last();
  965.         if ( $lasterror[ 'type' ] == E_ERROR or $lasterror[ 'type' ] == E_PARSE or $lasterror[ 'type' ] == E_CORE_ERROR or $lasterror[ 'type' ] == E_CORE_WARNING or $lasterror[ 'type' ] == E_COMPILE_ERROR or $lasterror[ 'type' ] == E_COMPILE_WARNING )
  966.             $this->log( $lasterror[ 'type' ], $lasterror[ 'message' ], $lasterror[ 'file' ], $lasterror[ 'line' ] );
  967.         //Put sigterm to log
  968.         if ( ! empty( $args[ 0 ] ) )
  969.             $this->log( sprintf( __( 'Signal %d is sent to script!', 'backwpup' ), $args[ 0 ] ), E_USER_ERROR );
  970.  
  971.         $this->do_restart( TRUE, TRUE );
  972.     }
  973.  
  974.  
  975.     /**
  976.      *
  977.      * Check is folder readable and exists create it if not
  978.      * add .htaccess or index.html file in folder to prevent directory listing
  979.      *
  980.      * @param string $folder the folder to check
  981.      * @param bool   $donotbackup Create a file that the folder will not backuped
  982.      * @return bool ok or not
  983.      */
  984.     public static function check_folder( $folder, $donotbackup = FALSE ) {
  985.  
  986.         $folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
  987.         if ( empty( $folder ) )
  988.             return FALSE;
  989.         //check that is not home of WP
  990.         if ( $folder == untrailingslashit( str_replace( '\\', '/', ABSPATH ) ) ||
  991.             $folder == untrailingslashit( str_replace( '\\', '/', WP_PLUGIN_DIR ) ) ||
  992.             $folder == untrailingslashit( str_replace( '\\', '/', WP_CONTENT_DIR ) )
  993.         ) {
  994.             BackWPup_Admin::message( sprintf( __( 'Folder %1$s not allowed, please use another folder.', 'backwpup' ), $folder ), TRUE );
  995.             return FALSE;
  996.         }
  997.         //create folder if it not exists
  998.         if ( ! is_dir( $folder ) ) {
  999.             if ( ! wp_mkdir_p( $folder ) ) {
  1000.                 BackWPup_Admin::message( sprintf( __( 'Cannot create folder: %1$s', 'backwpup' ), $folder ), TRUE );
  1001.                 return FALSE;
  1002.             }
  1003.         }
  1004.  
  1005.         //check is writable dir
  1006.         if ( ! is_writable( $folder ) ) {
  1007.             BackWPup_Admin::message( sprintf( __( 'Folder "%1$s" is not writable', 'backwpup' ), $folder ), TRUE );
  1008.             return FALSE;
  1009.         }
  1010.  
  1011.         //create .htaccess for apache and index.php for folder security
  1012.         if ( get_site_option( 'backwpup_cfg_protectfolders') && ! file_exists( $folder . '/.htaccess' ) )
  1013.             file_put_contents( $folder . '/.htaccess', "<Files \"*\">" . PHP_EOL . "<IfModule mod_access.c>" . PHP_EOL . "Deny from all" . PHP_EOL . "</IfModule>" . PHP_EOL . "<IfModule !mod_access_compat>" . PHP_EOL . "<IfModule mod_authz_host.c>" . PHP_EOL . "Deny from all" . PHP_EOL . "</IfModule>" . PHP_EOL . "</IfModule>" . PHP_EOL . "<IfModule mod_access_compat>" . PHP_EOL . "Deny from all" . PHP_EOL . "</IfModule>" . PHP_EOL . "</Files>" );
  1014.         if ( get_site_option( 'backwpup_cfg_protectfolders') && ! file_exists( $folder . '/index.php' ) )
  1015.             file_put_contents( $folder . '/index.php', "<?php" . PHP_EOL . "header( \$_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found' );" . PHP_EOL . "header( 'Status: 404 Not Found' );" . PHP_EOL );
  1016.  
  1017.         //Create do not backup file for this folder
  1018.         if ( $donotbackup && ! file_exists( $folder . '/.donotbackup' ) )
  1019.             file_put_contents( $folder . '/.donotbackup', __( 'BackWPup will not backup folders and subfolders when this file is inside.', 'backwpup' ) );
  1020.  
  1021.         return TRUE;
  1022.     }
  1023.  
  1024.     /**
  1025.      *
  1026.      * The uncouth exception handler
  1027.      *
  1028.      * @param object $exception
  1029.      */
  1030.     public function exception_handler( $exception ) {
  1031.         $this->log( E_USER_ERROR, sprintf( __( 'Exception caught in %1$s: %2$s', 'backwpup' ), get_class( $exception ), htmlentities( $exception->getMessage() ) ), $exception->getFile(), $exception->getLine() );
  1032.     }
  1033.  
  1034.     /**
  1035.      * Write messages to log file
  1036.      *
  1037.      * @internal param int     the error number (E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE, ...)
  1038.      * @internal param string  the error message
  1039.      * @internal param string  the full path of file with error (__FILE__)
  1040.      * @internal param int     the line in that is the error (__LINE__)
  1041.      *
  1042.      * @return bool true
  1043.      */
  1044.     public function log() {
  1045.  
  1046.         $args = func_get_args();
  1047.         // if error has been suppressed with an @
  1048.         if ( error_reporting() == 0 )
  1049.             return TRUE;
  1050.  
  1051.         //if first the message an second the type switch it on user errors
  1052.         if ( isset( $args[ 1 ] ) && in_array( $args[ 1 ], array( E_USER_NOTICE, E_USER_WARNING, E_USER_ERROR, 16384 ) ) ) {
  1053.             $temp       = $args[ 0 ];
  1054.             $args[ 0 ]  = $args[ 1 ];
  1055.             $args[ 1 ]  = $temp;
  1056.         }
  1057.  
  1058.         //if first the message and nothing else set
  1059.         if ( ! isset( $args[ 1 ] ) ) {
  1060.             $args[ 1 ] = $args[ 0 ];
  1061.             $args[ 0 ] = E_USER_NOTICE;
  1062.         }
  1063.  
  1064.         //json message if array or object
  1065.         if ( is_array( $args[ 1 ] ) || is_object( $args[ 1 ] ) )
  1066.             $args[ 1 ] = json_encode( $args[ 1 ] );
  1067.  
  1068.         //if not set line and file get it
  1069.         if ( empty( $args[ 2 ] ) || empty( $args[ 3 ] ) ) {
  1070.             $debug_info = debug_backtrace();
  1071.             $args[ 2 ] = $debug_info[ 0 ][ 'file' ];
  1072.             $args[ 3 ] = $debug_info[ 0 ][ 'line' ];
  1073.         }
  1074.  
  1075.         $error_or_warning = FALSE;
  1076.  
  1077.         switch ( $args[ 0 ] ) {
  1078.             case E_NOTICE:
  1079.             case E_USER_NOTICE:
  1080.                 $messagetype = '';
  1081.                 break;
  1082.             case E_WARNING:
  1083.             case E_CORE_WARNING:
  1084.             case E_COMPILE_WARNING:
  1085.             case E_USER_WARNING:
  1086.                 $this->warnings ++;
  1087.                 $error_or_warning = TRUE;
  1088.                 $messagetype = '<span style="background-color:#ffc000;color:#fff">' . __( 'WARNING:', 'backwpup' ) . ' ';
  1089.                 break;
  1090.             case E_ERROR:
  1091.             case E_PARSE:
  1092.             case E_CORE_ERROR:
  1093.             case E_COMPILE_ERROR:
  1094.             case E_USER_ERROR:
  1095.                 $this->errors ++;
  1096.                 $error_or_warning = TRUE;
  1097.                 $messagetype = '<span style="background-color:red;color:#fff">' . __( 'ERROR:', 'backwpup' ) . ' ';
  1098.                 break;
  1099.             case 8192: //E_DEPRECATED      comes with php 5.3
  1100.             case 16384: //E_USER_DEPRECATED comes with php 5.3
  1101.                 $messagetype = __( 'DEPRECATED:', 'backwpup' ) . ' ';
  1102.                 break;
  1103.             case E_STRICT:
  1104.                 $messagetype = __( 'STRICT NOTICE:', 'backwpup' ) . ' ';
  1105.                 break;
  1106.             case E_RECOVERABLE_ERROR:
  1107.                 $this->errors ++;
  1108.                 $error_or_warning = TRUE;
  1109.                 $messagetype = '<span style="background-color:red;color:#fff">' . __( 'RECOVERABLE ERROR:', 'backwpup' ) . ' ';
  1110.                 break;
  1111.             default:
  1112.                 $messagetype = $args[ 0 ] . ": ";
  1113.                 break;
  1114.         }
  1115.  
  1116.         $in_file = str_replace( str_replace( '\\', '/', ABSPATH ), '', str_replace( '\\', '/', $args[ 2 ] ) );
  1117.  
  1118.         //print message to cli
  1119.         if ( php_sapi_name() == 'cli' && defined( 'STDOUT' ) )
  1120.             fwrite( STDOUT, '[' . date_i18n( 'd-M-Y H:i:s' ) . '] ' . strip_tags( $messagetype ) . str_replace( '&hellip;', '...', strip_tags( $args[ 1 ] ) ) . PHP_EOL ) ;
  1121.         //log line
  1122.         $timestamp = '<span datetime="' . date_i18n( 'c' ) . '" title="[Type: ' . $args[ 0 ] . '|Line: ' . $args[ 3 ] . '|File: ' . $in_file . '|Mem: ' . size_format( @memory_get_usage( TRUE ), 2 ) . '|Mem Max: ' . size_format( @memory_get_peak_usage( TRUE ), 2 ) . '|Mem Limit: ' . ini_get( 'memory_limit' ) . '|PID: ' . self::get_pid() . ' | UniqID: ' . $this->uniqid . '|Query\'s: ' . get_num_queries() . ']">[' . date_i18n( 'd-M-Y H:i:s' ) . ']</span> ';
  1123.         //set last Message
  1124.         $message = $messagetype . htmlentities( $args[ 1 ], ENT_COMPAT , get_bloginfo( 'charset' ), FALSE );
  1125.         if ( strstr( $message, '<span' ) )
  1126.             $message .= '</span>';
  1127.         if ( $args[ 0 ] == E_NOTICE || $args[ 0 ] == E_USER_NOTICE )
  1128.             $this->lastmsg = $message;
  1129.         if ( $error_or_warning )
  1130.             $this->lasterrormsg = $message;
  1131.         //write log file
  1132.         file_put_contents( $this->logfile, $timestamp . $message . '<br />' . PHP_EOL, FILE_APPEND  );
  1133.  
  1134.         //write new log header
  1135.         if ( $error_or_warning ) {
  1136.             $found   = 0;
  1137.             $fd      = fopen( $this->logfile, 'r+' );
  1138.             $file_pos = ftell( $fd );
  1139.             while ( ! feof( $fd ) ) {
  1140.                 $line = fgets( $fd );
  1141.                 if ( stripos( $line, '<meta name="backwpup_errors" content="' ) !== FALSE ) {
  1142.                     fseek( $fd, $file_pos );
  1143.                     fwrite( $fd, str_pad( '<meta name="backwpup_errors" content="' . $this->errors . '" />', 100 ) . PHP_EOL );
  1144.                     $found ++;
  1145.                 }
  1146.                 if ( stripos( $line, '<meta name="backwpup_warnings" content="' ) !== FALSE ) {
  1147.                     fseek( $fd, $file_pos );
  1148.                     fwrite( $fd, str_pad( '<meta name="backwpup_warnings" content="' . $this->warnings . '" />', 100 ) . PHP_EOL );
  1149.                     $found ++;
  1150.                 }
  1151.                 if ( $found >= 2 )
  1152.                     break;
  1153.                 $file_pos = ftell( $fd );
  1154.             }
  1155.             fclose( $fd );
  1156.         }
  1157.  
  1158.         //write working data
  1159.         $this->update_working_data( $error_or_warning );
  1160.  
  1161.         //true for no more php error handling.
  1162.         return TRUE;
  1163.     }
  1164.  
  1165.     /**
  1166.      *
  1167.      * Write the Working data to display the process or that i can executes again
  1168.      * The write will only done every second
  1169.      *
  1170.      * @global wpdb $wpdb
  1171.      */
  1172.     public function update_working_data() {
  1173.         global $wpdb;
  1174.         /* @var wpdb $wpdb */
  1175.  
  1176.         //to reduce server load
  1177.         if ( get_site_option( 'backwpup_cfg_jobwaittimems' ) > 0 && get_site_option( 'backwpup_cfg_jobwaittimems') <= 500000 )
  1178.             usleep( get_site_option( 'backwpup_cfg_jobwaittimems' ) );
  1179.  
  1180.         //check free memory
  1181.         $this->need_free_memory( '10M' );
  1182.  
  1183.         //only run every 1 sec.
  1184.         $time_to_update = microtime( TRUE ) - $this->timestamp_last_update;
  1185.         if ( $time_to_update < 1 )
  1186.             return;
  1187.  
  1188.         //FCGI must have a permanent output so that it not broke
  1189.         if ( stristr( PHP_SAPI, 'fcgi' ) || stristr( PHP_SAPI, 'litespeed' ) ) {
  1190.             //only if no output buffering is active
  1191.             if ( ob_get_level() == 0 ) {
  1192.                 echo '          ';
  1193.                 flush();
  1194.             }
  1195.         }
  1196.  
  1197.         //set execution time again for 5 min
  1198.         @set_time_limit( 300 );
  1199.  
  1200.         //check MySQL connection to WordPress Database and reconnect if needed
  1201.         $res = $wpdb->query( 'SELECT 1' );
  1202.         if ( $res === FALSE )
  1203.             $wpdb->db_connect();
  1204.  
  1205.         //calc sub step percent
  1206.         if ( $this->substeps_todo > 0 && $this->substeps_done > 0 )
  1207.             $this->substep_percent = round( $this->substeps_done / $this->substeps_todo * 100 );
  1208.         else
  1209.             $this->substep_percent = 1;
  1210.  
  1211.         //check if job aborted
  1212.         if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
  1213.             if ( $this->step_working != 'END' )
  1214.                 $this->end();
  1215.         } else {
  1216.             $this->timestamp_last_update = microtime( TRUE ); //last update of working file
  1217.             $this->write_running_file();
  1218.         }
  1219.     }
  1220.  
  1221.     public function write_running_file() {
  1222.  
  1223.         $clone = clone $this;
  1224.         $data = '<?php //' . serialize( $clone );
  1225.  
  1226.         $write = file_put_contents( BackWPup::get_plugin_data( 'running_file' ), $data );
  1227.         if ( !$write || $write < strlen( $data ) ) {
  1228.             unlink( BackWPup::get_plugin_data( 'running_file' ) );
  1229.             $this->log( __( 'Cannot write progress to working file. Job will be aborted.', 'backwpup' ), E_USER_ERROR );
  1230.         }
  1231.     }
  1232.  
  1233.     /**
  1234.      *
  1235.      * Called on job stop makes cleanup and terminates the script
  1236.      *
  1237.      */
  1238.     private function end() {
  1239.  
  1240.         $this->step_working = 'END';
  1241.         $this->substeps_todo = 1;
  1242.         $abort = FALSE;
  1243.  
  1244.         if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
  1245.             if ( ! $this->user_abort )
  1246.                 $abort = TRUE;
  1247.             $this->log( __( 'Aborted by user!', 'backwpup' ), E_USER_ERROR );
  1248.         }
  1249.  
  1250.         //delete old logs
  1251.         if ( get_site_option( 'backwpup_cfg_maxlogs' ) ) {
  1252.             $log_file_list = array();
  1253.             if ( $dir = opendir( get_site_option( 'backwpup_cfg_logfolder' ) ) ) { //make file list
  1254.                 while ( ( $file = readdir( $dir ) ) !== FALSE ) {
  1255.                     if ( strpos( $file, 'backwpup_log_' ) == 0 && FALSE !== strpos( $file, '.html' ) )
  1256.                         $log_file_list[ filemtime( get_site_option( 'backwpup_cfg_logfolder' ) . '/' . $file ) ] = $file;
  1257.                 }
  1258.                 closedir( $dir );
  1259.             }
  1260.             if ( sizeof( $log_file_list ) > 0 ) {
  1261.                 krsort( $log_file_list, SORT_NUMERIC );
  1262.                 $num_delete_files = 0;
  1263.                 $i = -1;
  1264.                 foreach ( $log_file_list AS $log_file ) {
  1265.                     $i ++;
  1266.                     if ( $i <  get_site_option( 'backwpup_cfg_maxlogs' ) )
  1267.                         continue;
  1268.                     unlink( get_site_option( 'backwpup_cfg_logfolder' ) . $log_file );
  1269.                     $num_delete_files ++;
  1270.                 }
  1271.                 if ( $num_delete_files > 0 )
  1272.                     $this->log( sprintf( _n( 'One old log deleted', '%d old logs deleted', $num_delete_files, 'backwpup' ), $num_delete_files ) );
  1273.             }
  1274.         }
  1275.  
  1276.         //Display job working time
  1277.         if ( $this->errors > 0 )
  1278.             $this->log( sprintf( __( 'Job has ended with errors in %s seconds. You must resolve the errors for correct execution.', 'backwpup' ), current_time( 'timestamp' ) - $this->start_time ), E_USER_ERROR );
  1279.         elseif ( $this->warnings > 0 )
  1280.             $this->log( sprintf( __( 'Job finished with warnings in %s seconds. Please resolve them for correct execution.', 'backwpup' ), current_time( 'timestamp' ) - $this->start_time ), E_USER_WARNING );
  1281.         else
  1282.             $this->log( sprintf( __( 'Job done in %s seconds.', 'backwpup' ), current_time( 'timestamp' ) - $this->start_time, E_USER_NOTICE ) );
  1283.  
  1284.         //Update job options
  1285.         if ( ! empty( $this->job[ 'jobid' ] ) ) {
  1286.             $this->job[ 'lastruntime' ] = current_time( 'timestamp' ) - $this->start_time;
  1287.             BackWPup_Option::update( $this->job[ 'jobid' ], 'lastruntime', $this->job[ 'lastruntime' ] );
  1288.         }
  1289.  
  1290.         //write header info
  1291.         if ( is_writable( $this->logfile ) ) {
  1292.             $fd      = fopen( $this->logfile, 'r+' );
  1293.             $filepos = ftell( $fd );
  1294.             $found   = 0;
  1295.             while ( ! feof( $fd ) ) {
  1296.                 $line = fgets( $fd );
  1297.                 if ( stripos( $line, '<meta name="backwpup_jobruntime"' ) !== FALSE ) {
  1298.                     fseek( $fd, $filepos );
  1299.                     fwrite( $fd, str_pad( '<meta name="backwpup_jobruntime" content="' . $this->job[ 'lastruntime' ] . '" />', 100 ) . PHP_EOL );
  1300.                     $found ++;
  1301.                 }
  1302.                 if ( stripos( $line, '<meta name="backwpup_backupfilesize"' ) !== FALSE ) {
  1303.                     fseek( $fd, $filepos );
  1304.                     fwrite( $fd, str_pad( '<meta name="backwpup_backupfilesize" content="' . $this->backup_filesize . '" />', 100 ) . PHP_EOL );
  1305.                     $found ++;
  1306.                 }
  1307.                 if ( $found >= 2 )
  1308.                     break;
  1309.                 $filepos = ftell( $fd );
  1310.             }
  1311.             fclose( $fd );
  1312.         }
  1313.  
  1314.         //logfile end
  1315.         file_put_contents( $this->logfile, "</body>" . PHP_EOL . "</html>", FILE_APPEND );
  1316.  
  1317.         //Send mail with log
  1318.         $sendmail = FALSE;
  1319.         if ( $this->errors > 0 && ! empty( $this->job[ 'mailerroronly' ] ) && ! empty( $this->job[ 'mailaddresslog' ] ) )
  1320.             $sendmail = TRUE;
  1321.         if ( empty( $this->job[ 'mailerroronly' ] ) && ! empty( $this->job[ 'mailaddresslog' ] ) )
  1322.             $sendmail = TRUE;
  1323.         if ( $sendmail ) {
  1324.             //special subject
  1325.             $status   = __( 'SUCCESSFUL', 'backwpup' );
  1326.             $priority = 3; //Normal
  1327.             if ( $this->warnings > 0 ) {
  1328.                 $status   = __( 'WARNING', 'backwpup' );
  1329.                 $priority = 2; //High
  1330.             }
  1331.             if ( $this->errors > 0 ) {
  1332.                 $status   = __( 'ERROR', 'backwpup' );
  1333.                 $priority = 1; //Highest
  1334.             }
  1335.  
  1336.             $subject = sprintf( __( '[%3$s] BackWPup log %1$s: %2$s', 'backwpup' ), date_i18n( 'd-M-Y H:i', $this->start_time, TRUE ), esc_attr( $this->job[ 'name' ] ), $status );
  1337.             $headers = array();
  1338.             $headers[] = 'Content-Type: text/html; charset='. get_bloginfo( 'charset' );
  1339.             /* $headers[] = 'X-Priority: ' . $priority; */ // Priority not working with header setting
  1340.             if ( ! empty( $this->job[ 'mailaddresssenderlog' ] ) ) {
  1341.                 if ( FALSE === $start_mail = strpos( $this->job[ 'mailaddresssenderlog' ], '<' ) ) {
  1342.                     if ( FALSE === strpos( $this->job[ 'mailaddresssenderlog' ], '@' ) ) {
  1343.                         $this->job[ 'mailaddresssenderlog' ] = '"' . str_replace( array( '<','>','@' ), '', $this->job[ 'mailaddresssenderlog' ] ) . '" <' . get_bloginfo( 'admin_email' ). '>';
  1344.                     }
  1345.                 }
  1346.                 elseif ( FALSE === strpos( $this->job[ 'mailaddresssenderlog' ], '>', $start_mail ) ) {
  1347.                     $this->job[ 'mailaddresssenderlog' ] = '"' . str_replace( array( '<','>','@' ), '', substr( $this->job[ 'mailaddresssenderlog' ], 0, $start_mail ) ) . '" <' . get_bloginfo( 'admin_email' ). '>';
  1348.                 }
  1349.  
  1350.                 $headers[] = 'From: ' . $this->job[ 'mailaddresssenderlog' ];
  1351.             }
  1352.  
  1353.             wp_mail( $this->job[ 'mailaddresslog' ], $subject, file_get_contents( $this->logfile ), $headers );
  1354.         }
  1355.  
  1356.         //set done
  1357.         $this->substeps_done = 1;
  1358.         $this->steps_done[ ] = 'END';
  1359.  
  1360.         //clean up temp
  1361.         self::clean_temp_folder();
  1362.  
  1363.         //remove shutdown action
  1364.         remove_action( 'shutdown', array( $this, 'shutdown' ) );
  1365.         restore_exception_handler();
  1366.         restore_error_handler();
  1367.         if ( ! empty( $this->run[ 'PHP' ] ) ) {
  1368.             @ini_set( 'log_errors', $this->run[ 'PHP' ][ 'INI' ][ 'LOG_ERRORS' ] );
  1369.             @ini_set( 'error_log', $this->run[ 'PHP' ][ 'INI' ][ 'ERROR_LOG' ] );
  1370.             @ini_set( 'display_errors', $this->run[ 'PHP' ][ 'INI' ][ 'DISPLAY_ERRORS' ] );
  1371.             @ini_set( 'html_errors', $this->run[ 'PHP' ][ 'INI' ][ 'HTML_ERRORS' ] );
  1372.             @ini_set( 'zlib.output_compression', $this->run[ 'PHP' ][ 'INI' ][ 'ZLIB_OUTPUT_COMPRESSION' ] );
  1373.             @ini_set( 'implicit_flush', $this->run[ 'PHP' ][ 'INI' ][ 'IMPLICIT_FLUSH' ] );
  1374.             @ini_set( 'error_reporting', $this->run[ 'PHP' ][ 'INI' ][ 'ERROR_REPORTING' ] );
  1375.             @ini_set( 'report_memleaks', $this->run[ 'PHP' ][ 'INI' ][ 'REPORT_MEMLEAKS' ] );
  1376.             if ( !empty( $this->run[ 'PHP' ][ 'ENV' ][ 'TEMPDIR' ] ) ) {
  1377.                 @putenv('TMPDIR=' . $this->run[ 'PHP' ][ 'ENV' ][ 'TEMPDIR' ] );
  1378.             }
  1379.         }
  1380.  
  1381.         BackWPup_Cron::check_cleanup();
  1382.  
  1383.         if ( $abort )
  1384.             exit();
  1385.     }
  1386.  
  1387.  
  1388.     public static function user_abort() {
  1389.  
  1390.         /* @var $job_object BackWPup_Job */
  1391.         $job_object = BackWPup_Job::get_working_data();
  1392.  
  1393.         unlink( BackWPup::get_plugin_data( 'running_file' ) );
  1394.  
  1395.         //if job not working currently abort it this way for message
  1396.         $not_worked_time = microtime( TRUE ) - $job_object->timestamp_last_update;
  1397.         $restart_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
  1398.         if ( empty( $restart_time ) )
  1399.             $restart_time = 60;
  1400.         if ( empty( $job_object->pid ) || $not_worked_time > $restart_time ) {
  1401.             $job_object->user_abort = TRUE;
  1402.             $job_object->update_working_data();
  1403.         }
  1404.  
  1405.     }
  1406.  
  1407.     /**
  1408.      *
  1409.      * Increase automatically the memory that is needed
  1410.      *
  1411.      * @param int|string $memneed of the needed memory
  1412.      */
  1413.     public function need_free_memory( $memneed ) {
  1414.  
  1415.         //need memory
  1416.         $needmemory = @memory_get_usage( TRUE ) + self::convert_hr_to_bytes( $memneed );
  1417.         // increase Memory
  1418.         if ( $needmemory > self::convert_hr_to_bytes( ini_get( 'memory_limit' ) ) ) {
  1419.             $newmemory = round( $needmemory / 1024 / 1024 ) + 1 . 'M';
  1420.             if ( $needmemory >= 1073741824 )
  1421.                 $newmemory = round( $needmemory / 1024 / 1024 / 1024 ) . 'G';
  1422.             @ini_set( 'memory_limit', $newmemory );
  1423.         }
  1424.     }
  1425.  
  1426.  
  1427.     /**
  1428.      *
  1429.      * Converts hr to bytes
  1430.      *
  1431.      * @param $size
  1432.      * @return int
  1433.      */
  1434.     public static function convert_hr_to_bytes( $size ) {
  1435.         $size  = strtolower( $size );
  1436.         $bytes = (int) $size;
  1437.         if ( strpos( $size, 'k' ) !== FALSE )
  1438.             $bytes = intval( $size ) * 1024;
  1439.         elseif ( strpos( $size, 'm' ) !== FALSE )
  1440.             $bytes = intval($size) * 1024 * 1024;
  1441.         elseif ( strpos( $size, 'g' ) !== FALSE )
  1442.             $bytes = intval( $size ) * 1024 * 1024 * 1024;
  1443.         return $bytes;
  1444.     }
  1445.  
  1446.     /**
  1447.      *
  1448.      * Callback for the CURLOPT_READFUNCTION that submit the transferred bytes
  1449.      * to build the process bar
  1450.      *
  1451.      * @param $curl_handle
  1452.      * @param $file_handle
  1453.      * @param $read_count
  1454.      * @return string
  1455.      * @internal param $out
  1456.      */
  1457.     public function curl_read_callback( $curl_handle, $file_handle, $read_count ) {
  1458.  
  1459.         $data = NULL;
  1460.         if ( ! empty( $file_handle ) && is_numeric( $read_count ) )
  1461.             $data = fread( $file_handle, $read_count );
  1462.  
  1463.         if (  $this->job[ 'backuptype' ] == 'sync'  )
  1464.             return $data;
  1465.  
  1466.         $length = ( is_numeric( $read_count ) ) ? $read_count : strlen( $read_count );
  1467.         $this->substeps_done = $this->substeps_done + $length;
  1468.         $this->update_working_data();
  1469.  
  1470.         return $data;
  1471.     }
  1472.  
  1473.  
  1474.     /**
  1475.      *
  1476.      * Get the mime type of a file
  1477.      *
  1478.      * @param string $file The full file name
  1479.      *
  1480.      * @return bool|string the mime type or false
  1481.      */
  1482.     public function get_mime_type( $file ) {
  1483.  
  1484.         if ( is_dir( $file ) || is_link( $file ) )
  1485.             return 'application/octet-stream';
  1486.  
  1487.         $mime_types = array(
  1488.             'zip'     => 'application/zip',
  1489.             'gz'      => 'application/gzip',
  1490.             'bz2'     => 'application/x-bzip',
  1491.             'tar'     => 'application/x-tar',
  1492.             '3gp'     => 'video/3gpp',
  1493.             'ai'      => 'application/postscript',
  1494.             'aif'     => 'audio/x-aiff',
  1495.             'aifc'    => 'audio/x-aiff',
  1496.             'aiff'    => 'audio/x-aiff',
  1497.             'asc'     => 'text/plain',
  1498.             'atom'    => 'application/atom+xml',
  1499.             'au'      => 'audio/basic',
  1500.             'avi'     => 'video/x-msvideo',
  1501.             'bcpio'   => 'application/x-bcpio',
  1502.             'bin'     => 'application/octet-stream',
  1503.             'bmp'     => 'image/bmp',
  1504.             'cdf'     => 'application/x-netcdf',
  1505.             'cgm'     => 'image/cgm',
  1506.             'class'   => 'application/octet-stream',
  1507.             'cpio'    => 'application/x-cpio',
  1508.             'cpt'     => 'application/mac-compactpro',
  1509.             'csh'     => 'application/x-csh',
  1510.             'css'     => 'text/css',
  1511.             'dcr'     => 'application/x-director',
  1512.             'dif'     => 'video/x-dv',
  1513.             'dir'     => 'application/x-director',
  1514.             'djv'     => 'image/vnd.djvu',
  1515.             'djvu'    => 'image/vnd.djvu',
  1516.             'dll'     => 'application/octet-stream',
  1517.             'dmg'     => 'application/octet-stream',
  1518.             'dms'     => 'application/octet-stream',
  1519.             'doc'     => 'application/msword',
  1520.             'dtd'     => 'application/xml-dtd',
  1521.             'dv'      => 'video/x-dv',
  1522.             'dvi'     => 'application/x-dvi',
  1523.             'dxr'     => 'application/x-director',
  1524.             'eps'     => 'application/postscript',
  1525.             'etx'     => 'text/x-setext',
  1526.             'exe'     => 'application/octet-stream',
  1527.             'ez'      => 'application/andrew-inset',
  1528.             'flv'     => 'video/x-flv',
  1529.             'gif'     => 'image/gif',
  1530.             'gram'    => 'application/srgs',
  1531.             'grxml'   => 'application/srgs+xml',
  1532.             'gtar'    => 'application/x-gtar',
  1533.             'hdf'     => 'application/x-hdf',
  1534.             'hqx'     => 'application/mac-binhex40',
  1535.             'htm'     => 'text/html',
  1536.             'html'    => 'text/html',
  1537.             'ice'     => 'x-conference/x-cooltalk',
  1538.             'ico'     => 'image/x-icon',
  1539.             'ics'     => 'text/calendar',
  1540.             'ief'     => 'image/ief',
  1541.             'ifb'     => 'text/calendar',
  1542.             'iges'    => 'model/iges',
  1543.             'igs'     => 'model/iges',
  1544.             'jnlp'    => 'application/x-java-jnlp-file',
  1545.             'jp2'     => 'image/jp2',
  1546.             'jpe'     => 'image/jpeg',
  1547.             'jpeg'    => 'image/jpeg',
  1548.             'jpg'     => 'image/jpeg',
  1549.             'js'      => 'application/x-javascript',
  1550.             'kar'     => 'audio/midi',
  1551.             'latex'   => 'application/x-latex',
  1552.             'lha'     => 'application/octet-stream',
  1553.             'lzh'     => 'application/octet-stream',
  1554.             'm3u'     => 'audio/x-mpegurl',
  1555.             'm4a'     => 'audio/mp4a-latm',
  1556.             'm4p'     => 'audio/mp4a-latm',
  1557.             'm4u'     => 'video/vnd.mpegurl',
  1558.             'm4v'     => 'video/x-m4v',
  1559.             'mac'     => 'image/x-macpaint',
  1560.             'man'     => 'application/x-troff-man',
  1561.             'mathml'  => 'application/mathml+xml',
  1562.             'me'      => 'application/x-troff-me',
  1563.             'mesh'    => 'model/mesh',
  1564.             'mid'     => 'audio/midi',
  1565.             'midi'    => 'audio/midi',
  1566.             'mif'     => 'application/vnd.mif',
  1567.             'mov'     => 'video/quicktime',
  1568.             'movie'   => 'video/x-sgi-movie',
  1569.             'mp2'     => 'audio/mpeg',
  1570.             'mp3'     => 'audio/mpeg',
  1571.             'mp4'     => 'video/mp4',
  1572.             'mpe'     => 'video/mpeg',
  1573.             'mpeg'    => 'video/mpeg',
  1574.             'mpg'     => 'video/mpeg',
  1575.             'mpga'    => 'audio/mpeg',
  1576.             'ms'      => 'application/x-troff-ms',
  1577.             'msh'     => 'model/mesh',
  1578.             'mxu'     => 'video/vnd.mpegurl',
  1579.             'nc'      => 'application/x-netcdf',
  1580.             'oda'     => 'application/oda',
  1581.             'ogg'     => 'application/ogg',
  1582.             'ogv'     => 'video/ogv',
  1583.             'pbm'     => 'image/x-portable-bitmap',
  1584.             'pct'     => 'image/pict',
  1585.             'pdb'     => 'chemical/x-pdb',
  1586.             'pdf'     => 'application/pdf',
  1587.             'pgm'     => 'image/x-portable-graymap',
  1588.             'pgn'     => 'application/x-chess-pgn',
  1589.             'pic'     => 'image/pict',
  1590.             'pict'    => 'image/pict',
  1591.             'png'     => 'image/png',
  1592.             'pnm'     => 'image/x-portable-anymap',
  1593.             'pnt'     => 'image/x-macpaint',
  1594.             'pntg'    => 'image/x-macpaint',
  1595.             'ppm'     => 'image/x-portable-pixmap',
  1596.             'ppt'     => 'application/vnd.ms-powerpoint',
  1597.             'ps'      => 'application/postscript',
  1598.             'qt'      => 'video/quicktime',
  1599.             'qti'     => 'image/x-quicktime',
  1600.             'qtif'    => 'image/x-quicktime',
  1601.             'ra'      => 'audio/x-pn-realaudio',
  1602.             'ram'     => 'audio/x-pn-realaudio',
  1603.             'ras'     => 'image/x-cmu-raster',
  1604.             'rdf'     => 'application/rdf+xml',
  1605.             'rgb'     => 'image/x-rgb',
  1606.             'rm'      => 'application/vnd.rn-realmedia',
  1607.             'roff'    => 'application/x-troff',
  1608.             'rtf'     => 'text/rtf',
  1609.             'rtx'     => 'text/richtext',
  1610.             'sgm'     => 'text/sgml',
  1611.             'sgml'    => 'text/sgml',
  1612.             'sh'      => 'application/x-sh',
  1613.             'shar'    => 'application/x-shar',
  1614.             'silo'    => 'model/mesh',
  1615.             'sit'     => 'application/x-stuffit',
  1616.             'skd'     => 'application/x-koan',
  1617.             'skm'     => 'application/x-koan',
  1618.             'skp'     => 'application/x-koan',
  1619.             'skt'     => 'application/x-koan',
  1620.             'smi'     => 'application/smil',
  1621.             'smil'    => 'application/smil',
  1622.             'snd'     => 'audio/basic',
  1623.             'so'      => 'application/octet-stream',
  1624.             'spl'     => 'application/x-futuresplash',
  1625.             'src'     => 'application/x-wais-source',
  1626.             'sv4cpio' => 'application/x-sv4cpio',
  1627.             'sv4crc'  => 'application/x-sv4crc',
  1628.             'svg'     => 'image/svg+xml',
  1629.             'swf'     => 'application/x-shockwave-flash',
  1630.             't'       => 'application/x-troff',
  1631.             'tcl'     => 'application/x-tcl',
  1632.             'tex'     => 'application/x-tex',
  1633.             'texi'    => 'application/x-texinfo',
  1634.             'texinfo' => 'application/x-texinfo',
  1635.             'tif'     => 'image/tiff',
  1636.             'tiff'    => 'image/tiff',
  1637.             'tr'      => 'application/x-troff',
  1638.             'tsv'     => 'text/tab-separated-values',
  1639.             'txt'     => 'text/plain',
  1640.             'ustar'   => 'application/x-ustar',
  1641.             'vcd'     => 'application/x-cdlink',
  1642.             'vrml'    => 'model/vrml',
  1643.             'vxml'    => 'application/voicexml+xml',
  1644.             'wav'     => 'audio/x-wav',
  1645.             'wbmp'    => 'image/vnd.wap.wbmp',
  1646.             'wbxml'   => 'application/vnd.wap.wbxml',
  1647.             'webm'    => 'video/webm',
  1648.             'wml'     => 'text/vnd.wap.wml',
  1649.             'wmlc'    => 'application/vnd.wap.wmlc',
  1650.             'wmls'    => 'text/vnd.wap.wmlscript',
  1651.             'wmlsc'   => 'application/vnd.wap.wmlscriptc',
  1652.             'wmv'     => 'video/x-ms-wmv',
  1653.             'wrl'     => 'model/vrml',
  1654.             'xbm'     => 'image/x-xbitmap',
  1655.             'xht'     => 'application/xhtml+xml',
  1656.             'xhtml'   => 'application/xhtml+xml',
  1657.             'xls'     => 'application/vnd.ms-excel',
  1658.             'xml'     => 'application/xml',
  1659.             'xpm'     => 'image/x-xpixmap',
  1660.             'xsl'     => 'application/xml',
  1661.             'xslt'    => 'application/xslt+xml',
  1662.             'xul'     => 'application/vnd.mozilla.xul+xml',
  1663.             'xwd'     => 'image/x-xwindowdump',
  1664.             'xyz'     => 'chemical/x-xyz',
  1665.         );
  1666.  
  1667.         $filesuffix = pathinfo( $file, PATHINFO_EXTENSION );
  1668.         $suffix = strtolower( $filesuffix );
  1669.         if ( isset( $mime_types[ $suffix ] ) )
  1670.             return $mime_types[ $suffix ];
  1671.  
  1672.         if ( ! is_readable( $file ) )
  1673.             return 'application/octet-stream';
  1674.  
  1675.         if ( function_exists( 'fileinfo' ) ) {
  1676.             $finfo = finfo_open( FILEINFO_MIME_TYPE );
  1677.             $mime = finfo_file( $finfo, $file );
  1678.         }
  1679.  
  1680.         if ( empty( $mime ) && function_exists( 'mime_content_type' ) )
  1681.             $mime = mime_content_type( $file );
  1682.  
  1683.         if ( empty( $mime ) )
  1684.             return 'application/octet-stream';
  1685.         else
  1686.             return $mime;
  1687.     }
  1688.  
  1689.  
  1690.     /**
  1691.      *
  1692.      * Gifs back a array of files to backup in the selected folder
  1693.      *
  1694.      * @param string $folder the folder to get the files from
  1695.      *
  1696.      * @return array files to backup
  1697.      */
  1698.     public function get_files_in_folder( $folder ) {
  1699.  
  1700.         $files = array();
  1701.         $folder = trailingslashit( $folder );
  1702.  
  1703.         if ( ! is_dir( $folder ) ) {
  1704.             $this->log( sprintf( _x( 'Folder %s not exists', 'Folder name', 'backwpup' ), $folder ), E_USER_WARNING );
  1705.             return $files;
  1706.         }
  1707.  
  1708.         if ( ! is_readable( $folder ) ) {
  1709.             $this->log( sprintf( _x( 'Folder %s not readable', 'Folder name', 'backwpup' ), $folder ), E_USER_WARNING );
  1710.             return $files;
  1711.         }
  1712.  
  1713.         if ( $dir = opendir( $folder ) ) {
  1714.             while ( FALSE !== ( $file = readdir( $dir ) ) ) {
  1715.                 if ( in_array( $file, array( '.', '..' ) ) || is_dir( $folder . $file ) )
  1716.                     continue;
  1717.                 foreach ( $this->exclude_from_backup as $exclusion ) { //exclude files
  1718.                     $exclusion = trim( $exclusion );
  1719.                     if ( FALSE !== stripos( $folder . $file, trim( $exclusion ) ) && ! empty( $exclusion ) )
  1720.                         continue 2;
  1721.                 }
  1722.                 if ( $this->job[ 'backupexcludethumbs' ] && strpos( $folder, BackWPup_File::get_upload_dir() ) !== FALSE && preg_match( "/\-[0-9]{1,4}x[0-9]{1,4}.+\.(jpg|png|gif)$/i", $file ) ) {
  1723.                     continue;
  1724.                 }
  1725.                 if ( is_link( $folder . $file ) ) {
  1726.                     $this->log( sprintf( __( 'Link "%s" not following.', 'backwpup' ), $folder . $file ), E_USER_WARNING );
  1727.                 } elseif ( ! is_readable( $folder . $file ) ) {
  1728.                     $this->log( sprintf( __( 'File "%s" is not readable!', 'backwpup' ), $folder . $file ), E_USER_WARNING );
  1729.                 } else {
  1730.                     $file_size = filesize( $folder . $file );
  1731.                     if ( ! is_int( $file_size ) || $file_size < 0 || $file_size > 2147483647 ) {
  1732.                         $this->log( sprintf( __( 'File size of “%s” cannot be retrieved. File might be too large and will not be added to queue.', 'backwpup' ), $folder . $file . ' ' . $file_size ), E_USER_WARNING );
  1733.                         continue;
  1734.                     }
  1735.                     $files[ ] = $folder . $file;
  1736.                     $this->count_files_in_folder ++;
  1737.                     $this->count_filesize_in_folder = $this->count_filesize_in_folder + $file_size;
  1738.                 }
  1739.             }
  1740.             closedir( $dir );
  1741.         }
  1742.  
  1743.         return $files;
  1744.     }
  1745.  
  1746.     /**
  1747.      * @param create manifest file
  1748.      * @return bool
  1749.      */
  1750.     public function create_manifest( ) {
  1751.  
  1752.         $this->substeps_todo = 3;
  1753.  
  1754.         $this->log( sprintf( __( '%d. Trying to generate a manifest file&#160;&hellip;', 'backwpup' ), $this->steps_data[ $this->step_working ][ 'STEP_TRY' ] ) );
  1755.  
  1756.         //build manifest
  1757.         $manifest = array();
  1758.         // add blog information
  1759.         $manifest[ 'blog_info' ][ 'url' ] = home_url();
  1760.         $manifest[ 'blog_info' ][ 'wpurl' ] = site_url();
  1761.         $manifest[ 'blog_info' ][ 'prefix' ] = $GLOBALS[ 'wpdb' ]->prefix;
  1762.         $manifest[ 'blog_info' ][ 'description' ] = get_option('blogdescription');
  1763.         $manifest[ 'blog_info' ][ 'stylesheet_directory' ] =  get_template_directory_uri();
  1764.         $manifest[ 'blog_info' ][ 'activate_plugins' ] = wp_get_active_and_valid_plugins();
  1765.         $manifest[ 'blog_info' ][ 'activate_theme' ] = wp_get_theme()->get('Name');
  1766.         $manifest[ 'blog_info' ][ 'admin_email' ] = get_option('admin_email');
  1767.         $manifest[ 'blog_info' ][ 'charset' ] = get_bloginfo( 'charset' );
  1768.         $manifest[ 'blog_info' ][ 'version' ] = BackWPup::get_plugin_data( 'wp_version' );
  1769.         $manifest[ 'blog_info' ][ 'backwpup_version' ] = BackWPup::get_plugin_data( 'version' );
  1770.         $manifest[ 'blog_info' ][ 'language' ] = get_bloginfo( 'language' );
  1771.         $manifest[ 'blog_info' ][ 'name' ] = get_bloginfo( 'name' );
  1772.         $manifest[ 'blog_info' ][ 'abspath' ] = ABSPATH;
  1773.         $manifest[ 'blog_info' ][ 'uploads' ] = wp_upload_dir();
  1774.         $manifest[ 'blog_info' ][ 'contents' ][ 'basedir' ] = WP_CONTENT_DIR;
  1775.         $manifest[ 'blog_info' ][ 'contents' ][ 'baseurl' ] = WP_CONTENT_URL;
  1776.         $manifest[ 'blog_info' ][ 'plugins' ][ 'basedir' ] = WP_PLUGIN_DIR;
  1777.         $manifest[ 'blog_info' ][ 'plugins' ][ 'baseurl' ] = WP_PLUGIN_URL;
  1778.         $manifest[ 'blog_info' ][ 'themes' ][ 'basedir' ] = get_theme_root();
  1779.         $manifest[ 'blog_info' ][ 'themes' ][ 'baseurl' ] = get_theme_root_uri();
  1780.         // add job settings
  1781.         $manifest[ 'job_settings' ] = $this->job;
  1782.         // add archive info
  1783.         foreach( $this->additional_files_to_backup as $file ) {
  1784.             $manifest[ 'archive' ][ 'extra_files' ][] = basename( $file );
  1785.         }
  1786.         if ( isset( $this->steps_data[ 'JOB_FILE' ] ) ) {
  1787.             if ( $this->job[ 'backuproot'] )
  1788.                 $manifest[ 'archive' ][ 'abspath' ] = trailingslashit( str_replace( $this->remove_path, '', str_replace( '\\', '/',ABSPATH) ) );
  1789.             if ( $this->job[ 'backupuploads'] )
  1790.                 $manifest[ 'archive' ][ 'uploads' ] = trailingslashit( str_replace( $this->remove_path, '',  BackWPup_File::get_upload_dir() ) );
  1791.             if ( $this->job[ 'backupcontent'] )
  1792.                 $manifest[ 'archive' ][ 'contents' ] = trailingslashit( str_replace( $this->remove_path, '', str_replace( '\\', '/',WP_CONTENT_DIR ) ) );
  1793.             if ( $this->job[ 'backupplugins'])
  1794.                 $manifest[ 'archive' ][ 'plugins' ] = trailingslashit( str_replace( $this->remove_path, '', str_replace( '\\', '/', WP_PLUGIN_DIR ) ) );
  1795.             if ( $this->job[ 'backupthemes'] )
  1796.                 $manifest[ 'archive' ][ 'themes' ] = trailingslashit( str_replace( $this->remove_path, '', str_replace( '\\', '/', get_theme_root() ) ) );
  1797.         }
  1798.  
  1799.         if ( ! file_put_contents( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json', json_encode( $manifest ) ) )
  1800.             return FALSE;
  1801.         $this->substeps_done = 1;
  1802.  
  1803.         //Create backwpup_readme.txt
  1804.         $readme_text  = __( 'You may have noticed the manifest.json file in this archive.', 'backwpup' ) . PHP_EOL;
  1805.         $readme_text .= __( 'manifest.json might be needed for later restoring a backup from this archive.', 'backwpup' ) . PHP_EOL;
  1806.         $readme_text .= __( 'Please leave manifest.json untouched and in place. Otherwise it is safe to be ignored.', 'backwpup' ) . PHP_EOL;
  1807.         if ( ! file_put_contents( BackWPup::get_plugin_data( 'TEMP' ) . 'backwpup_readme.txt', $readme_text ) )
  1808.             return FALSE;
  1809.         $this->substeps_done = 2;
  1810.  
  1811.         //add file to backup files
  1812.         if ( is_readable( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json' ) ) {
  1813.             $this->additional_files_to_backup[ ] = BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json';
  1814.             $this->count_files ++;
  1815.             $this->additional_files_to_backup[ ] = BackWPup::get_plugin_data( 'TEMP' ) . 'backwpup_readme.txt';
  1816.             $this->count_files ++;
  1817.             $this->count_filesize = $this->count_filesize + filesize( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json' );
  1818.             $this->count_filesize = $this->count_filesize + filesize( BackWPup::get_plugin_data( 'TEMP' ) . 'backwpup_readme.txt' );
  1819.             $this->log( sprintf( __( 'Added manifest.json file with %1$s to backup file list.', 'backwpup' ), size_format( filesize( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json' ), 2 ) ) );
  1820.         }
  1821.         $this->substeps_done = 3;
  1822.  
  1823.         return TRUE;
  1824.     }
  1825.  
  1826.     /**
  1827.      * Creates the backup archive
  1828.      */
  1829.     private function create_archive() {
  1830.  
  1831.         //load folders to backup
  1832.         $folders_to_backup = $this->get_folders_to_backup();
  1833.  
  1834.         $this->substeps_todo = $this->count_folder  + 1;
  1835.  
  1836.         //initial settings for restarts in archiving
  1837.         if ( ! isset( $this->steps_data[ $this->step_working ]['on_file'] ) ) {
  1838.             $this->steps_data[ $this->step_working ]['on_file'] = '';
  1839.         }
  1840.         if ( ! isset( $this->steps_data[ $this->step_working ]['on_folder'] ) ) {
  1841.             $this->steps_data[ $this->step_working ]['on_folder'] = '';
  1842.         }
  1843.  
  1844.         if ( $this->steps_data[ $this->step_working ][ 'on_folder' ] == '' && $this->steps_data[ $this->step_working ][ 'on_file' ] == '' && is_file( $this->backup_folder . $this->backup_file ) ) {
  1845.             unlink( $this->backup_folder . $this->backup_file );
  1846.         }
  1847.  
  1848.         if ( $this->steps_data[ $this->step_working ]['SAVE_STEP_TRY'] != $this->steps_data[ $this->step_working ][ 'STEP_TRY' ] )
  1849.             $this->log( sprintf( __( '%d. Trying to create backup archive &hellip;', 'backwpup' ), $this->steps_data[ $this->step_working ][ 'STEP_TRY' ] ), E_USER_NOTICE );
  1850.  
  1851.         try {
  1852.             $backup_archive = new BackWPup_Create_Archive( $this->backup_folder . $this->backup_file );
  1853.  
  1854.             //show method for creation
  1855.             if ( $this->substeps_done == 0 )
  1856.                 $this->log( sprintf( _x( 'Compressing files as %s. Please be patient, this may take a moment.', 'Archive compression method', 'backwpup'), $backup_archive->get_method() ) );
  1857.  
  1858.             //add extra files
  1859.             if ( $this->substeps_done == 0 ) {
  1860.                 if ( ! empty( $this->additional_files_to_backup ) && $this->substeps_done == 0 ) {
  1861.                     foreach ( $this->additional_files_to_backup as $file ) {
  1862.                         if ( $backup_archive->add_file( $file, basename( $file ) ) ) {;
  1863.                             $this->count_files ++;
  1864.                             $this->count_filesize = filesize( $file );
  1865.                             $this->update_working_data();
  1866.                         } else {
  1867.                             $backup_archive->close();
  1868.                             $this->steps_data[ $this->step_working ][ 'on_file' ] = '';
  1869.                             $this->steps_data[ $this->step_working ][ 'on_folder' ] = '';
  1870.                             $this->log( __( 'Cannot create backup archive correctly. Aborting creation.', 'backwpup' ), E_USER_ERROR );
  1871.                             return FALSE;
  1872.                         }
  1873.                     }
  1874.                 }
  1875.                 $this->substeps_done ++;
  1876.             }
  1877.  
  1878.             //add normal files
  1879.             while ( $folder = array_shift( $folders_to_backup ) ) {
  1880.                 //jump over already done folders
  1881.                 if ( in_array( $this->steps_data[ $this->step_working ]['on_folder'], $folders_to_backup ) )
  1882.                     continue;
  1883.                 $this->steps_data[ $this->step_working ]['on_folder'] = $folder;
  1884.                 $files_in_folder = $this->get_files_in_folder( $folder );
  1885.                 //add empty folders
  1886.                 if ( empty( $files_in_folder ) ) {
  1887.                     $folder_name_in_archive = trim( ltrim( str_replace( $this->remove_path, '', $folder ), '/' ) );
  1888.                     if ( ! empty ( $folder_name_in_archive ) )
  1889.                         $backup_archive->add_empty_folder( $folder, $folder_name_in_archive );
  1890.                     continue;
  1891.                 }
  1892.                 //add files
  1893.                 while ( $file = array_shift( $files_in_folder ) ) {
  1894.                     //jump over already done files
  1895.                     if ( in_array( $this->steps_data[ $this->step_working ]['on_file'], $files_in_folder ) )
  1896.                         continue;
  1897.                     $this->steps_data[ $this->step_working ]['on_file'] = $file;
  1898.                     //close archive before restart
  1899.                     $restart_time = $this->get_restart_time();
  1900.                     if ( $restart_time < 0 ) {
  1901.                         unset( $backup_archive );
  1902.                         $this->do_restart_time( TRUE );
  1903.                     }
  1904.                     //generate filename in archive
  1905.                     $in_archive_filename = ltrim( str_replace( $this->remove_path, '', $file ), '/' );
  1906.                     //add file to archive
  1907.                     if ( $backup_archive->add_file( $file, $in_archive_filename ) ) {
  1908.                         $this->update_working_data();
  1909.                     } else {
  1910.                         $backup_archive->close();
  1911.                         $this->steps_data[ $this->step_working ][ 'on_file' ] = '';
  1912.                         $this->steps_data[ $this->step_working ][ 'on_folder' ] = '';
  1913.                         $this->substeps_done   = 0;
  1914.                         $this->backup_filesize = filesize( $this->backup_folder . $this->backup_file );
  1915.                         if ( ( $this->backup_filesize + filesize( $file ) ) >= 2147483647 ) {
  1916.                             $this->log( __( 'Aborting creation.', 'backwpup' ), E_USER_ERROR );
  1917.                             return TRUE;
  1918.                         }
  1919.                         $this->log( __( 'Cannot create backup archive correctly. Aborting creation.', 'backwpup' ), E_USER_ERROR );
  1920.                         return FALSE;
  1921.                     }
  1922.                 }
  1923.                 $this->steps_data[ $this->step_working ]['on_file'] = '';
  1924.                 $this->substeps_done ++;
  1925.             }
  1926.             //restart if needed
  1927.             $restart_time = $this->get_restart_time();
  1928.             if ( $restart_time < 5 ) {
  1929.                 unset( $backup_archive );
  1930.                 $this->do_restart_time( TRUE );
  1931.             }
  1932.             $backup_archive->close();
  1933.             unset( $backup_archive );
  1934.             $this->log( __( 'Backup archive created.', 'backwpup' ), E_USER_NOTICE );
  1935.         } catch ( Exception $e ) {
  1936.             $this->log( $e->getMessage(), E_USER_ERROR, $e->getFile(), $e->getLine() );
  1937.             unset( $backup_archive );
  1938.             return FALSE;
  1939.         }
  1940.  
  1941.         $this->backup_filesize = filesize( $this->backup_folder . $this->backup_file );
  1942.         if ( $this->backup_filesize )
  1943.             $this->log( sprintf( __( 'Archive size is %s.', 'backwpup' ), size_format( $this->backup_filesize, 2 ) ), E_USER_NOTICE );
  1944.         $this->log( sprintf( __( '%1$d Files with %2$s in Archive.', 'backwpup' ), $this->count_files + $this->count_files_in_folder, size_format( $this->count_filesize + $this->count_filesize_in_folder, 2 ) ), E_USER_NOTICE );
  1945.  
  1946.         return TRUE;
  1947.     }
  1948.  
  1949.     /**
  1950.      * @param        $name
  1951.      * @param string $suffix
  1952.      * @param bool   $delete_temp_file
  1953.      * @return string
  1954.      */
  1955.     public function generate_filename( $name, $suffix = '', $delete_temp_file = TRUE ) {
  1956.  
  1957.         $datevars   = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
  1958.         $datevalues = array( date_i18n( 'd' ), date_i18n( 'j' ), date_i18n( 'm' ), date_i18n( 'n' ), date_i18n( 'Y' ), date_i18n( 'y' ), date_i18n( 'a' ), date_i18n( 'A' ), date_i18n( 'B' ), date_i18n( 'g' ), date_i18n( 'G' ), date_i18n( 'h' ), date_i18n( 'H' ), date_i18n( 'i' ), date_i18n( 's' ) );
  1959.  
  1960.         if ( ! empty( $suffix ) && substr( $suffix, 0, 1 ) != '.' )
  1961.             $suffix = '.' . $suffix;
  1962.  
  1963.         $name = str_replace( $datevars, $datevalues, $name );
  1964.         $name = sanitize_file_name( $name ) . $suffix; //prevent _ in extension name that sanitize_file_name add.
  1965.         if ( $delete_temp_file && is_writeable( BackWPup::get_plugin_data( 'TEMP' ) . $name ) && !is_dir( BackWPup::get_plugin_data( 'TEMP' ) . $name ) && !is_link( BackWPup::get_plugin_data( 'TEMP' ) . $name ) )
  1966.             unlink( BackWPup::get_plugin_data( 'TEMP' ) . $name );
  1967.  
  1968.         return $name;
  1969.     }
  1970.  
  1971.     /**
  1972.      * @param $filename
  1973.      * @return bool
  1974.      */
  1975.     public function is_backup_archive( $filename ) {
  1976.  
  1977.         $filename  = basename( $filename );
  1978.  
  1979.         if ( ! substr( $filename, -3 ) == '.gz' ||  ! substr( $filename, -4 ) == '.bz2' ||  ! substr( $filename, -4 ) == '.tar' ||  ! substr( $filename, -4 ) == '.zip' )
  1980.             return FALSE;
  1981.  
  1982.         $filename = str_replace( array( '.gz', '.bz2', '.tar', '.zip' ), '', $filename );
  1983.  
  1984.         $datevars  = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
  1985.         $dateregex = array( '(0[1-9]|[12][0-9]|3[01])', '([1-9]|[12][0-9]|3[01])', '(0[1-9]|1[012])', '([1-9]|1[012])', '((19|20|21)[0-9]{2})', '([0-9]{2})', '(am|pm)', '(AM|PM)', '([0-9]{3})', '([1-9]|1[012])', '([0-9]|1[0-9]|2[0-3])', '(0[1-9]|1[012])', '(0[0-9]|1[0-9]|2[0-3])', '([0-5][0-9])', '([0-5][0-9])' );
  1986.  
  1987.         $regex = "/^" . str_replace( $datevars, $dateregex, str_replace( "\/", "/", sanitize_file_name( $this->job[ 'archivename' ] ) ) ) . "$/";
  1988.  
  1989.         preg_match( $regex, $filename, $matches );
  1990.         if ( ! empty( $matches[ 0 ] ) && $matches[ 0 ] == $filename )
  1991.             return TRUE;
  1992.  
  1993.         return FALSE;
  1994.     }
  1995.  
  1996.     /**
  1997.      * Get the Process id of working script
  1998.      *
  1999.      * @return int
  2000.      */
  2001.     private static function get_pid( ) {
  2002.  
  2003.         if  ( function_exists( 'posix_getpid' ) ) {
  2004.  
  2005.             return posix_getpid();
  2006.         } elseif ( function_exists( 'getmypid' ) ) {
  2007.  
  2008.             return getmypid();
  2009.         }
  2010.  
  2011.         return -1;
  2012.     }
  2013.  
  2014.     /**
  2015.      * For storing and getting data in/from a extra temp file
  2016.      *
  2017.      * @param   string $storage The name of the storage
  2018.      * @param   array  $data data to save in storage
  2019.      * @return  array|mixed|null data from storage
  2020.      */
  2021.     public function data_storage( $storage = NULL, $data = NULL ) {
  2022.  
  2023.         if ( empty( $storage ) )
  2024.             return $data;
  2025.  
  2026.         $storage = strtolower( $storage );
  2027.  
  2028.         $file = BackWPup::get_plugin_data( 'temp' ) . 'backwpup-' . BackWPup::get_plugin_data( 'hash' ) . '-'.$storage.'.json';
  2029.  
  2030.         if ( ! empty( $data ) ) {
  2031.             file_put_contents( $file, json_encode( $data ) );
  2032.         }
  2033.         elseif ( is_readable( $file ) ) {
  2034.             $json = file_get_contents( $file );
  2035.             $data = json_decode( $json, TRUE );
  2036.         }
  2037.  
  2038.         return $data;
  2039.     }
  2040.  
  2041.     /**
  2042.      * Get list of Folder for backup
  2043.      *
  2044.      * @return array folder list
  2045.      */
  2046.     public function get_folders_to_backup( ) {
  2047.  
  2048.         $file = BackWPup::get_plugin_data( 'temp' ) . 'backwpup-' . BackWPup::get_plugin_data( 'hash' ) . '-folder.php';
  2049.  
  2050.         if ( ! file_exists( $file ) )
  2051.             return array();
  2052.  
  2053.         $folders = array();
  2054.  
  2055.         $file_data = file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
  2056.  
  2057.         foreach( $file_data as $folder ) {
  2058.             $folder = trim( str_replace( array( '<?php', '//' ), '', $folder ) );
  2059.             if ( ! empty( $folder ) && is_dir( $folder ) )
  2060.                 $folders[] = $folder;
  2061.         }
  2062.         $folders = array_unique( $folders );
  2063.         sort( $folders );
  2064.         $this->count_folder = count( $folders );
  2065.  
  2066.         return $folders;
  2067.     }
  2068.  
  2069.  
  2070.     /**
  2071.      * Add a Folders to Folder list that should be backup
  2072.      *
  2073.      * @param array $folders folder to add
  2074.      * @param bool  $new overwrite existing file
  2075.      */
  2076.     public function add_folders_to_backup( $folders = array(), $new = FALSE ) {
  2077.  
  2078.         if ( ! is_array( $folders ) )
  2079.             $folders = (array) $folders;
  2080.  
  2081.         $file = BackWPup::get_plugin_data( 'temp' ) . 'backwpup-' . BackWPup::get_plugin_data( 'hash' ) . '-folder.php';
  2082.  
  2083.         if ( ! file_exists( $file ) || $new )
  2084.             file_put_contents( $file, '<?php' . PHP_EOL );
  2085.  
  2086.         $content = '';
  2087.         foreach ( $folders AS $folder ) {
  2088.             $content .= '//' . $folder . PHP_EOL;
  2089.         }
  2090.  
  2091.         if ( ! empty( $content ) )
  2092.             file_put_contents( $file, $content, FILE_APPEND );
  2093.     }
  2094.  
  2095.     /**
  2096.      * Check whether exec has been disabled.
  2097.      *
  2098.      * @access public
  2099.      * @static
  2100.      * @return bool
  2101.      */
  2102.     public static function is_exec() {
  2103.  
  2104.         // Is function avail
  2105.         if ( ! function_exists( 'exec' ) ) {
  2106.             return FALSE;
  2107.         }
  2108.  
  2109.         // Is shell_exec disabled?
  2110.         if ( in_array( 'exec', array_map( 'trim', explode( ',', @ini_get( 'disable_functions' ) ) ) ) ) {
  2111.             return FALSE;
  2112.         }
  2113.  
  2114.         // Can we issue a simple echo command?
  2115.         $output = exec( 'echo backwpupechotest' );
  2116.         if ( $output != 'backwpupechotest' ) {
  2117.             return FALSE;
  2118.         }
  2119.  
  2120.         return TRUE;
  2121.  
  2122.     }
  2123.  
  2124.     /**
  2125.      * Cleanup Temp Folder
  2126.      */
  2127.     public static function clean_temp_folder() {
  2128.  
  2129.         $temp_dir = BackWPup::get_plugin_data( 'TEMP' );
  2130.         $do_not_delete_files = array( '.htaccess', 'index.php', '.', '..', '.donotbackup' );
  2131.  
  2132.         if ( $dir = opendir( $temp_dir ) ) {
  2133.             while ( FALSE !== ( $file = readdir( $dir ) ) ) {
  2134.                 if ( in_array( $file, $do_not_delete_files ) || is_dir( $temp_dir . $file ) || is_link( $temp_dir . $file ) )
  2135.                     continue;
  2136.                 if ( is_writeable( $temp_dir . $file ) )
  2137.                     unlink( $temp_dir . $file );
  2138.             }
  2139.             closedir( $dir );
  2140.         }
  2141.     }
  2142. }
Add Comment
Please, Sign In to add comment