BackWPup – WordPress Backup Plugin - Version 1.2.0

Version Description

  • Backup file size now in log file
  • Paged Logs Table
  • added Backup Archives Page
  • Grammar fixes
  • Bug fixes
Download this release

Release Info

Developer danielhuesken
Plugin Icon 128x128 BackWPup – WordPress Backup Plugin
Version 1.2.0
Comparing to
See all releases

Code changes from version 1.1.1 to 1.2.0

app/backwpup_dojob.php CHANGED
@@ -1,23 +1,23 @@
1
  <?php
2
- // don't load directly
3
- if ( !defined('ABSPATH') )
4
  die('-1');
5
 
6
-
7
- //function for PHP error handling
8
  function backwpup_joberrorhandler($errno, $errstr, $errfile, $errline) {
9
  global $backwpup_logfile;
10
-
11
  //genrate timestamp
12
  if (!function_exists('memory_get_usage')) { // test if memory functions compiled in
13
  $timestamp="<span style=\"background-color:c3c3c3;\" title=\"[Line: ".$errline."|File: ".basename($errfile)."\">".date_i18n('Y-m-d H:i.s').":</span> ";
14
  } else {
15
  if (version_compare(phpversion(), '5.2.0', '<'))
16
  $timestamp="<span style=\"background-color:c3c3c3;\" title=\"[Line: ".$errline."|File: ".basename($errfile)."|Mem: ".backwpup_formatBytes(@memory_get_usage())."|Mem Max: ".backwpup_formatBytes(@memory_get_peak_usage())."|Mem Limit: ".ini_get('memory_limit')."]\">".date_i18n('Y-m-d H:i.s').":</span> ";
17
- else
18
  $timestamp="<span style=\"background-color:c3c3c3;\" title=\"[Line: ".$errline."|File: ".basename($errfile)."|Mem: ".backwpup_formatBytes(@memory_get_usage(true))."|Mem Max: ".backwpup_formatBytes(@memory_get_peak_usage(true))."|Mem Limit: ".ini_get('memory_limit')."]\">".date_i18n('Y-m-d H:i.s').":</span> ";
19
  }
20
-
21
  switch ($errno) {
22
  case E_NOTICE:
23
  case E_USER_NOTICE:
@@ -36,7 +36,7 @@ function backwpup_joberrorhandler($errno, $errstr, $errfile, $errline) {
36
  break;
37
  case E_DEPRECATED:
38
  case E_USER_DEPRECATED:
39
- $massage=$timestamp."<span>".__('[DEPRECATED]','backwpup')." ".$errstr."</span>";
40
  break;
41
  case E_STRICT:
42
  $massage=$timestamp."<span>".__('[STRICT NOTICE]','backwpup')." ".$errstr."</span>";
@@ -48,20 +48,20 @@ function backwpup_joberrorhandler($errno, $errstr, $errfile, $errline) {
48
  $massage=$timestamp."<span>[".$errno."] ".$errstr."</span>";
49
  break;
50
  }
51
-
52
  if (!empty($massage)) {
53
  //wirte log file
54
  $fd=@fopen($backwpup_logfile,"a+");
55
  @fputs($fd,$massage."<br />\n");
56
  @fclose($fd);
57
-
58
- //output on run now
59
  if (!defined('DOING_CRON')) {
60
  echo $massage."<script type=\"text/javascript\">window.scrollBy(0, 15);</script><br />\n";
61
  @flush();
62
  @ob_flush();
63
  }
64
-
65
  //write new log header
66
  if (isset($errors) or isset($warnings)) {
67
  $fd=@fopen($backwpup_logfile,"r+");
@@ -81,10 +81,10 @@ function backwpup_joberrorhandler($errno, $errstr, $errfile, $errline) {
81
  }
82
  @fclose($fd);
83
  }
84
-
85
  if ($errno==E_ERROR or $errno==E_CORE_ERROR or $errno==E_COMPILE_ERROR) //Die on fatal php errors.
86
  die();
87
-
88
 
89
  @set_time_limit(300); //300 is most webserver time limit. 0= max time! Give script 5 min. more to work.
90
  //true for no more php error hadling.
@@ -100,29 +100,29 @@ function backwpup_jobshutdown() {
100
  $logheader=backwpup_read_logheader($backwpup_logfile); //read waring count from log header
101
  $cfg=get_option('backwpup'); //load config
102
  $jobs=get_option('backwpup_jobs'); //load job options
103
-
104
  if (!empty($jobs[$logheader['jobid']]['stoptime'])) //abort if job exits normaly
105
  return;
106
-
107
- backwpup_joberrorhandler(E_USER_WARNING, __('Job shutdown function is working! Please delete temp Backupfiles by hand.','backwpup'), __FILE__, __LINE__);
108
-
109
  //try to get last error
110
  $lasterror=error_get_last();
111
  backwpup_joberrorhandler($lasterror['type'], __('Last ERROR:','backwpup').' '.$lasterror['message'], $lasterror['file'], $lasterror['line']);
112
-
113
  //set Temp Dir
114
  $tempdir=trailingslashit($cfg['dirtemp']);
115
- if ($tempdir=='/')
116
  $tempdir=backwpup_get_upload_dir();
117
-
118
  if (is_file($tempdir.DB_NAME.'.sql') ) { //delete sql temp file
119
  unlink($tempdir.DB_NAME.'.sql');
120
  }
121
-
122
  if (is_file($tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml') ) { //delete WP XML Export temp file
123
  unlink($tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml');
124
  }
125
-
126
  $jobs[$logheader['jobid']]['stoptime']=current_time('timestamp');
127
  $jobs[$logheader['jobid']]['lastrun']=$jobs[$logheader['jobid']]['starttime'];
128
  $jobs[$logheader['jobid']]['lastruntime']=$jobs[$logheader['jobid']]['stoptime']-$jobs[$logheader['jobid']]['starttime'];
@@ -155,12 +155,12 @@ function backwpup_jobshutdown() {
155
  if ($sendmail) {
156
  $mailbody=__("Jobname:","backwpup")." ".$logdata['name']."\n";
157
  $mailbody.=__("Jobtype:","backwpup")." ".$logdata['type']."\n";
158
- if (!empty($logdata['errors']))
159
  $mailbody.=__("Errors:","backwpup")." ".$logdata['errors']."\n";
160
  if (!empty($logdata['warnings']))
161
  $mailbody.=__("Warnings:","backwpup")." ".$logdata['warnings']."\n";
162
  wp_mail($jobs[$logheader['jobid']]['mailaddresslog'],__('BackWPup Log File from','backwpup').' '.date_i18n('Y-m-d H:i',$jobs[$logheader['jobid']]['starttime']).': '.$jobs[$logheader['jobid']]['name'] ,$mailbody,'',array($backwpup_logfile));
163
- }
164
  }
165
 
166
  /**
@@ -168,7 +168,7 @@ function backwpup_jobshutdown() {
168
  *
169
  */
170
  class backwpup_dojob {
171
-
172
  private $jobid=0;
173
  private $filelist=array();
174
  private $tempfilelist=array();
@@ -182,7 +182,7 @@ class backwpup_dojob {
182
  private $tempdir='';
183
  private $cfg=array();
184
  private $job=array();
185
-
186
  public function __construct($jobid) {
187
  global $backwpup_logfile,$backwpup_dojob;
188
  @ini_get('safe_mode','Off'); //disable safe mode
@@ -204,7 +204,7 @@ class backwpup_dojob {
204
  $this->backupfileformat=$this->job['fileformart'];
205
  //set Temp Dir
206
  $this->tempdir=trailingslashit($this->cfg['dirtemp']);
207
- if (empty($this->tempdir) or $this->tempdir=='/')
208
  $this->tempdir=backwpup_get_upload_dir();
209
  //set Backup Dir
210
  $this->backupdir=$this->job['backupdir'];
@@ -217,10 +217,10 @@ class backwpup_dojob {
217
  $this->logdir=str_replace('\\','/',trailingslashit(WP_CONTENT_DIR)).'backwpup-'.$rand.'-logs/';
218
  }
219
  //set Backup file name only for jos that makes backups
220
- if (in_array('FILE',$this->todo) or in_array('DB',$this->todo) or in_array('WPEXP',$this->todo))
221
  $this->backupfile='backwpup_'.$this->jobid.'_'.date_i18n('Y-m-d_H-i-s').$this->backupfileformat;
222
  //set Log file name
223
- $this->logfile='backwpup_log_'.date_i18n('Y-m-d_H-i-s').'.html';
224
  $backwpup_logfile=$this->logdir.$this->logfile;
225
  //Create log file
226
  if (!$this->_check_folders($this->logdir))
@@ -234,15 +234,16 @@ class backwpup_dojob {
234
  @fputs($fd,"<meta name=\"backwpup_jobid\" content=\"".$this->jobid."\" />\n");
235
  @fputs($fd,"<meta name=\"backwpup_jobname\" content=\"".$this->job['name']."\" />\n");
236
  @fputs($fd,"<meta name=\"backwpup_jobtype\" content=\"".$this->job['type']."\" />\n");
237
- if (!empty($this->backupfile) and $this->backupdir!=$this->tempdir)
238
- @fputs($fd,"<meta name=\"backwpup_backupfile\" content=\"".$this->backupdir.$this->backupfile."\" />\n");
 
239
  @fputs($fd,str_pad("<meta name=\"backwpup_jobruntime\" content=\"0\" />",100)."\n");
240
  @fputs($fd,"<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>\n</head>\n<body style=\"font-family:monospace;font-size:12px;white-space:nowrap;\">\n");
241
  @fclose($fd);
242
  //set function for PHP user defineid error handling
243
  if (defined(WP_DEBUG) and WP_DEBUG)
244
  set_error_handler('backwpup_joberrorhandler',E_ALL | E_STRICT);
245
- else
246
  set_error_handler('backwpup_joberrorhandler',E_ALL & ~E_NOTICE);
247
  //set a schutdown function.
248
  register_shutdown_function('backwpup_jobshutdown');
@@ -252,12 +253,12 @@ class backwpup_dojob {
252
  return false;
253
  }
254
  //check max script execution tme
255
- if (ini_get('safe_mode') or strtolower(ini_get('safe_mode'))=='on' or ini_get('safe_mode')=='1')
256
  trigger_error(sprintf(__('PHP Safe Mode is on!!! Max exec time is %1$d sec.','backwpup'),ini_get('max_execution_time')),E_USER_WARNING);
257
  // check function for memorylimit
258
  if (!function_exists('memory_get_usage')) {
259
  ini_set('memory_limit', apply_filters( 'admin_memory_limit', '256M' )); //Wordpress default
260
- trigger_error(sprintf(__('Memory limit set to %1$s ,because can not use PHP: memory_get_usage() function to dynamicly increase the Memeory!','backwpup'),ini_get('memory_limit')),E_USER_WARNING);
261
  }
262
  //run job parts
263
  foreach($this->todo as $key => $value) {
@@ -280,13 +281,13 @@ class backwpup_dojob {
280
  elseif ($this->backupfileformat==".tar.gz" or $this->backupfileformat==".tar.bz2" or $this->backupfileformat==".tar")
281
  $this->tar_pack_files();
282
  }
283
- if (file_exists($this->backupdir.$this->backupfile)) { // Put backup file to destination
284
  $this->destination_mail();
285
  $this->destination_ftp();
286
  $this->destination_s3();
287
  $this->destination_dir();
288
  }
289
-
290
  foreach($this->todo as $key => $value) {
291
  switch ($value) {
292
  case 'CHECK':
@@ -296,9 +297,9 @@ class backwpup_dojob {
296
  $this->optimize_db();
297
  break;
298
  }
299
- }
300
- }
301
-
302
  private function _check_folders($folder) {
303
  if (!is_dir($folder)) { //create dir if not exists
304
  if (!mkdir($folder,0777,true)) {
@@ -307,8 +308,8 @@ class backwpup_dojob {
307
  }
308
  }
309
  if (!is_writeable($folder)) { //test if folder wirteable
310
- trigger_error(sprintf(__('Can not write to Folder: %1$s','backwpup'),$folder),E_USER_ERROR);
311
- return false;
312
  }
313
  //create .htaccess for apache and index.html for other
314
  if (strtolower(substr($_SERVER["SERVER_SOFTWARE"],0,6))=="apache") { //check if it a apache webserver
@@ -323,18 +324,18 @@ class backwpup_dojob {
323
  if($file = fopen($folder.'index.html', 'w')) {
324
  fwrite($file,"\n");
325
  fclose($file);
326
- }
327
  }
328
  if (!is_file($folder.'index.php')) {
329
  if($file = fopen($folder.'index.php', 'w')) {
330
  fwrite($file,"\n");
331
  fclose($file);
332
- }
333
  }
334
  }
335
  return true;
336
  }
337
-
338
  private function need_free_memory($memneed) {
339
  //fail back if fuction not exist
340
  if (!function_exists('memory_get_usage'))
@@ -344,7 +345,7 @@ class backwpup_dojob {
344
  trigger_error(sprintf(__('PHP Safe Mode is on!!! Can not increase Memory Limit is %1$s','backwpup'),ini_get('memory_limit')),E_USER_WARNING);
345
  return false;
346
  }
347
-
348
  //calc mem to bytes
349
  if (strtoupper(substr(trim(ini_get('memory_limit')),-1))=='K')
350
  $memory=trim(substr(ini_get('memory_limit'),0,-1))*1024;
@@ -354,73 +355,73 @@ class backwpup_dojob {
354
  $memory=trim(substr(ini_get('memory_limit'),0,-1))*1024*1024*1024;
355
  else
356
  $memory=trim(ini_get('memory_limit'));
357
-
358
  //use real memory at php version 5.2.0
359
  if (version_compare(phpversion(), '5.2.0', '<'))
360
  $memnow=memory_get_usage();
361
- else
362
  $memnow=memory_get_usage(true);
363
-
364
  //need memory
365
  $needmemory=$memnow+$memneed;
366
-
367
- // increase Memory
368
- if ($needmemory>$memory) {
369
  $newmemory=round($needmemory/1024/1024)+1;
370
- if ($oldmem=ini_set('memory_limit', $newmemory.'M'))
371
  trigger_error(sprintf(__('Memory increased from %1$s to %2$s','backwpup'),$oldmem,ini_get('memory_limit')),E_USER_NOTICE);
372
- else
373
  trigger_error(sprintf(__('Can not increase Memory Limit is %1$s','backwpup'),ini_get('memory_limit')),E_USER_WARNING);
374
  }
375
- return true;
376
  }
377
-
378
  private function maintenance_mode($enable = false) {
379
  if (!$this->job['maintenance'])
380
  return;
381
-
382
  if ( $enable ) {
383
  trigger_error(__('Set Blog to Maintenance Mode','backwpup'),E_USER_NOTICE);
384
  if ( class_exists('WPMaintenanceMode') ) { //Support for WP Maintenance Mode Plugin
385
- update_option('wp-maintenance-mode-msqld','1');
386
  } elseif ( class_exists('MaintenanceMode') ) { //Support for Maintenance Mode Plugin
387
  $mamo=get_option('plugin_maintenance-mode');
388
  $mamo['mamo_activate']='on_'.current_time('timestamp');
389
  $mamo['mamo_backtime_days']='0';
390
  $mamo['mamo_backtime_hours']='0';
391
  $mamo['mamo_backtime_mins']='5';
392
- update_option('plugin_maintenance-mode',$mamo);
393
  } else { //WP Support
394
  $fdmain=fopen(trailingslashit(ABSPATH).'.maintenance','w');
395
  fputs($fdmain,'<?php $upgrading = ' . time() . '; ?>');
396
- fclose($fdmain);
397
  }
398
  } else {
399
  trigger_error(__('Set Blog to normal Mode','backwpup'),E_USER_NOTICE);
400
  if ( class_exists('WPMaintenanceMode') ) { //Support for WP Maintenance Mode Plugin
401
- update_option('wp-maintenance-mode-msqld','0');
402
  } elseif ( class_exists('MaintenanceMode') ) { //Support for Maintenance Mode Plugin
403
  $mamo=get_option('plugin_maintenance-mode');
404
  $mamo['mamo_activate']='off';
405
- update_option('plugin_maintenance-mode',$mamo);
406
  } else { //WP Support
407
  @unlink(trailingslashit(ABSPATH).'.maintenance');
408
  }
409
  }
410
  }
411
-
412
  private function check_db() {
413
  global $wpdb;
414
-
415
  trigger_error(__('Run Database check...','backwpup'),E_USER_NOTICE);
416
-
417
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
418
  //exclude tables from check
419
  foreach($tables as $tablekey => $tablevalue) {
420
  if (in_array($tablevalue,$this->job['dbexclude']))
421
  unset($tables[$tablekey]);
422
  }
423
-
424
  //check tables
425
  if (sizeof($tables)>0) {
426
  $this->maintenance_mode(true);
@@ -431,8 +432,8 @@ class backwpup_dojob {
431
  elseif ($check['Msg_type']=='warning')
432
  trigger_error(sprintf(__('Result of table check for %1$s is: %2$s','backwpup'), $table, $check['Msg_text']),E_USER_WARNING);
433
  else
434
- trigger_error(sprintf(__('Result of table check for %1$s is: %2$s','backwpup'), $table, $check['Msg_text']),E_USER_NOTICE);
435
-
436
  if ($sqlerr=mysql_error($wpdb->dbh)) //aditional SQL error
437
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, $sqlerr->last_query),E_USER_ERROR);
438
  //Try to Repair tabele
@@ -443,8 +444,8 @@ class backwpup_dojob {
443
  elseif ($repair['Msg_type']=='warning')
444
  trigger_error(sprintf(__('Result of table repair for %1$s is: %2$s','backwpup'), $table, $repair['Msg_text']),E_USER_WARNING);
445
  else
446
- trigger_error(sprintf(__('Result of table repair for %1$s is: %2$s','backwpup'), $table, $repair['Msg_text']),E_USER_NOTICE);
447
-
448
  if ($sqlerr=mysql_error($wpdb->dbh)) //aditional SQL error
449
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, $sqlerr->last_query),E_USER_ERROR);
450
  }
@@ -454,7 +455,7 @@ class backwpup_dojob {
454
  trigger_error(__('Database check done!','backwpup'),E_USER_NOTICE);
455
  } else {
456
  trigger_error(__('No Tables to check','backwpup'),E_USER_WARNING);
457
- }
458
  }
459
 
460
  private function dump_db_table($table,$status,$file) {
@@ -464,7 +465,7 @@ class backwpup_dojob {
464
  fwrite($file, "--\n");
465
  fwrite($file, "-- Table structure for table $table\n");
466
  fwrite($file, "--\n\n");
467
- fwrite($file, "DROP TABLE IF EXISTS `" . $table . "`;\n");
468
  fwrite($file, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n");
469
  fwrite($file, "/*!40101 SET character_set_client = '".mysql_client_encoding()."' */;\n");
470
  //Dump the table structure
@@ -476,14 +477,14 @@ class backwpup_dojob {
476
  $tablestruc=mysql_fetch_assoc($result);
477
  fwrite($file, $tablestruc['Create Table'].";\n");
478
  fwrite($file, "/*!40101 SET character_set_client = @saved_cs_client */;\n");
479
-
480
  //take data of table
481
  $result=mysql_query("SELECT * FROM `".$table."`");
482
  if (!$result) {
483
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), mysql_error(), "SELECT * FROM `".$table."`"),E_USER_ERROR);
484
  return false;
485
  }
486
-
487
  fwrite($file, "--\n");
488
  fwrite($file, "-- Dumping data for table $table\n");
489
  fwrite($file, "--\n\n");
@@ -491,7 +492,7 @@ class backwpup_dojob {
491
  if ($status['Engine']=='MyISAM')
492
  fwrite($file, "/*!40000 ALTER TABLE `".$table."` DISABLE KEYS */;\n");
493
 
494
-
495
  while ($data = mysql_fetch_assoc($result)) {
496
  $keys = array();
497
  $values = array();
@@ -522,22 +523,22 @@ class backwpup_dojob {
522
  global $wpdb;
523
  trigger_error(__('Run Database Dump to file...','backwpup'),E_USER_NOTICE);
524
  $this->maintenance_mode(true);
525
-
526
- //Tables to backup
527
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
528
- if ($sqlerr=mysql_error($wpdb->dbh))
529
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, "SHOW TABLES FROM `'.DB_NAME.'`"),E_USER_ERROR);
530
-
531
  foreach($tables as $tablekey => $tablevalue) {
532
  if (in_array($tablevalue,$this->job['dbexclude']))
533
  unset($tables[$tablekey]);
534
  }
535
  sort($tables);
536
-
537
 
538
  if (sizeof($tables)>0) {
539
  $result=$wpdb->get_results("SHOW TABLE STATUS FROM `".DB_NAME."`;", ARRAY_A); //get table status
540
- if ($sqlerr=mysql_error($wpdb->dbh))
541
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, "SHOW TABLE STATUS FROM `".DB_NAME."`;"),E_USER_ERROR);
542
  foreach($result as $statusdata) {
543
  $status[$statusdata['Name']]=$statusdata;
@@ -549,9 +550,9 @@ class backwpup_dojob {
549
  fwrite($file, "-- Plugin for WordPress by Daniel Huesken\n");
550
  fwrite($file, "-- http://danielhuesken.de/portfolio/backwpup/\n");
551
  fwrite($file, "-- Blog Name: ".get_option('blogname')."\n");
552
- if (defined('WP_SITEURL'))
553
  fwrite($file, "-- Blog URL: ".trailingslashit(WP_SITEURL)."\n");
554
- else
555
  fwrite($file, "-- Blog URL: ".trailingslashit(get_option('siteurl'))."\n");
556
  fwrite($file, "-- Blog ABSPATH: ".trailingslashit(ABSPATH)."\n");
557
  fwrite($file, "-- Table Prefix: ".$wpdb->prefix."\n");
@@ -598,9 +599,11 @@ class backwpup_dojob {
598
  trigger_error(__('Add Database Dump to Backup:','backwpup').' '.DB_NAME.'.sql '.backwpup_formatBytes(filesize($this->tempdir.DB_NAME.'.sql')),E_USER_NOTICE);
599
  $this->allfilesize+=filesize($this->tempdir.DB_NAME.'.sql');
600
  $this->filelist[]=array(79001=>$this->tempdir.DB_NAME.'.sql',79003=>DB_NAME.'.sql');
601
-
602
  $this->maintenance_mode(false);
603
- }
 
 
604
 
605
  private function export_wp() {
606
  trigger_error(__('Run Wordpress Export to XML file...','backwpup'),E_USER_NOTICE);
@@ -613,20 +616,20 @@ class backwpup_dojob {
613
  } else {
614
  trigger_error(__('Can not Export to XML!','backwpup'),E_USER_ERROR);
615
  }
616
- }
617
 
618
  private function optimize_db() {
619
  global $wpdb;
620
-
621
  trigger_error(__('Run Database optimize...','backwpup'),E_USER_NOTICE);
622
-
623
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
624
  //exclude tables from optimize
625
  foreach($tables as $tablekey => $tablevalue) {
626
  if (in_array($tablevalue,$this->job['dbexclude']))
627
  unset($tables[$tablekey]);
628
  }
629
-
630
  if (sizeof($tables)>0) {
631
  $this->maintenance_mode(true);
632
  foreach ($tables as $table) {
@@ -636,9 +639,9 @@ class backwpup_dojob {
636
  elseif ($optimize['Msg_type']=='warning')
637
  trigger_error(sprintf(__('Result of table optimize for %1$s is: %2$s','backwpup'), $table, $optimize['Msg_text']),E_USER_WARNING);
638
  else
639
- trigger_error(sprintf(__('Result of table optimize for %1$s is: %2$s','backwpup'), $table, $optimize['Msg_text']),E_USER_NOTICE);
640
-
641
- if ($sqlerr=mysql_error($wpdb->dbh))
642
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, $sqlerr->last_query),E_USER_ERROR);
643
  }
644
  $wpdb->flush();
@@ -646,7 +649,7 @@ class backwpup_dojob {
646
  $this->maintenance_mode(false);
647
  } else {
648
  trigger_error(__('No Tables to optimize','backwpup'),E_USER_WARNING);
649
- }
650
  }
651
 
652
  private function _file_list_folder( $folder = '', $levels = 100, $excludes,$excludedirs=array()) {
@@ -677,41 +680,41 @@ class backwpup_dojob {
677
  }
678
  }
679
  @closedir( $dir );
680
- }
681
  }
682
-
683
  private function file_list() {
684
 
685
  //Make filelist
686
  trigger_error(__('Make a list of files to Backup ....','backwpup'),E_USER_NOTICE);
687
-
688
  $this->tempfilelist=array();
689
-
690
  $backwpup_exclude=explode(',',trim($this->job['fileexclude']));
691
  //Exclude Temp Files
692
  $backwpup_exclude[]=$this->tempdir.DB_NAME.'.sql';
693
  $backwpup_exclude[]=$this->tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml';
694
  $backwpup_exclude=array_unique($backwpup_exclude,SORT_STRING);
695
-
696
  //File list for blog folders
697
  if ($this->job['backuproot'])
698
- $this->_file_list_folder(untrailingslashit(str_replace('\\','/',ABSPATH)),100,$backwpup_exclude,array_merge($this->job['backuprootexcludedirs'],backwpup_get_exclude_wp_dirs(ABSPATH)));
699
  if ($this->job['backupcontent'])
700
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',WP_CONTENT_DIR)),100,$backwpup_exclude,array_merge($this->job['backupcontentexcludedirs'],backwpup_get_exclude_wp_dirs(WP_CONTENT_DIR)));
701
  if ($this->job['backupplugins'])
702
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',WP_PLUGIN_DIR)),100,$backwpup_exclude,array_merge($this->job['backuppluginsexcludedirs'],backwpup_get_exclude_wp_dirs(WP_PLUGIN_DIR)));
703
- if ($this->job['backupthemes'])
704
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',trailingslashit(WP_CONTENT_DIR).'themes')),100,$backwpup_exclude,array_merge($this->job['backupthemesexcludedirs'],backwpup_get_exclude_wp_dirs(trailingslashit(WP_CONTENT_DIR).'themes')));
705
  if ($this->job['backupuploads'])
706
  $this->_file_list_folder(untrailingslashit(backwpup_get_upload_dir()),100,$backwpup_exclude,array_merge($this->job['backupuploadsexcludedirs'],backwpup_get_exclude_wp_dirs(backwpup_get_upload_dir())));
707
-
708
- //include dirs
709
  $dirinclude=explode(',',$this->job['dirinclude']);
710
  $dirinclude=array_unique($dirinclude,SORT_STRING);
711
  //Crate file list
712
  if (is_array($dirinclude)) {
713
  foreach($dirinclude as $dirincludevalue) {
714
- if (is_dir($dirincludevalue))
715
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',$dirincludevalue)),100,$backwpup_exclude);
716
  }
717
  }
@@ -722,22 +725,22 @@ class backwpup_dojob {
722
  $this->filelist[]=array(79001=>$files,79003=>str_replace(str_replace('\\','/',trailingslashit(ABSPATH)),'',$files));
723
  }
724
  $this->tempfilelist=array();
725
-
726
  if (!is_array($this->filelist[0])) {
727
  trigger_error(__('No files to Backup','backwpup'),E_USER_ERROR);
728
  } else {
729
  trigger_error(__('Size off all files:','backwpup').' '.backwpup_formatBytes($this->allfilesize),E_USER_NOTICE);
730
  }
731
-
732
- }
733
 
734
  private function zip_files() {
735
-
736
  if (class_exists('ZipArchive')) { //use php zip lib
737
  trigger_error(__('Create Backup Zip file...','backwpup'),E_USER_NOTICE);
738
  $zip = new ZipArchive;
739
  if ($res=$zip->open($this->backupdir.$this->backupfile,ZIPARCHIVE::CREATE) === TRUE) {
740
- foreach($this->filelist as $key => $files) {
741
  if (!is_file($files[79001])) //check file exists
742
  continue;
743
  if ($zip->addFile($files[79001], $files[79003])) {
@@ -751,31 +754,31 @@ class backwpup_dojob {
751
  } else {
752
  trigger_error(__('Can not create Backup ZIP file:','backwpup').' '.$res,E_USER_ERROR);
753
  }
754
-
755
  } else { //use PclZip
756
  define( 'PCLZIP_TEMPORARY_DIR', $this->tempdir );
757
- if (!class_exists('PclZip'))
758
  require_once (plugin_dir_path(__FILE__).'libs/pclzip.lib.php');
759
-
760
  //Create Zip File
761
  if (is_array($this->filelist[0])) {
762
  $this->need_free_memory(10485760); //10MB free memory for zip
763
  trigger_error(__('Create Backup Zip (PclZip) file...','backwpup'),E_USER_NOTICE);
764
  foreach($this->filelist as $key => $files) {
765
  trigger_error(__('Add File to ZIP file:','backwpup').' '.$files[79001].' '.backwpup_formatBytes(filesize($files[79001])),E_USER_NOTICE);
766
- }
767
  $zipbackupfile = new PclZip($this->backupdir.$this->backupfile);
768
  if (0==$zipbackupfile -> create($this->filelist,PCLZIP_OPT_ADD_TEMP_FILE_ON)) {
769
  trigger_error(__('Zip file create:','backwpup').' '.$zipbackupfile->errorInfo(true),E_USER_ERROR);
770
- } else {
771
  trigger_error(__('Backup Zip file create done!','backwpup'),E_USER_NOTICE);
772
  }
773
  }
774
  }
775
  }
776
-
777
  private function tar_pack_files() {
778
-
779
  if ($this->backupfileformat=='.tar.gz') {
780
  $tarbackup=gzopen($this->backupdir.$this->backupfile,'w9');
781
  } elseif ($this->backupfileformat=='.tar.bz2') {
@@ -783,23 +786,23 @@ class backwpup_dojob {
783
  } else {
784
  $tarbackup=fopen($this->backupdir.$this->backupfile,'w');
785
  }
786
-
787
  if (!$tarbackup) {
788
  trigger_error(__('Can not create TAR Backup file','backwpup'),E_USER_ERROR);
789
  return;
790
  } else {
791
  trigger_error(__('Create Backup Archive file...','backwpup'),E_USER_NOTICE);
792
  }
793
-
794
  $this->need_free_memory(1048576); //1MB free memory for zip
795
-
796
  foreach($this->filelist as $key => $files) {
797
  trigger_error(__('Add File to Backup Archive:','backwpup').' '.$files[79001].' '.backwpup_formatBytes(filesize($files[79001])),E_USER_NOTICE);
798
-
799
  //check file exists
800
  if (!is_file($files[79001]))
801
  continue;
802
-
803
  // Get file information
804
  $file_information = stat($files[79001]);
805
 
@@ -822,15 +825,15 @@ class backwpup_dojob {
822
  "", //device minor number 8
823
  substr($files[79003],101), //prefix for file name 155
824
  ""); //fill block 512K
825
-
826
  // Computes the unsigned Checksum of a file's header
827
  $checksum = 0;
828
  for ($i = 0; $i < 512; $i++)
829
  $checksum += ord(substr($header, $i, 1));
830
  $checksum = pack("a8", sprintf("%07o", $checksum));
831
-
832
  $header = substr_replace($header, $checksum, 148, 8);
833
-
834
  if ($this->backupfileformat=='.tar.gz') {
835
  gzwrite($tarbackup, $header);
836
  } elseif ($this->backupfileformat=='.tar.bz2') {
@@ -838,7 +841,7 @@ class backwpup_dojob {
838
  } else {
839
  fwrite($tarbackup, $header);
840
  }
841
-
842
  // read/write files in 512K Blocks
843
  $fd=fopen($files[79001],'rb');
844
  while(!feof($fd)) {
@@ -855,23 +858,23 @@ class backwpup_dojob {
855
  }
856
  fclose($fd);
857
  }
858
-
859
-
860
  if ($this->backupfileformat=='.tar.gz') {
861
  gzwrite($tarbackup, pack("a1024", "")); // Add 1024 bytes of NULLs to designate EOF
862
- gzclose($tarbackup);
863
  } elseif ($this->backupfileformat=='.tar.bz2') {
864
  bzwrite($tarbackup, pack("a1024", "")); // Add 1024 bytes of NULLs to designate EOF
865
  bzclose($tarbackup);
866
  } else {
867
  fwrite($tarbackup, pack("a1024", "")); // Add 1024 bytes of NULLs to designate EOF
868
- fclose($tarbackup);
869
  }
870
-
871
  trigger_error(__('Backup Archive file create done!','backwpup'),E_USER_NOTICE);
872
  }
873
-
874
-
875
  private function _ftp_raw_helper($ftp_conn_id,$command) { //FTP Comands helper function
876
  $return=ftp_raw($ftp_conn_id,$command);
877
  if (strtoupper(substr(trim($command),0,4))=="PASS") {
@@ -899,13 +902,13 @@ class backwpup_dojob {
899
  }
900
  }
901
  }
902
-
903
-
904
  private function destination_ftp() {
905
-
906
- if (empty($this->job['ftphost']) or empty($this->job['ftpuser']) or empty($this->job['ftppass']))
907
  return false;
908
-
909
  $ftpport=21;
910
  $ftphost=$this->job['ftphost'];
911
  if (false !== strpos($this->job['ftphost'],':')) //look for port
@@ -913,17 +916,15 @@ class backwpup_dojob {
913
 
914
  if (function_exists('ftp_ssl_connect')) { //make SSL FTP connection
915
  $ftp_conn_id = ftp_ssl_connect($ftphost,$ftpport,10);
916
- if ($ftp_conn_id) {
917
  trigger_error(__('Connected by SSL to FTP server:','backwpup').' '.$this->job['ftphost'],E_USER_NOTICE);
918
- }
919
  }
920
  if (!$ftp_conn_id) { //make normal FTP conection if SSL not work
921
  $ftp_conn_id = ftp_connect($ftphost,$ftpport,10);
922
- if ($ftp_conn_id) {
923
  trigger_error(__('Connected insecure to FTP server:','backwpup').' '.$this->job['ftphost'],E_USER_NOTICE);
924
- }
925
  }
926
-
927
  if (!$ftp_conn_id) {
928
  trigger_error(__('Can not connect to FTP server:','backwpup').' '.$this->job['ftphost'],E_USER_ERROR);
929
  return false;
@@ -941,45 +942,45 @@ class backwpup_dojob {
941
  }
942
  }
943
  }
944
-
945
  //if (ftp_login($ftp_conn_id, $jobs[$jobid]['ftpuser'], $jobs[$jobid]['ftppass'])) {
946
- if (!$loginok)
947
  return false;
948
-
949
  //SYSTYPE
950
  $this->_ftp_raw_helper($ftp_conn_id,'SYST');
951
  //PASV
952
  trigger_error(__('FTP Client command:','backwpup').' PASV',E_USER_NOTICE);
953
  if (ftp_pasv($ftp_conn_id, true))
954
  trigger_error(__('Server Completion reply: 227 Entering Passive Mode','backwpup'),E_USER_NOTICE);
955
- else
956
  trigger_error(__('FTP Server reply:','backwpup').' '.__('Can not Entering Passive Mode','backwpup'),E_USER_WARNING);
957
  //ALLO show no erros in log if do not work
958
  trigger_error(__('FTP Client command:','backwpup').' ALLO',E_USER_NOTICE);
959
  ftp_alloc($ftp_conn_id,filesize($this->backupdir.$this->backupfile),$result);
960
  trigger_error(__('FTP Server reply:','backwpup').' '.$result,E_USER_NOTICE);
961
-
962
  //test ftp dir and create it f not exists
963
  $ftpdirs=explode("/", untrailingslashit($this->job['ftpdir']));
964
  foreach ($ftpdirs as $ftpdir) {
965
  if (empty($ftpdir))
966
  continue;
967
  if (!@ftp_chdir($ftp_conn_id, $ftpdir)) {
968
- trigger_error('"'.$ftpdir.'" '.__('FTP Dir on Server not exists!','backwpup'),E_USER_WARNING);
969
  if (@ftp_mkdir($ftp_conn_id, $ftpdir)) {
970
- trigger_error('"'.$ftpdir.'" '.__('FTP Dir created!','backwpup'),E_USER_NOTICE);
971
  ftp_chdir($ftp_conn_id, $ftpdir);
972
  } else {
973
- trigger_error('"'.$ftpdir.'" '.__('FTP Dir on Server can not created!','backwpup'),E_USER_ERROR);
974
  }
975
  }
976
  }
977
-
978
  if (ftp_put($ftp_conn_id, $this->job['ftpdir'].$this->backupfile, $this->backupdir.$this->backupfile, FTP_BINARY)) //transfere file
979
  trigger_error(__('Backup File transferred to FTP Server:','backwpup').' '.$this->job['ftpdir'].$this->backupfile,E_USER_NOTICE);
980
  else
981
  trigger_error(__('Can not transfer backup to FTP server.','backwpup'),E_USER_ERROR);
982
-
983
  if ($this->job['ftpmaxbackups']>0) { //Delete old backups
984
  $backupfilelist=array();
985
  if ($filelist=ftp_nlist($ftp_conn_id, $this->job['ftpdir'])) {
@@ -993,7 +994,7 @@ class backwpup_dojob {
993
  for ($i=$this->job['ftpmaxbackups'];$i<sizeof($backupfilelist);$i++) {
994
  if (ftp_delete($ftp_conn_id, $this->job['ftpdir'].$backupfilelist[$i])) //delte files on ftp
995
  $numdeltefiles++;
996
- else
997
  trigger_error(__('Can not delete file on FTP Server:','backwpup').' '.$this->job['ftpdir'].$backupfilelist[$i],E_USER_ERROR);
998
  }
999
  if ($numdeltefiles>0)
@@ -1001,16 +1002,16 @@ class backwpup_dojob {
1001
  }
1002
  }
1003
  }
1004
- ftp_close($ftp_conn_id);
1005
 
1006
- }
1007
 
1008
  private function destination_mail() {
1009
  if (empty($this->job['mailaddress']))
1010
  return false;
1011
-
1012
- trigger_error(__('Prepare Sending backupfile with mail...','backwpup'),E_USER_NOTICE);
1013
-
1014
  //Crate PHP Mailer
1015
  require_once(ABSPATH.WPINC.'/class-phpmailer.php');
1016
  require_once(ABSPATH.WPINC.'/class-smtp.php');
@@ -1038,16 +1039,16 @@ class backwpup_dojob {
1038
  $phpmailer->IsMail();
1039
  trigger_error(__('Send mail with PHP mail','backwpup'),E_USER_NOTICE);
1040
  }
1041
-
1042
 
1043
  trigger_error(__('Creating mail','backwpup'),E_USER_NOTICE);
1044
  $phpmailer->From = $this->cfg['mailsndemail'];
1045
  $phpmailer->FromName = $this->cfg['mailsndname'];
1046
- $phpmailer->AddAddress($this->job['mailaddress']);
1047
  $phpmailer->Subject = __('BackWPup File from','backwpup').' '.date_i18n('Y-m-d H:i',$this->job['starttime']).': '.$this->job['name'];
1048
  $phpmailer->IsHTML(false);
1049
  $phpmailer->Body = 'Backup File';
1050
-
1051
  //check file Size
1052
  if (!empty($this->job['mailefilesize'])) {
1053
  $maxfilezise=abs($this->job['mailefilesize']*1024*1024);
@@ -1056,23 +1057,23 @@ class backwpup_dojob {
1056
  return false;
1057
  }
1058
  }
1059
-
1060
  trigger_error(__('Adding Attachment to mail','backwpup'),E_USER_NOTICE);
1061
  $this->need_free_memory(filesize($this->backupdir.$this->backupfile)*5);
1062
- $phpmailer->AddAttachment($this->backupdir.$this->backupfile);
1063
-
1064
  trigger_error(__('Send mail....','backwpup'),E_USER_NOTICE);
1065
  if (false == $phpmailer->Send()) {
1066
  trigger_error(__('Can not send mail:','backwpup').' '.$phpmailer->ErrorInfo,E_USER_ERROR);
1067
  } else {
1068
  trigger_error(__('Mail send!!!','backwpup'),E_USER_NOTICE);
1069
- }
1070
-
1071
  }
1072
 
1073
  private function destination_s3() {
1074
-
1075
- if (empty($this->job['awsAccessKey']) or empty($this->job['awsSecretKey']) or empty($this->job['awsBucket']))
1076
  return false;
1077
 
1078
  if (!(extension_loaded('curl') or @dl(PHP_SHLIB_SUFFIX == 'so' ? 'curl.so' : 'php_curl.dll'))) {
@@ -1080,9 +1081,9 @@ class backwpup_dojob {
1080
  return false;
1081
  }
1082
 
1083
- if (!class_exists('S3'))
1084
  require_once(plugin_dir_path(__FILE__).'libs/S3.php');
1085
-
1086
  $s3 = new S3($this->job['awsAccessKey'], $this->job['awsSecretKey'], $this->job['awsSSL']);
1087
 
1088
  if (in_array($this->job['awsBucket'],$s3->listBuckets())) {
@@ -1092,7 +1093,7 @@ class backwpup_dojob {
1092
  trigger_error(__('Backup File transferred to S3://','backwpup').$this->job['awsBucket'].'/'.$this->job['awsdir'].$this->backupfile,E_USER_NOTICE);
1093
  else
1094
  trigger_error(__('Can not transfer backup to S3.','backwpup'),E_USER_ERROR);
1095
-
1096
  if ($this->job['awsmaxbackups']>0) { //Delete old backups
1097
  $backupfilelist=array();
1098
  if (($contents = $s3->getBucket($this->job['awsBucket'],$this->job['awsdir'])) !== false) {
@@ -1110,7 +1111,7 @@ class backwpup_dojob {
1110
  for ($i=$this->job['awsmaxbackups'];$i<sizeof($backupfilelist);$i++) {
1111
  if ($s3->deleteObject($this->job['awsBucket'], $this->job['awsdir'].$backupfilelist[$i])) //delte files on S3
1112
  $numdeltefiles++;
1113
- else
1114
  trigger_error(__('Can not delete file on S3//:','backwpup').$this->job['awsBucket'].'/'.$this->job['awsdir'].$backupfilelist[$i],E_USER_ERROR);
1115
  }
1116
  if ($numdeltefiles>0)
@@ -1128,7 +1129,7 @@ class backwpup_dojob {
1128
  //Delete old Backupfiles
1129
  $backupfilelist=array();
1130
  if (!empty($this->job['maxbackups'])) {
1131
- if ( $dir = @opendir($this->job['backupdir']) ) { //make file list
1132
  while (($file = readdir($dir)) !== false ) {
1133
  if ('backwpup_'.$this->jobid.'_' == substr($file,0,strlen('backwpup_'.$this->jobid.'_')) and $this->backupfileformat == substr($file,-strlen($this->backupfileformat)))
1134
  $backupfilelist[]=$file;
@@ -1147,29 +1148,33 @@ class backwpup_dojob {
1147
  }
1148
  }
1149
  }
1150
-
1151
  public function __destruct() {
1152
  global $backwpup_logfile;
1153
-
1154
  if (is_file($this->backupdir.$this->backupfile)) {
1155
- trigger_error(sprintf(__('Backup Archive File size is %1s','backwpup'),backwpup_formatBytes(filesize($this->backupdir.$this->backupfile))),E_USER_NOTICE);
 
1156
  }
1157
 
 
 
 
1158
  if (is_file($this->tempdir.DB_NAME.'.sql') ) { //delete sql temp file
1159
  unlink($this->tempdir.DB_NAME.'.sql');
1160
  }
1161
-
1162
  if (is_file($this->tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml') ) { //delete WP XML Export temp file
1163
  unlink($this->tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml');
1164
  }
1165
-
1166
  if (empty($this->job['backupdir']) and is_file($this->backupdir.$this->backupfile)) { //delete backup file in temp dir
1167
  unlink($this->backupdir.$this->backupfile);
1168
  }
1169
-
1170
  //delete old logs
1171
  if (!empty($this->cfg['maxlogs'])) {
1172
- if ( $dir = @opendir($this->logdir) ) { //make file list
1173
  while (($file = readdir($dir)) !== false ) {
1174
  if ('backwpup_log_' == substr($file,0,strlen('backwpup_log_')) and ".html" == substr($file,-5))
1175
  $logfilelist[]=$file;
@@ -1186,8 +1191,8 @@ class backwpup_dojob {
1186
  if ($numdeltefiles>0)
1187
  trigger_error($numdeltefiles.' '.__('old Log files deleted!!!','backwpup'),E_USER_NOTICE);
1188
  }
1189
- }
1190
-
1191
  $jobs=get_option('backwpup_jobs');
1192
  $jobs[$this->jobid]['stoptime']=current_time('timestamp');
1193
  $jobs[$this->jobid]['lastrun']=$jobs[$this->jobid]['starttime'];
@@ -1197,13 +1202,21 @@ class backwpup_dojob {
1197
 
1198
  //write runtime header
1199
  $fd=@fopen($backwpup_logfile,"r+");
 
1200
  while (!feof($fd)) {
1201
  $line=@fgets($fd);
1202
  if (stripos($line,"<meta name=\"backwpup_jobruntime\"") !== false) {
1203
  @fseek($fd,$filepos);
1204
  @fputs($fd,str_pad("<meta name=\"backwpup_jobruntime\" content=\"".$jobs[$this->jobid]['lastruntime']."\" />",100)."\n");
1205
- break;
 
 
 
 
 
1206
  }
 
 
1207
  $filepos=ftell($fd);
1208
  }
1209
  @fclose($fd);
@@ -1222,7 +1235,7 @@ class backwpup_dojob {
1222
  if ($sendmail) {
1223
  $mailbody=__("Jobname:","backwpup")." ".$logdata['name']."\n";
1224
  $mailbody.=__("Jobtype:","backwpup")." ".$logdata['type']."\n";
1225
- if (!empty($logdata['errors']))
1226
  $mailbody.=__("Errors:","backwpup")." ".$logdata['errors']."\n";
1227
  if (!empty($logdata['warnings']))
1228
  $mailbody.=__("Warnings:","backwpup")." ".$logdata['warnings']."\n";
1
  <?php
2
+ // don't load directly
3
+ if ( !defined('ABSPATH') )
4
  die('-1');
5
 
6
+
7
+ //function for PHP error handling
8
  function backwpup_joberrorhandler($errno, $errstr, $errfile, $errline) {
9
  global $backwpup_logfile;
10
+
11
  //genrate timestamp
12
  if (!function_exists('memory_get_usage')) { // test if memory functions compiled in
13
  $timestamp="<span style=\"background-color:c3c3c3;\" title=\"[Line: ".$errline."|File: ".basename($errfile)."\">".date_i18n('Y-m-d H:i.s').":</span> ";
14
  } else {
15
  if (version_compare(phpversion(), '5.2.0', '<'))
16
  $timestamp="<span style=\"background-color:c3c3c3;\" title=\"[Line: ".$errline."|File: ".basename($errfile)."|Mem: ".backwpup_formatBytes(@memory_get_usage())."|Mem Max: ".backwpup_formatBytes(@memory_get_peak_usage())."|Mem Limit: ".ini_get('memory_limit')."]\">".date_i18n('Y-m-d H:i.s').":</span> ";
17
+ else
18
  $timestamp="<span style=\"background-color:c3c3c3;\" title=\"[Line: ".$errline."|File: ".basename($errfile)."|Mem: ".backwpup_formatBytes(@memory_get_usage(true))."|Mem Max: ".backwpup_formatBytes(@memory_get_peak_usage(true))."|Mem Limit: ".ini_get('memory_limit')."]\">".date_i18n('Y-m-d H:i.s').":</span> ";
19
  }
20
+
21
  switch ($errno) {
22
  case E_NOTICE:
23
  case E_USER_NOTICE:
36
  break;
37
  case E_DEPRECATED:
38
  case E_USER_DEPRECATED:
39
+ $massage=$timestamp."<span>".__('[DEPRECATED]','backwpup')." ".$errstr."</span>";
40
  break;
41
  case E_STRICT:
42
  $massage=$timestamp."<span>".__('[STRICT NOTICE]','backwpup')." ".$errstr."</span>";
48
  $massage=$timestamp."<span>[".$errno."] ".$errstr."</span>";
49
  break;
50
  }
51
+
52
  if (!empty($massage)) {
53
  //wirte log file
54
  $fd=@fopen($backwpup_logfile,"a+");
55
  @fputs($fd,$massage."<br />\n");
56
  @fclose($fd);
57
+
58
+ //output on run now
59
  if (!defined('DOING_CRON')) {
60
  echo $massage."<script type=\"text/javascript\">window.scrollBy(0, 15);</script><br />\n";
61
  @flush();
62
  @ob_flush();
63
  }
64
+
65
  //write new log header
66
  if (isset($errors) or isset($warnings)) {
67
  $fd=@fopen($backwpup_logfile,"r+");
81
  }
82
  @fclose($fd);
83
  }
84
+
85
  if ($errno==E_ERROR or $errno==E_CORE_ERROR or $errno==E_COMPILE_ERROR) //Die on fatal php errors.
86
  die();
87
+
88
 
89
  @set_time_limit(300); //300 is most webserver time limit. 0= max time! Give script 5 min. more to work.
90
  //true for no more php error hadling.
100
  $logheader=backwpup_read_logheader($backwpup_logfile); //read waring count from log header
101
  $cfg=get_option('backwpup'); //load config
102
  $jobs=get_option('backwpup_jobs'); //load job options
103
+
104
  if (!empty($jobs[$logheader['jobid']]['stoptime'])) //abort if job exits normaly
105
  return;
106
+
107
+ backwpup_joberrorhandler(E_USER_WARNING, __('Job shutdown function is working! Please delete temp Backup files by hand.','backwpup'), __FILE__, __LINE__);
108
+
109
  //try to get last error
110
  $lasterror=error_get_last();
111
  backwpup_joberrorhandler($lasterror['type'], __('Last ERROR:','backwpup').' '.$lasterror['message'], $lasterror['file'], $lasterror['line']);
112
+
113
  //set Temp Dir
114
  $tempdir=trailingslashit($cfg['dirtemp']);
115
+ if ($tempdir=='/')
116
  $tempdir=backwpup_get_upload_dir();
117
+
118
  if (is_file($tempdir.DB_NAME.'.sql') ) { //delete sql temp file
119
  unlink($tempdir.DB_NAME.'.sql');
120
  }
121
+
122
  if (is_file($tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml') ) { //delete WP XML Export temp file
123
  unlink($tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml');
124
  }
125
+
126
  $jobs[$logheader['jobid']]['stoptime']=current_time('timestamp');
127
  $jobs[$logheader['jobid']]['lastrun']=$jobs[$logheader['jobid']]['starttime'];
128
  $jobs[$logheader['jobid']]['lastruntime']=$jobs[$logheader['jobid']]['stoptime']-$jobs[$logheader['jobid']]['starttime'];
155
  if ($sendmail) {
156
  $mailbody=__("Jobname:","backwpup")." ".$logdata['name']."\n";
157
  $mailbody.=__("Jobtype:","backwpup")." ".$logdata['type']."\n";
158
+ if (!empty($logdata['errors']))
159
  $mailbody.=__("Errors:","backwpup")." ".$logdata['errors']."\n";
160
  if (!empty($logdata['warnings']))
161
  $mailbody.=__("Warnings:","backwpup")." ".$logdata['warnings']."\n";
162
  wp_mail($jobs[$logheader['jobid']]['mailaddresslog'],__('BackWPup Log File from','backwpup').' '.date_i18n('Y-m-d H:i',$jobs[$logheader['jobid']]['starttime']).': '.$jobs[$logheader['jobid']]['name'] ,$mailbody,'',array($backwpup_logfile));
163
+ }
164
  }
165
 
166
  /**
168
  *
169
  */
170
  class backwpup_dojob {
171
+
172
  private $jobid=0;
173
  private $filelist=array();
174
  private $tempfilelist=array();
182
  private $tempdir='';
183
  private $cfg=array();
184
  private $job=array();
185
+
186
  public function __construct($jobid) {
187
  global $backwpup_logfile,$backwpup_dojob;
188
  @ini_get('safe_mode','Off'); //disable safe mode
204
  $this->backupfileformat=$this->job['fileformart'];
205
  //set Temp Dir
206
  $this->tempdir=trailingslashit($this->cfg['dirtemp']);
207
+ if (empty($this->tempdir) or $this->tempdir=='/')
208
  $this->tempdir=backwpup_get_upload_dir();
209
  //set Backup Dir
210
  $this->backupdir=$this->job['backupdir'];
217
  $this->logdir=str_replace('\\','/',trailingslashit(WP_CONTENT_DIR)).'backwpup-'.$rand.'-logs/';
218
  }
219
  //set Backup file name only for jos that makes backups
220
+ if (in_array('FILE',$this->todo) or in_array('DB',$this->todo) or in_array('WPEXP',$this->todo))
221
  $this->backupfile='backwpup_'.$this->jobid.'_'.date_i18n('Y-m-d_H-i-s').$this->backupfileformat;
222
  //set Log file name
223
+ $this->logfile='backwpup_log_'.date_i18n('Y-m-d_H-i-s').'.html';
224
  $backwpup_logfile=$this->logdir.$this->logfile;
225
  //Create log file
226
  if (!$this->_check_folders($this->logdir))
234
  @fputs($fd,"<meta name=\"backwpup_jobid\" content=\"".$this->jobid."\" />\n");
235
  @fputs($fd,"<meta name=\"backwpup_jobname\" content=\"".$this->job['name']."\" />\n");
236
  @fputs($fd,"<meta name=\"backwpup_jobtype\" content=\"".$this->job['type']."\" />\n");
237
+ if (!empty($this->backupfile))
238
+ @fputs($fd,"<meta name=\"backwpup_backupfile\" content=\"".$this->backupfile."\" />\n");
239
+ @fputs($fd,str_pad("<meta name=\"backwpup_backupfilesize\" content=\"0\" />",100)."\n");
240
  @fputs($fd,str_pad("<meta name=\"backwpup_jobruntime\" content=\"0\" />",100)."\n");
241
  @fputs($fd,"<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>\n</head>\n<body style=\"font-family:monospace;font-size:12px;white-space:nowrap;\">\n");
242
  @fclose($fd);
243
  //set function for PHP user defineid error handling
244
  if (defined(WP_DEBUG) and WP_DEBUG)
245
  set_error_handler('backwpup_joberrorhandler',E_ALL | E_STRICT);
246
+ else
247
  set_error_handler('backwpup_joberrorhandler',E_ALL & ~E_NOTICE);
248
  //set a schutdown function.
249
  register_shutdown_function('backwpup_jobshutdown');
253
  return false;
254
  }
255
  //check max script execution tme
256
+ if (ini_get('safe_mode') or strtolower(ini_get('safe_mode'))=='on' or ini_get('safe_mode')=='1')
257
  trigger_error(sprintf(__('PHP Safe Mode is on!!! Max exec time is %1$d sec.','backwpup'),ini_get('max_execution_time')),E_USER_WARNING);
258
  // check function for memorylimit
259
  if (!function_exists('memory_get_usage')) {
260
  ini_set('memory_limit', apply_filters( 'admin_memory_limit', '256M' )); //Wordpress default
261
+ trigger_error(sprintf(__('Memory limit set to %1$s ,because can not use PHP: memory_get_usage() function to dynamically increase the Memory!','backwpup'),ini_get('memory_limit')),E_USER_WARNING);
262
  }
263
  //run job parts
264
  foreach($this->todo as $key => $value) {
281
  elseif ($this->backupfileformat==".tar.gz" or $this->backupfileformat==".tar.bz2" or $this->backupfileformat==".tar")
282
  $this->tar_pack_files();
283
  }
284
+ if (is_file($this->backupdir.$this->backupfile)) { // Put backup file to destination
285
  $this->destination_mail();
286
  $this->destination_ftp();
287
  $this->destination_s3();
288
  $this->destination_dir();
289
  }
290
+
291
  foreach($this->todo as $key => $value) {
292
  switch ($value) {
293
  case 'CHECK':
297
  $this->optimize_db();
298
  break;
299
  }
300
+ }
301
+ }
302
+
303
  private function _check_folders($folder) {
304
  if (!is_dir($folder)) { //create dir if not exists
305
  if (!mkdir($folder,0777,true)) {
308
  }
309
  }
310
  if (!is_writeable($folder)) { //test if folder wirteable
311
+ trigger_error(sprintf(__('Can not write to Folder: %1$s','backwpup'),$folder),E_USER_ERROR);
312
+ return false;
313
  }
314
  //create .htaccess for apache and index.html for other
315
  if (strtolower(substr($_SERVER["SERVER_SOFTWARE"],0,6))=="apache") { //check if it a apache webserver
324
  if($file = fopen($folder.'index.html', 'w')) {
325
  fwrite($file,"\n");
326
  fclose($file);
327
+ }
328
  }
329
  if (!is_file($folder.'index.php')) {
330
  if($file = fopen($folder.'index.php', 'w')) {
331
  fwrite($file,"\n");
332
  fclose($file);
333
+ }
334
  }
335
  }
336
  return true;
337
  }
338
+
339
  private function need_free_memory($memneed) {
340
  //fail back if fuction not exist
341
  if (!function_exists('memory_get_usage'))
345
  trigger_error(sprintf(__('PHP Safe Mode is on!!! Can not increase Memory Limit is %1$s','backwpup'),ini_get('memory_limit')),E_USER_WARNING);
346
  return false;
347
  }
348
+
349
  //calc mem to bytes
350
  if (strtoupper(substr(trim(ini_get('memory_limit')),-1))=='K')
351
  $memory=trim(substr(ini_get('memory_limit'),0,-1))*1024;
355
  $memory=trim(substr(ini_get('memory_limit'),0,-1))*1024*1024*1024;
356
  else
357
  $memory=trim(ini_get('memory_limit'));
358
+
359
  //use real memory at php version 5.2.0
360
  if (version_compare(phpversion(), '5.2.0', '<'))
361
  $memnow=memory_get_usage();
362
+ else
363
  $memnow=memory_get_usage(true);
364
+
365
  //need memory
366
  $needmemory=$memnow+$memneed;
367
+
368
+ // increase Memory
369
+ if ($needmemory>$memory) {
370
  $newmemory=round($needmemory/1024/1024)+1;
371
+ if ($oldmem=ini_set('memory_limit', $newmemory.'M'))
372
  trigger_error(sprintf(__('Memory increased from %1$s to %2$s','backwpup'),$oldmem,ini_get('memory_limit')),E_USER_NOTICE);
373
+ else
374
  trigger_error(sprintf(__('Can not increase Memory Limit is %1$s','backwpup'),ini_get('memory_limit')),E_USER_WARNING);
375
  }
376
+ return true;
377
  }
378
+
379
  private function maintenance_mode($enable = false) {
380
  if (!$this->job['maintenance'])
381
  return;
382
+
383
  if ( $enable ) {
384
  trigger_error(__('Set Blog to Maintenance Mode','backwpup'),E_USER_NOTICE);
385
  if ( class_exists('WPMaintenanceMode') ) { //Support for WP Maintenance Mode Plugin
386
+ update_option('wp-maintenance-mode-msqld','1');
387
  } elseif ( class_exists('MaintenanceMode') ) { //Support for Maintenance Mode Plugin
388
  $mamo=get_option('plugin_maintenance-mode');
389
  $mamo['mamo_activate']='on_'.current_time('timestamp');
390
  $mamo['mamo_backtime_days']='0';
391
  $mamo['mamo_backtime_hours']='0';
392
  $mamo['mamo_backtime_mins']='5';
393
+ update_option('plugin_maintenance-mode',$mamo);
394
  } else { //WP Support
395
  $fdmain=fopen(trailingslashit(ABSPATH).'.maintenance','w');
396
  fputs($fdmain,'<?php $upgrading = ' . time() . '; ?>');
397
+ fclose($fdmain);
398
  }
399
  } else {
400
  trigger_error(__('Set Blog to normal Mode','backwpup'),E_USER_NOTICE);
401
  if ( class_exists('WPMaintenanceMode') ) { //Support for WP Maintenance Mode Plugin
402
+ update_option('wp-maintenance-mode-msqld','0');
403
  } elseif ( class_exists('MaintenanceMode') ) { //Support for Maintenance Mode Plugin
404
  $mamo=get_option('plugin_maintenance-mode');
405
  $mamo['mamo_activate']='off';
406
+ update_option('plugin_maintenance-mode',$mamo);
407
  } else { //WP Support
408
  @unlink(trailingslashit(ABSPATH).'.maintenance');
409
  }
410
  }
411
  }
412
+
413
  private function check_db() {
414
  global $wpdb;
415
+
416
  trigger_error(__('Run Database check...','backwpup'),E_USER_NOTICE);
417
+
418
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
419
  //exclude tables from check
420
  foreach($tables as $tablekey => $tablevalue) {
421
  if (in_array($tablevalue,$this->job['dbexclude']))
422
  unset($tables[$tablekey]);
423
  }
424
+
425
  //check tables
426
  if (sizeof($tables)>0) {
427
  $this->maintenance_mode(true);
432
  elseif ($check['Msg_type']=='warning')
433
  trigger_error(sprintf(__('Result of table check for %1$s is: %2$s','backwpup'), $table, $check['Msg_text']),E_USER_WARNING);
434
  else
435
+ trigger_error(sprintf(__('Result of table check for %1$s is: %2$s','backwpup'), $table, $check['Msg_text']),E_USER_NOTICE);
436
+
437
  if ($sqlerr=mysql_error($wpdb->dbh)) //aditional SQL error
438
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, $sqlerr->last_query),E_USER_ERROR);
439
  //Try to Repair tabele
444
  elseif ($repair['Msg_type']=='warning')
445
  trigger_error(sprintf(__('Result of table repair for %1$s is: %2$s','backwpup'), $table, $repair['Msg_text']),E_USER_WARNING);
446
  else
447
+ trigger_error(sprintf(__('Result of table repair for %1$s is: %2$s','backwpup'), $table, $repair['Msg_text']),E_USER_NOTICE);
448
+
449
  if ($sqlerr=mysql_error($wpdb->dbh)) //aditional SQL error
450
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, $sqlerr->last_query),E_USER_ERROR);
451
  }
455
  trigger_error(__('Database check done!','backwpup'),E_USER_NOTICE);
456
  } else {
457
  trigger_error(__('No Tables to check','backwpup'),E_USER_WARNING);
458
+ }
459
  }
460
 
461
  private function dump_db_table($table,$status,$file) {
465
  fwrite($file, "--\n");
466
  fwrite($file, "-- Table structure for table $table\n");
467
  fwrite($file, "--\n\n");
468
+ fwrite($file, "DROP TABLE IF EXISTS `" . $table . "`;\n");
469
  fwrite($file, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n");
470
  fwrite($file, "/*!40101 SET character_set_client = '".mysql_client_encoding()."' */;\n");
471
  //Dump the table structure
477
  $tablestruc=mysql_fetch_assoc($result);
478
  fwrite($file, $tablestruc['Create Table'].";\n");
479
  fwrite($file, "/*!40101 SET character_set_client = @saved_cs_client */;\n");
480
+
481
  //take data of table
482
  $result=mysql_query("SELECT * FROM `".$table."`");
483
  if (!$result) {
484
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), mysql_error(), "SELECT * FROM `".$table."`"),E_USER_ERROR);
485
  return false;
486
  }
487
+
488
  fwrite($file, "--\n");
489
  fwrite($file, "-- Dumping data for table $table\n");
490
  fwrite($file, "--\n\n");
492
  if ($status['Engine']=='MyISAM')
493
  fwrite($file, "/*!40000 ALTER TABLE `".$table."` DISABLE KEYS */;\n");
494
 
495
+
496
  while ($data = mysql_fetch_assoc($result)) {
497
  $keys = array();
498
  $values = array();
523
  global $wpdb;
524
  trigger_error(__('Run Database Dump to file...','backwpup'),E_USER_NOTICE);
525
  $this->maintenance_mode(true);
526
+
527
+ //Tables to backup
528
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
529
+ if ($sqlerr=mysql_error($wpdb->dbh))
530
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, "SHOW TABLES FROM `'.DB_NAME.'`"),E_USER_ERROR);
531
+
532
  foreach($tables as $tablekey => $tablevalue) {
533
  if (in_array($tablevalue,$this->job['dbexclude']))
534
  unset($tables[$tablekey]);
535
  }
536
  sort($tables);
537
+
538
 
539
  if (sizeof($tables)>0) {
540
  $result=$wpdb->get_results("SHOW TABLE STATUS FROM `".DB_NAME."`;", ARRAY_A); //get table status
541
+ if ($sqlerr=mysql_error($wpdb->dbh))
542
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, "SHOW TABLE STATUS FROM `".DB_NAME."`;"),E_USER_ERROR);
543
  foreach($result as $statusdata) {
544
  $status[$statusdata['Name']]=$statusdata;
550
  fwrite($file, "-- Plugin for WordPress by Daniel Huesken\n");
551
  fwrite($file, "-- http://danielhuesken.de/portfolio/backwpup/\n");
552
  fwrite($file, "-- Blog Name: ".get_option('blogname')."\n");
553
+ if (defined('WP_SITEURL'))
554
  fwrite($file, "-- Blog URL: ".trailingslashit(WP_SITEURL)."\n");
555
+ else
556
  fwrite($file, "-- Blog URL: ".trailingslashit(get_option('siteurl'))."\n");
557
  fwrite($file, "-- Blog ABSPATH: ".trailingslashit(ABSPATH)."\n");
558
  fwrite($file, "-- Table Prefix: ".$wpdb->prefix."\n");
599
  trigger_error(__('Add Database Dump to Backup:','backwpup').' '.DB_NAME.'.sql '.backwpup_formatBytes(filesize($this->tempdir.DB_NAME.'.sql')),E_USER_NOTICE);
600
  $this->allfilesize+=filesize($this->tempdir.DB_NAME.'.sql');
601
  $this->filelist[]=array(79001=>$this->tempdir.DB_NAME.'.sql',79003=>DB_NAME.'.sql');
602
+
603
  $this->maintenance_mode(false);
604
+ }
605
+
606
+
607
 
608
  private function export_wp() {
609
  trigger_error(__('Run Wordpress Export to XML file...','backwpup'),E_USER_NOTICE);
616
  } else {
617
  trigger_error(__('Can not Export to XML!','backwpup'),E_USER_ERROR);
618
  }
619
+ }
620
 
621
  private function optimize_db() {
622
  global $wpdb;
623
+
624
  trigger_error(__('Run Database optimize...','backwpup'),E_USER_NOTICE);
625
+
626
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
627
  //exclude tables from optimize
628
  foreach($tables as $tablekey => $tablevalue) {
629
  if (in_array($tablevalue,$this->job['dbexclude']))
630
  unset($tables[$tablekey]);
631
  }
632
+
633
  if (sizeof($tables)>0) {
634
  $this->maintenance_mode(true);
635
  foreach ($tables as $table) {
639
  elseif ($optimize['Msg_type']=='warning')
640
  trigger_error(sprintf(__('Result of table optimize for %1$s is: %2$s','backwpup'), $table, $optimize['Msg_text']),E_USER_WARNING);
641
  else
642
+ trigger_error(sprintf(__('Result of table optimize for %1$s is: %2$s','backwpup'), $table, $optimize['Msg_text']),E_USER_NOTICE);
643
+
644
+ if ($sqlerr=mysql_error($wpdb->dbh))
645
  trigger_error(sprintf(__('BackWPup database error %1$s for query %2$s','backwpup'), $sqlerr, $sqlerr->last_query),E_USER_ERROR);
646
  }
647
  $wpdb->flush();
649
  $this->maintenance_mode(false);
650
  } else {
651
  trigger_error(__('No Tables to optimize','backwpup'),E_USER_WARNING);
652
+ }
653
  }
654
 
655
  private function _file_list_folder( $folder = '', $levels = 100, $excludes,$excludedirs=array()) {
680
  }
681
  }
682
  @closedir( $dir );
683
+ }
684
  }
685
+
686
  private function file_list() {
687
 
688
  //Make filelist
689
  trigger_error(__('Make a list of files to Backup ....','backwpup'),E_USER_NOTICE);
690
+
691
  $this->tempfilelist=array();
692
+
693
  $backwpup_exclude=explode(',',trim($this->job['fileexclude']));
694
  //Exclude Temp Files
695
  $backwpup_exclude[]=$this->tempdir.DB_NAME.'.sql';
696
  $backwpup_exclude[]=$this->tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml';
697
  $backwpup_exclude=array_unique($backwpup_exclude,SORT_STRING);
698
+
699
  //File list for blog folders
700
  if ($this->job['backuproot'])
701
+ $this->_file_list_folder(untrailingslashit(str_replace('\\','/',ABSPATH)),100,$backwpup_exclude,array_merge($this->job['backuprootexcludedirs'],backwpup_get_exclude_wp_dirs(ABSPATH)));
702
  if ($this->job['backupcontent'])
703
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',WP_CONTENT_DIR)),100,$backwpup_exclude,array_merge($this->job['backupcontentexcludedirs'],backwpup_get_exclude_wp_dirs(WP_CONTENT_DIR)));
704
  if ($this->job['backupplugins'])
705
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',WP_PLUGIN_DIR)),100,$backwpup_exclude,array_merge($this->job['backuppluginsexcludedirs'],backwpup_get_exclude_wp_dirs(WP_PLUGIN_DIR)));
706
+ if ($this->job['backupthemes'])
707
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',trailingslashit(WP_CONTENT_DIR).'themes')),100,$backwpup_exclude,array_merge($this->job['backupthemesexcludedirs'],backwpup_get_exclude_wp_dirs(trailingslashit(WP_CONTENT_DIR).'themes')));
708
  if ($this->job['backupuploads'])
709
  $this->_file_list_folder(untrailingslashit(backwpup_get_upload_dir()),100,$backwpup_exclude,array_merge($this->job['backupuploadsexcludedirs'],backwpup_get_exclude_wp_dirs(backwpup_get_upload_dir())));
710
+
711
+ //include dirs
712
  $dirinclude=explode(',',$this->job['dirinclude']);
713
  $dirinclude=array_unique($dirinclude,SORT_STRING);
714
  //Crate file list
715
  if (is_array($dirinclude)) {
716
  foreach($dirinclude as $dirincludevalue) {
717
+ if (is_dir($dirincludevalue))
718
  $this->_file_list_folder(untrailingslashit(str_replace('\\','/',$dirincludevalue)),100,$backwpup_exclude);
719
  }
720
  }
725
  $this->filelist[]=array(79001=>$files,79003=>str_replace(str_replace('\\','/',trailingslashit(ABSPATH)),'',$files));
726
  }
727
  $this->tempfilelist=array();
728
+
729
  if (!is_array($this->filelist[0])) {
730
  trigger_error(__('No files to Backup','backwpup'),E_USER_ERROR);
731
  } else {
732
  trigger_error(__('Size off all files:','backwpup').' '.backwpup_formatBytes($this->allfilesize),E_USER_NOTICE);
733
  }
734
+
735
+ }
736
 
737
  private function zip_files() {
738
+
739
  if (class_exists('ZipArchive')) { //use php zip lib
740
  trigger_error(__('Create Backup Zip file...','backwpup'),E_USER_NOTICE);
741
  $zip = new ZipArchive;
742
  if ($res=$zip->open($this->backupdir.$this->backupfile,ZIPARCHIVE::CREATE) === TRUE) {
743
+ foreach($this->filelist as $key => $files) {
744
  if (!is_file($files[79001])) //check file exists
745
  continue;
746
  if ($zip->addFile($files[79001], $files[79003])) {
754
  } else {
755
  trigger_error(__('Can not create Backup ZIP file:','backwpup').' '.$res,E_USER_ERROR);
756
  }
757
+
758
  } else { //use PclZip
759
  define( 'PCLZIP_TEMPORARY_DIR', $this->tempdir );
760
+ if (!class_exists('PclZip'))
761
  require_once (plugin_dir_path(__FILE__).'libs/pclzip.lib.php');
762
+
763
  //Create Zip File
764
  if (is_array($this->filelist[0])) {
765
  $this->need_free_memory(10485760); //10MB free memory for zip
766
  trigger_error(__('Create Backup Zip (PclZip) file...','backwpup'),E_USER_NOTICE);
767
  foreach($this->filelist as $key => $files) {
768
  trigger_error(__('Add File to ZIP file:','backwpup').' '.$files[79001].' '.backwpup_formatBytes(filesize($files[79001])),E_USER_NOTICE);
769
+ }
770
  $zipbackupfile = new PclZip($this->backupdir.$this->backupfile);
771
  if (0==$zipbackupfile -> create($this->filelist,PCLZIP_OPT_ADD_TEMP_FILE_ON)) {
772
  trigger_error(__('Zip file create:','backwpup').' '.$zipbackupfile->errorInfo(true),E_USER_ERROR);
773
+ } else {
774
  trigger_error(__('Backup Zip file create done!','backwpup'),E_USER_NOTICE);
775
  }
776
  }
777
  }
778
  }
779
+
780
  private function tar_pack_files() {
781
+
782
  if ($this->backupfileformat=='.tar.gz') {
783
  $tarbackup=gzopen($this->backupdir.$this->backupfile,'w9');
784
  } elseif ($this->backupfileformat=='.tar.bz2') {
786
  } else {
787
  $tarbackup=fopen($this->backupdir.$this->backupfile,'w');
788
  }
789
+
790
  if (!$tarbackup) {
791
  trigger_error(__('Can not create TAR Backup file','backwpup'),E_USER_ERROR);
792
  return;
793
  } else {
794
  trigger_error(__('Create Backup Archive file...','backwpup'),E_USER_NOTICE);
795
  }
796
+
797
  $this->need_free_memory(1048576); //1MB free memory for zip
798
+
799
  foreach($this->filelist as $key => $files) {
800
  trigger_error(__('Add File to Backup Archive:','backwpup').' '.$files[79001].' '.backwpup_formatBytes(filesize($files[79001])),E_USER_NOTICE);
801
+
802
  //check file exists
803
  if (!is_file($files[79001]))
804
  continue;
805
+
806
  // Get file information
807
  $file_information = stat($files[79001]);
808
 
825
  "", //device minor number 8
826
  substr($files[79003],101), //prefix for file name 155
827
  ""); //fill block 512K
828
+
829
  // Computes the unsigned Checksum of a file's header
830
  $checksum = 0;
831
  for ($i = 0; $i < 512; $i++)
832
  $checksum += ord(substr($header, $i, 1));
833
  $checksum = pack("a8", sprintf("%07o", $checksum));
834
+
835
  $header = substr_replace($header, $checksum, 148, 8);
836
+
837
  if ($this->backupfileformat=='.tar.gz') {
838
  gzwrite($tarbackup, $header);
839
  } elseif ($this->backupfileformat=='.tar.bz2') {
841
  } else {
842
  fwrite($tarbackup, $header);
843
  }
844
+
845
  // read/write files in 512K Blocks
846
  $fd=fopen($files[79001],'rb');
847
  while(!feof($fd)) {
858
  }
859
  fclose($fd);
860
  }
861
+
862
+
863
  if ($this->backupfileformat=='.tar.gz') {
864
  gzwrite($tarbackup, pack("a1024", "")); // Add 1024 bytes of NULLs to designate EOF
865
+ gzclose($tarbackup);
866
  } elseif ($this->backupfileformat=='.tar.bz2') {
867
  bzwrite($tarbackup, pack("a1024", "")); // Add 1024 bytes of NULLs to designate EOF
868
  bzclose($tarbackup);
869
  } else {
870
  fwrite($tarbackup, pack("a1024", "")); // Add 1024 bytes of NULLs to designate EOF
871
+ fclose($tarbackup);
872
  }
873
+
874
  trigger_error(__('Backup Archive file create done!','backwpup'),E_USER_NOTICE);
875
  }
876
+
877
+
878
  private function _ftp_raw_helper($ftp_conn_id,$command) { //FTP Comands helper function
879
  $return=ftp_raw($ftp_conn_id,$command);
880
  if (strtoupper(substr(trim($command),0,4))=="PASS") {
902
  }
903
  }
904
  }
905
+
906
+
907
  private function destination_ftp() {
908
+
909
+ if (empty($this->job['ftphost']) or empty($this->job['ftpuser']) or empty($this->job['ftppass']))
910
  return false;
911
+
912
  $ftpport=21;
913
  $ftphost=$this->job['ftphost'];
914
  if (false !== strpos($this->job['ftphost'],':')) //look for port
916
 
917
  if (function_exists('ftp_ssl_connect')) { //make SSL FTP connection
918
  $ftp_conn_id = ftp_ssl_connect($ftphost,$ftpport,10);
919
+ if ($ftp_conn_id)
920
  trigger_error(__('Connected by SSL to FTP server:','backwpup').' '.$this->job['ftphost'],E_USER_NOTICE);
 
921
  }
922
  if (!$ftp_conn_id) { //make normal FTP conection if SSL not work
923
  $ftp_conn_id = ftp_connect($ftphost,$ftpport,10);
924
+ if ($ftp_conn_id)
925
  trigger_error(__('Connected insecure to FTP server:','backwpup').' '.$this->job['ftphost'],E_USER_NOTICE);
 
926
  }
927
+
928
  if (!$ftp_conn_id) {
929
  trigger_error(__('Can not connect to FTP server:','backwpup').' '.$this->job['ftphost'],E_USER_ERROR);
930
  return false;
942
  }
943
  }
944
  }
945
+
946
  //if (ftp_login($ftp_conn_id, $jobs[$jobid]['ftpuser'], $jobs[$jobid]['ftppass'])) {
947
+ if (!$loginok)
948
  return false;
949
+
950
  //SYSTYPE
951
  $this->_ftp_raw_helper($ftp_conn_id,'SYST');
952
  //PASV
953
  trigger_error(__('FTP Client command:','backwpup').' PASV',E_USER_NOTICE);
954
  if (ftp_pasv($ftp_conn_id, true))
955
  trigger_error(__('Server Completion reply: 227 Entering Passive Mode','backwpup'),E_USER_NOTICE);
956
+ else
957
  trigger_error(__('FTP Server reply:','backwpup').' '.__('Can not Entering Passive Mode','backwpup'),E_USER_WARNING);
958
  //ALLO show no erros in log if do not work
959
  trigger_error(__('FTP Client command:','backwpup').' ALLO',E_USER_NOTICE);
960
  ftp_alloc($ftp_conn_id,filesize($this->backupdir.$this->backupfile),$result);
961
  trigger_error(__('FTP Server reply:','backwpup').' '.$result,E_USER_NOTICE);
962
+
963
  //test ftp dir and create it f not exists
964
  $ftpdirs=explode("/", untrailingslashit($this->job['ftpdir']));
965
  foreach ($ftpdirs as $ftpdir) {
966
  if (empty($ftpdir))
967
  continue;
968
  if (!@ftp_chdir($ftp_conn_id, $ftpdir)) {
969
+ trigger_error('"'.$ftpdir.'" '.__('FTP Folder on Server not exists!','backwpup'),E_USER_WARNING);
970
  if (@ftp_mkdir($ftp_conn_id, $ftpdir)) {
971
+ trigger_error('"'.$ftpdir.'" '.__('FTP Folder created!','backwpup'),E_USER_NOTICE);
972
  ftp_chdir($ftp_conn_id, $ftpdir);
973
  } else {
974
+ trigger_error('"'.$ftpdir.'" '.__('FTP Folder on Server can not created!','backwpup'),E_USER_ERROR);
975
  }
976
  }
977
  }
978
+
979
  if (ftp_put($ftp_conn_id, $this->job['ftpdir'].$this->backupfile, $this->backupdir.$this->backupfile, FTP_BINARY)) //transfere file
980
  trigger_error(__('Backup File transferred to FTP Server:','backwpup').' '.$this->job['ftpdir'].$this->backupfile,E_USER_NOTICE);
981
  else
982
  trigger_error(__('Can not transfer backup to FTP server.','backwpup'),E_USER_ERROR);
983
+
984
  if ($this->job['ftpmaxbackups']>0) { //Delete old backups
985
  $backupfilelist=array();
986
  if ($filelist=ftp_nlist($ftp_conn_id, $this->job['ftpdir'])) {
994
  for ($i=$this->job['ftpmaxbackups'];$i<sizeof($backupfilelist);$i++) {
995
  if (ftp_delete($ftp_conn_id, $this->job['ftpdir'].$backupfilelist[$i])) //delte files on ftp
996
  $numdeltefiles++;
997
+ else
998
  trigger_error(__('Can not delete file on FTP Server:','backwpup').' '.$this->job['ftpdir'].$backupfilelist[$i],E_USER_ERROR);
999
  }
1000
  if ($numdeltefiles>0)
1002
  }
1003
  }
1004
  }
1005
+ ftp_close($ftp_conn_id);
1006
 
1007
+ }
1008
 
1009
  private function destination_mail() {
1010
  if (empty($this->job['mailaddress']))
1011
  return false;
1012
+
1013
+ trigger_error(__('Prepare Sending backup file with mail...','backwpup'),E_USER_NOTICE);
1014
+
1015
  //Crate PHP Mailer
1016
  require_once(ABSPATH.WPINC.'/class-phpmailer.php');
1017
  require_once(ABSPATH.WPINC.'/class-smtp.php');
1039
  $phpmailer->IsMail();
1040
  trigger_error(__('Send mail with PHP mail','backwpup'),E_USER_NOTICE);
1041
  }
1042
+
1043
 
1044
  trigger_error(__('Creating mail','backwpup'),E_USER_NOTICE);
1045
  $phpmailer->From = $this->cfg['mailsndemail'];
1046
  $phpmailer->FromName = $this->cfg['mailsndname'];
1047
+ $phpmailer->AddAddress($this->job['mailaddress']);
1048
  $phpmailer->Subject = __('BackWPup File from','backwpup').' '.date_i18n('Y-m-d H:i',$this->job['starttime']).': '.$this->job['name'];
1049
  $phpmailer->IsHTML(false);
1050
  $phpmailer->Body = 'Backup File';
1051
+
1052
  //check file Size
1053
  if (!empty($this->job['mailefilesize'])) {
1054
  $maxfilezise=abs($this->job['mailefilesize']*1024*1024);
1057
  return false;
1058
  }
1059
  }
1060
+
1061
  trigger_error(__('Adding Attachment to mail','backwpup'),E_USER_NOTICE);
1062
  $this->need_free_memory(filesize($this->backupdir.$this->backupfile)*5);
1063
+ $phpmailer->AddAttachment($this->backupdir.$this->backupfile);
1064
+
1065
  trigger_error(__('Send mail....','backwpup'),E_USER_NOTICE);
1066
  if (false == $phpmailer->Send()) {
1067
  trigger_error(__('Can not send mail:','backwpup').' '.$phpmailer->ErrorInfo,E_USER_ERROR);
1068
  } else {
1069
  trigger_error(__('Mail send!!!','backwpup'),E_USER_NOTICE);
1070
+ }
1071
+
1072
  }
1073
 
1074
  private function destination_s3() {
1075
+
1076
+ if (empty($this->job['awsAccessKey']) or empty($this->job['awsSecretKey']) or empty($this->job['awsBucket']))
1077
  return false;
1078
 
1079
  if (!(extension_loaded('curl') or @dl(PHP_SHLIB_SUFFIX == 'so' ? 'curl.so' : 'php_curl.dll'))) {
1081
  return false;
1082
  }
1083
 
1084
+ if (!class_exists('S3'))
1085
  require_once(plugin_dir_path(__FILE__).'libs/S3.php');
1086
+
1087
  $s3 = new S3($this->job['awsAccessKey'], $this->job['awsSecretKey'], $this->job['awsSSL']);
1088
 
1089
  if (in_array($this->job['awsBucket'],$s3->listBuckets())) {
1093
  trigger_error(__('Backup File transferred to S3://','backwpup').$this->job['awsBucket'].'/'.$this->job['awsdir'].$this->backupfile,E_USER_NOTICE);
1094
  else
1095
  trigger_error(__('Can not transfer backup to S3.','backwpup'),E_USER_ERROR);
1096
+
1097
  if ($this->job['awsmaxbackups']>0) { //Delete old backups
1098
  $backupfilelist=array();
1099
  if (($contents = $s3->getBucket($this->job['awsBucket'],$this->job['awsdir'])) !== false) {
1111
  for ($i=$this->job['awsmaxbackups'];$i<sizeof($backupfilelist);$i++) {
1112
  if ($s3->deleteObject($this->job['awsBucket'], $this->job['awsdir'].$backupfilelist[$i])) //delte files on S3
1113
  $numdeltefiles++;
1114
+ else
1115
  trigger_error(__('Can not delete file on S3//:','backwpup').$this->job['awsBucket'].'/'.$this->job['awsdir'].$backupfilelist[$i],E_USER_ERROR);
1116
  }
1117
  if ($numdeltefiles>0)
1129
  //Delete old Backupfiles
1130
  $backupfilelist=array();
1131
  if (!empty($this->job['maxbackups'])) {
1132
+ if ( $dir = @opendir($this->job['backupdir']) ) { //make file list
1133
  while (($file = readdir($dir)) !== false ) {
1134
  if ('backwpup_'.$this->jobid.'_' == substr($file,0,strlen('backwpup_'.$this->jobid.'_')) and $this->backupfileformat == substr($file,-strlen($this->backupfileformat)))
1135
  $backupfilelist[]=$file;
1148
  }
1149
  }
1150
  }
1151
+
1152
  public function __destruct() {
1153
  global $backwpup_logfile;
1154
+
1155
  if (is_file($this->backupdir.$this->backupfile)) {
1156
+ $filesize=filesize($this->backupdir.$this->backupfile);
1157
+ trigger_error(sprintf(__('Backup Archive File size is %1s','backwpup'),backwpup_formatBytes($filesize)),E_USER_NOTICE);
1158
  }
1159
 
1160
+ if (empty($filesize)) //Set the filezie corectly
1161
+ $filesize=0;
1162
+
1163
  if (is_file($this->tempdir.DB_NAME.'.sql') ) { //delete sql temp file
1164
  unlink($this->tempdir.DB_NAME.'.sql');
1165
  }
1166
+
1167
  if (is_file($this->tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml') ) { //delete WP XML Export temp file
1168
  unlink($this->tempdir.'wordpress.' . date( 'Y-m-d' ) . '.xml');
1169
  }
1170
+
1171
  if (empty($this->job['backupdir']) and is_file($this->backupdir.$this->backupfile)) { //delete backup file in temp dir
1172
  unlink($this->backupdir.$this->backupfile);
1173
  }
1174
+
1175
  //delete old logs
1176
  if (!empty($this->cfg['maxlogs'])) {
1177
+ if ( $dir = @opendir($this->logdir) ) { //make file list
1178
  while (($file = readdir($dir)) !== false ) {
1179
  if ('backwpup_log_' == substr($file,0,strlen('backwpup_log_')) and ".html" == substr($file,-5))
1180
  $logfilelist[]=$file;
1191
  if ($numdeltefiles>0)
1192
  trigger_error($numdeltefiles.' '.__('old Log files deleted!!!','backwpup'),E_USER_NOTICE);
1193
  }
1194
+ }
1195
+
1196
  $jobs=get_option('backwpup_jobs');
1197
  $jobs[$this->jobid]['stoptime']=current_time('timestamp');
1198
  $jobs[$this->jobid]['lastrun']=$jobs[$this->jobid]['starttime'];
1202
 
1203
  //write runtime header
1204
  $fd=@fopen($backwpup_logfile,"r+");
1205
+ $found=0;
1206
  while (!feof($fd)) {
1207
  $line=@fgets($fd);
1208
  if (stripos($line,"<meta name=\"backwpup_jobruntime\"") !== false) {
1209
  @fseek($fd,$filepos);
1210
  @fputs($fd,str_pad("<meta name=\"backwpup_jobruntime\" content=\"".$jobs[$this->jobid]['lastruntime']."\" />",100)."\n");
1211
+ $found++;
1212
+ }
1213
+ if (stripos($line,"<meta name=\"backwpup_backupfilesize\"") !== false) {
1214
+ @fseek($fd,$filepos);
1215
+ @fputs($fd,str_pad("<meta name=\"backwpup_backupfilesize\" content=\"".$filesize."\" />",100)."\n");
1216
+ $found++;
1217
  }
1218
+ if ($found>=2)
1219
+ break;
1220
  $filepos=ftell($fd);
1221
  }
1222
  @fclose($fd);
1235
  if ($sendmail) {
1236
  $mailbody=__("Jobname:","backwpup")." ".$logdata['name']."\n";
1237
  $mailbody.=__("Jobtype:","backwpup")." ".$logdata['type']."\n";
1238
+ if (!empty($logdata['errors']))
1239
  $mailbody.=__("Errors:","backwpup")." ".$logdata['errors']."\n";
1240
  if (!empty($logdata['warnings']))
1241
  $mailbody.=__("Warnings:","backwpup")." ".$logdata['warnings']."\n";
app/css/options.css CHANGED
@@ -1,12 +1,12 @@
1
- .column-id {
2
- width:40px;text-align:center;
3
- }
4
- .column-runtime, .column-last, .column-next , .column-status {
5
- width:125px;
6
- }
7
- .column-type {
8
- width:125px;
9
- }
10
- .column-size {
11
- width:75px;
12
  }
1
+ .column-id {
2
+ width:40px;text-align:center;
3
+ }
4
+ .column-runtime, .column-last, .column-next , .column-status {
5
+ width:125px;
6
+ }
7
+ .column-type {
8
+ width:125px;
9
+ }
10
+ .column-size {
11
+ width:75px;
12
  }
app/functions.php CHANGED
@@ -1,8 +1,8 @@
1
  <?PHP
2
- // don't load directly
3
- if ( !defined('ABSPATH') )
4
  die('-1');
5
-
6
  //Thems Option menu entry
7
  function backwpup_menu_entry() {
8
  $hook = add_management_page(__('BackWPup','backwpup'), __('BackWPup','backwpup'), '10', 'BackWPup','backwpup_options_page') ;
@@ -10,6 +10,7 @@ if ( !defined('ABSPATH') )
10
  add_contextual_help($hook,backwpup_show_help());
11
  switch($_REQUEST['action']) {
12
  case 'logs':
 
13
  register_column_headers($hook,array('cb'=>'<input type="checkbox" />','id'=>__('Job','backwpup'),'type'=>__('Type','backwpup'),'log'=>__('Backup/Log Date/Time','backwpup'),'status'=>__('Status','backwpup'),'size'=>__('Size','backwpup'),'runtime'=>__('Runtime','backwpup')));
14
  break;
15
  case 'edit':
@@ -18,18 +19,24 @@ if ( !defined('ABSPATH') )
18
  break;
19
  case 'tools':
20
  break;
 
 
 
 
21
  case 'runnow':
22
  add_action('load-'.$hook, 'backwpup_send_no_cache_header');
23
  add_action('admin_head-'.$hook, 'backwpup_meta_no_cache');
24
  break;
25
  case 'view_log':
26
  break;
 
 
27
  default:
28
  register_column_headers($hook,array('cb'=>'<input type="checkbox" />','id'=>__('ID','backwpup'),'jobname'=>__('Job Name','backwpup'),'type'=>__('Type','backwpup'),'next'=>__('Next Run','backwpup'),'last'=>__('Last Run','backwpup')));
29
  break;
30
  }
31
- }
32
-
33
  // Help too display
34
  function backwpup_show_help() {
35
  $help .= '<div class="metabox-prefs">';
@@ -42,20 +49,20 @@ if ( !defined('ABSPATH') )
42
  var flattr_btn = 'compact';
43
  var flattr_url = 'http://danielhuesken.de/portfolio/backwpup/';
44
  </script><script src=\"http://api.flattr.com/button/load.js\" type=\"text/javascript\"></script>";
45
- $help .= "</div>\n";
46
  $help .= '<div class="metabox-prefs">';
47
  $help .= __('Version:', 'backwpup').' '.BACKWPUP_VERSION.' | ';
48
  $help .= __('Author:', 'backwpup').' <a href="http://danielhuesken.de" target="_blank">Daniel H&uuml;sken</a>';
49
  $help .= "</div>\n";
50
  return $help;
51
  }
52
-
53
  //Options Page
54
  function backwpup_options_page() {
55
  global $wpdb,$backwpup_message,$page_hook;
56
- if (!current_user_can(10))
57
  wp_die('No rights');
58
- if(!empty($backwpup_message))
59
  echo '<div id="message" class="updated fade"><p><strong>'.$backwpup_message.'</strong></p></div>';
60
  switch($_REQUEST['action']) {
61
  case 'edit':
@@ -75,6 +82,9 @@ if ( !defined('ABSPATH') )
75
  case 'tools':
76
  require_once(plugin_dir_path(__FILE__).'options-tools.php');
77
  break;
 
 
 
78
  case 'runnow':
79
  $jobid = (int) $_GET['jobid'];
80
  check_admin_referer('runnow-job_' . $jobid);
@@ -89,13 +99,13 @@ if ( !defined('ABSPATH') )
89
  $jobs=get_option('backwpup_jobs');
90
  require_once(plugin_dir_path(__FILE__).'options.php');
91
  break;
92
- }
93
  }
94
-
95
  //Options Page
96
  function backwpup_options_load() {
97
  global $wpdb,$backwpup_message;
98
- if (!current_user_can(10))
99
  wp_die('No rights');
100
  //Css for Admin Section
101
  wp_enqueue_style('BackWpup',plugins_url('css/options.css',__FILE__),'',BACKWPUP_VERSION,'screen');
@@ -103,7 +113,7 @@ if ( !defined('ABSPATH') )
103
  //For save Options
104
  require_once(plugin_dir_path(__FILE__).'options-save.php');
105
  }
106
-
107
  //delete Otions
108
  function backwpup_plugin_uninstall() {
109
  delete_option('backwpup');
@@ -124,39 +134,39 @@ if ( !defined('ABSPATH') )
124
  $jobsettings['type']=implode('+',$todo);
125
  if (empty($jobsettings['type']))
126
  $jobsettings['type']='DB+FILE';
127
-
128
  if (empty($jobsettings['name']) or !is_string($jobsettings['name']))
129
  $jobsettings['name']= __('New');
130
-
131
- if (!isset($jobsettings['activated']) or !is_bool($jobsettings['activated']))
132
  $jobsettings['activated']=false;
133
-
134
  if (!isset($jobsettings['scheduletime']) or !is_numeric($jobsettings['scheduletime']))
135
  $jobsettings['scheduletime']=current_time('timestamp');
136
-
137
- if (!isset($jobsettings['scheduleintervaltype']) or !is_int($jobsettings['scheduleintervaltype']))
138
  $jobsettings['scheduleintervaltype']=3600;
139
  if ($jobsettings['scheduleintervaltype']!=60 and $jobsettings['scheduleintervaltype']!=3600 and $jobsettings['scheduleintervaltype']!=86400)
140
  $jobsettings['scheduleintervaltype']=3600;
141
-
142
  if (!isset($jobsettings['scheduleintervalteimes']) or !is_int($jobsettings['scheduleintervalteimes']) or ($jobsettings['scheduleintervalteimes']<1 and $jobsettings['scheduleintervalteimes']>100))
143
  $jobsettings['scheduleintervalteimes']=1;
144
-
145
  $jobsettings['scheduleinterval']=$jobsettings['scheduleintervaltype']*$jobsettings['scheduleintervalteimes'];
146
-
147
  if (!is_string($jobsettings['mailaddresslog']) or false === $pos=strpos($jobsettings['mailaddresslog'],'@') or false === strpos($jobsettings['mailaddresslog'],'.',$pos))
148
  $jobsettings['mailaddresslog']=get_option('admin_email');
149
-
150
  if (!isset($jobsettings['mailerroronly']) or !is_bool($jobsettings['mailerroronly']))
151
  $jobsettings['mailerroronly']=true;
152
-
153
  if (!isset($jobsettings['dbexclude']) or !is_array($jobsettings['dbexclude'])) {
154
  $jobsettings['dbexclude']=array();
155
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
156
  foreach ($tables as $table) {
157
  if (substr($table,0,strlen($wpdb->prefix))!=$wpdb->prefix)
158
  $jobsettings['dbexclude'][]=$table;
159
- }
160
  }
161
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
162
  foreach($jobsettings['dbexclude'] as $key => $value) {
@@ -164,13 +174,13 @@ if ( !defined('ABSPATH') )
164
  unset($jobsettings['dbexclude'][$key]);
165
  }
166
  sort($jobsettings['dbexclude']);
167
-
168
  if (!isset($jobsettings['dbshortinsert']) or !is_bool($jobsettings['dbshortinsert']))
169
  $jobsettings['dbshortinsert']=false;
170
-
171
  if (!isset($jobsettings['maintenance']) or !is_bool($jobsettings['maintenance']))
172
  $jobsettings['maintenance']=false;
173
-
174
  if (!isset($jobsettings['fileexclude']) or !is_string($jobsettings['fileexclude']))
175
  $jobsettings['fileexclude']='';
176
  $fileexclude=explode(',',$jobsettings['fileexclude']);
@@ -180,8 +190,8 @@ if ( !defined('ABSPATH') )
180
  unset($fileexclude[$key]);
181
  }
182
  sort($fileexclude);
183
- $jobsettings['fileexclude']=implode(',',$fileexclude);
184
-
185
  if (!isset($jobsettings['dirinclude']) or !is_string($jobsettings['dirinclude']))
186
  $jobsettings['dirinclude']='';
187
  $dirinclude=explode(',',$jobsettings['dirinclude']);
@@ -191,17 +201,17 @@ if ( !defined('ABSPATH') )
191
  unset($dirinclude[$key]);
192
  }
193
  sort($dirinclude);
194
- $jobsettings['dirinclude']=implode(',',$dirinclude);
195
 
196
  if (!isset($jobsettings['backuproot']) or !is_bool($jobsettings['backuproot']))
197
  $jobsettings['backuproot']=true;
198
-
199
  if (!isset($jobsettings['backupcontent']) or !is_bool($jobsettings['backupcontent']))
200
  $jobsettings['backupcontent']=true;
201
-
202
  if (!isset($jobsettings['backupplugins']) or !is_bool($jobsettings['backupplugins']))
203
  $jobsettings['backupplugins']=true;
204
-
205
  if (!isset($jobsettings['backupthemes']) or !is_bool($jobsettings['backupthemes']))
206
  $jobsettings['backupthemes']=true;
207
 
@@ -252,78 +262,78 @@ if ( !defined('ABSPATH') )
252
  unset($jobsettings['backupuploadsexcludedirs'][$key]);
253
  }
254
  sort($jobsettings['backupuploadsexcludedirs']);
255
-
256
  $fileformarts=array('.zip','.tar.gz','tar.bz2','.tar');
257
  if (!isset($jobsettings['fileformart']) or !in_array($jobsettings['fileformart'],$fileformarts))
258
  $jobsettings['fileformart']='.zip';
259
-
260
  if (!isset($jobsettings['mailefilesize']) or !is_float($jobsettings['mailefilesize']))
261
  $jobsettings['mailefilesize']=0;
262
-
263
  if (!isset($jobsettings['backupdir']) or (!is_dir($jobsettings['backupdir']) and !empty($jobsettings['backupdir']))) {
264
  $rand = substr( md5( md5( SECURE_AUTH_KEY ) ), -5 );
265
- $jobsettings['backupdir']=str_replace('\\','/',trailingslashit(WP_CONTENT_DIR)).'backwpup-'.$rand.'/';
266
  }
267
  $jobsettings['backupdir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['backupdir']))));
268
  if ($jobsettings['backupdir']=='/')
269
  $jobsettings['backupdir']='';
270
-
271
  if (!isset($jobsettings['maxbackups']) or !is_int($jobsettings['maxbackups']))
272
  $jobsettings['maxbackups']=0;
273
-
274
  if (!isset($jobsettings['ftphost']) or !is_string($jobsettings['ftphost']))
275
  $jobsettings['ftphost']='';
276
-
277
- if (!isset($jobsettings['ftpuser']) or !is_string($jobsettings['ftpuser']))
278
  $jobsettings['ftpuser']='';
279
-
280
  if (!isset($jobsettings['ftppass']) or !is_string($jobsettings['ftppass']))
281
  $jobsettings['ftppass']='';
282
 
283
- if (!isset($jobsettings['ftpdir']) or !is_string($jobsettings['ftpdir']) or $jobsettings['ftpdir']=='/')
284
  $jobsettings['ftpdir']='';
285
  $jobsettings['ftpdir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['ftpdir']))));
286
- if (substr($jobsettings['ftpdir'],0,1)=='/')
287
- $jobsettings['ftpdir']=substr($jobsettings['ftpdir'],1);
288
-
289
  if (!isset($jobsettings['ftpmaxbackups']) or !is_int($jobsettings['ftpmaxbackups']))
290
  $jobsettings['ftpmaxbackups']=0;
291
-
292
  if (!isset($jobsettings['awsAccessKey']) or !is_string($jobsettings['awsAccessKey']))
293
  $jobsettings['awsAccessKey']='';
294
-
295
  if (!isset($jobsettings['awsSecretKey']) or !is_string($jobsettings['awsSecretKey']))
296
  $jobsettings['awsSecretKey']='';
297
-
298
  if (!isset($jobsettings['awsSSL']) or !is_bool($jobsettings['awsSSL']))
299
  $jobsettings['awsSSL']=true;
300
-
301
  if (!isset($jobsettings['awsBucket']) or !is_string($jobsettings['awsBucket']))
302
  $jobsettings['awsBucket']='';
303
-
304
- if (!isset($jobsettings['awsdir']) or !is_string($jobsettings['awsdir']) or $jobsettings['awsdir']=='/')
305
  $jobsettings['awsdir']='';
306
  $jobsettings['awsdir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['awsdir']))));
307
  if (substr($jobsettings['awsdir'],0,1)=='/')
308
  $jobsettings['awsdir']=substr($jobsettings['awsdir'],1);
309
-
310
  if (!isset($jobsettings['awsmaxbackups']) or !is_int($jobsettings['awsmaxbackups']))
311
- $jobsettings['awsmaxbackups']=0;
312
-
313
  if (!is_string($jobsettings['mailaddress']) or false === $pos=strpos($jobsettings['mailaddress'],'@') or false === strpos($jobsettings['mailaddress'],'.',$pos))
314
  $jobsettings['mailaddress']='';
315
 
316
  return $jobsettings;
317
  }
318
 
319
-
320
  //On Plugin activate
321
  function backwpup_plugin_activate() {
322
  //add cron jobs
323
  $jobs=get_option('backwpup_jobs');
324
- if (is_array($jobs)) {
325
  foreach ($jobs as $jobid => $jobvalue) {
326
- if ($jobvalue['activated'] and wp_get_schedule('backwpup_cron',array('jobid'=>$jobid)) === false)
327
  wp_schedule_event($jobvalue['scheduletime'], 'backwpup_int_'.$jobid, 'backwpup_cron',array('jobid'=>$jobid));
328
  }
329
  }
@@ -340,25 +350,25 @@ if ( !defined('ABSPATH') )
340
  }
341
  if (empty($cfg['dirlogs'])) {
342
  $rand = substr( md5( md5( SECURE_AUTH_KEY ) ), -5 );
343
- $cfg['dirlogs']=str_replace('\\','/',trailingslashit(WP_CONTENT_DIR)).'/backwpup-'.$rand.'-logs/';
344
  }
345
  update_option('backwpup',$cfg);
346
  }
347
-
348
  //on Plugin deaktivate
349
  function backwpup_plugin_deactivate() {
350
  //remove cron jobs
351
  $jobs=get_option('backwpup_jobs');
352
  wp_clear_scheduled_hook('backwpup_cron');
353
  }
354
-
355
  //add edit setting to plugins page
356
  function backwpup_plugin_options_link($links) {
357
  $settings_link='<a href="admin.php?page=BackWPup" title="' . __('Go to Settings Page','backwpup') . '" class="edit">' . __('Settings') . '</a>';
358
- array_unshift( $links, $settings_link );
359
  return $links;
360
  }
361
-
362
  //add links on plugins page
363
  function backwpup_plugin_links($links, $file) {
364
  if ($file == BACKWPUP_PLUGIN_BASEDIR.'/backwpup.php') {
@@ -368,7 +378,7 @@ if ( !defined('ABSPATH') )
368
  }
369
  return $links;
370
  }
371
-
372
  //Add cron interval
373
  function backwpup_intervals($schedules) {
374
  $jobs=get_option('backwpup_jobs'); //Load Settings
@@ -377,9 +387,9 @@ if ( !defined('ABSPATH') )
377
  if (!empty($jobvalue['scheduleinterval']))
378
  $intervals['backwpup_int_'.$jobkey]=array('interval' => $jobvalue['scheduleinterval'], 'display' => __('BackWPup Job '.$jobkey, 'backwpup'));
379
  }
380
- if (is_array($intervals))
381
  $schedules=array_merge($intervals,$schedules);
382
- }
383
  return $schedules;
384
  }
385
 
@@ -390,14 +400,14 @@ if ( !defined('ABSPATH') )
390
  extract($args, EXTR_SKIP );
391
  else
392
  $jobid=$args;
393
- if (empty($jobid))
394
  return false;
395
  require_once('backwpup_dojob.php');
396
  $backwpup_dojob= new backwpup_dojob($jobid);
397
  unset($backwpup_dojob);
398
  return $backwpup_logfile;
399
  }
400
-
401
  //file size
402
  function backwpup_formatBytes($bytes, $precision = 2) {
403
  $units = array('B', 'KB', 'MB', 'GB', 'TB');
@@ -406,8 +416,8 @@ if ( !defined('ABSPATH') )
406
  $pow = min($pow, count($units) - 1);
407
  $bytes /= pow(1024, $pow);
408
  return round($bytes, $precision) . ' ' . $units[$pow];
409
- }
410
-
411
  //echo long backup type name
412
  function backwpup_backup_types($type='',$echo=false) {
413
  $typename='';
@@ -420,7 +430,7 @@ if ( !defined('ABSPATH') )
420
  break;
421
  case 'DB':
422
  $typename.=__('Database Backup','backwpup')."<br />";
423
- break;
424
  case 'FILE':
425
  $typename.=__('File Backup','backwpup')."<br />";
426
  break;
@@ -435,16 +445,16 @@ if ( !defined('ABSPATH') )
435
  } else {
436
  $typename=array('WPEXP','DB','FILE','OPTIMIZE','CHECK');
437
  }
438
-
439
- if ($echo)
440
  echo $typename;
441
  else
442
  return $typename;
443
  }
444
-
445
  //read log file header
446
  function backwpup_read_logheader($logfile) {
447
- $headers=array("backwpup_version" => "version","backwpup_logtime" => "logtime","backwpup_errors" => "errors","backwpup_warnings" => "warnings","backwpup_jobid" => "jobid","backwpup_jobname" => "name","backwpup_jobtype" => "type","backwpup_jobruntime" => "runtime","backwpup_backupfile" => "backupfile");
448
  if (!is_readable($logfile))
449
  return false;
450
  //Read file
@@ -460,14 +470,14 @@ if ( !defined('ABSPATH') )
460
  else
461
  $joddata[$field]='';
462
  }
463
-
464
  if (empty($joddata['logtime']))
465
  $joddata['logtime']=filectime($logfile);
466
-
467
  return $joddata;
468
  }
469
-
470
-
471
  //Dashboard widget
472
  function backwpup_dashboard_output() {
473
  global $wpdb;
@@ -483,25 +493,25 @@ if ( !defined('ABSPATH') )
483
  closedir( $dir );
484
  rsort($logfiles);
485
  }
486
-
487
  if (is_array($logfiles)) {
488
  $count=0;
489
  foreach ($logfiles as $logfile) {
490
  $logdata=backwpup_read_logheader($cfg['dirlogs'].'/'.$logfile);
491
  echo '<a href="'.wp_nonce_url('admin.php?page=BackWPup&action=view_log&logfile='.$cfg['dirlogs'].'/'.$logfile, 'view-log_'.$logfile).'" title="'.__('View Log','backwpup').'">'.date_i18n(get_option('date_format'),$logdata['logtime']).' '.date_i18n(get_option('time_format'),$logdata['logtime']).': <i>';
492
- if (empty($logdata['name']))
493
  echo $logdata['type'];
494
  else
495
  echo $logdata['name'];
496
  echo '</i>';
497
- if($logdata['errors']>0 or $logdata['warnings']>0) {
498
  if ($logdata['errors']>0)
499
- echo ' <span style="color:red;">'.$logdata['errors'].' '.__('ERROR(S)','backwpup').'</span>';
500
  if ($logdata['warnings']>0)
501
- echo ' <span style="color:yellow;">'.$logdata['warnings'].' '.__('WARNING(S)','backwpup').'</span>';
502
- } else {
503
- echo ' <span style="color:green;">'.__('OK','backwpup').'</span>';
504
- }
505
  echo '</a><br />';
506
  $count++;
507
  if ($count>=5)
@@ -512,7 +522,7 @@ if ( !defined('ABSPATH') )
512
  }
513
  $jobs=get_option('backwpup_jobs');
514
  echo '<strong>'.__('Scheduled Jobs:','backwpup').'</strong><br />';
515
- if (is_array($jobs)) {
516
  foreach ($jobs as $jobid => $jobvalue) {
517
  if (wp_next_scheduled('backwpup_cron',array('jobid'=>$jobid))) {
518
  echo '<a href="'.wp_nonce_url('admin.php?page=BackWPup&action=edit&jobid='.$jobid, 'edit-job').'" title="'.__('Edit Job','backwpup').'">';
@@ -529,19 +539,19 @@ if ( !defined('ABSPATH') )
529
  echo '<i>'.__('none','backwpup').'</i><br />';
530
  }
531
  }
532
-
533
  //add dashboard widget
534
  function backwpup_add_dashboard() {
535
- wp_add_dashboard_widget( 'backwpup_dashboard_widget', 'BackWPup', 'backwpup_dashboard_output' );
536
  }
537
-
538
  //turn cache off
539
  function backwpup_meta_no_cache() {
540
  echo "<meta http-equiv=\"expires\" content=\"0\" />\n";
541
  echo "<meta http-equiv=\"pragma\" content=\"no-cache\" />\n";
542
  echo "<meta http-equiv=\"cache-control\" content=\"no-cache\" />\n";
543
  }
544
-
545
  function backwpup_send_no_cache_header() {
546
  header("Expires: 0");
547
  header("Cache-Control: no-cache, must-revalidate");
@@ -564,7 +574,7 @@ if ( !defined('ABSPATH') )
564
  // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
565
  $dir = path_join( ABSPATH, $dir );
566
  }
567
- }
568
  if ( defined('UPLOADS') && !$main_override && ( !isset( $switched ) || $switched === false ) ) {
569
  $dir = ABSPATH . UPLOADS;
570
  }
@@ -574,10 +584,10 @@ if ( !defined('ABSPATH') )
574
  $dir = untrailingslashit(BLOGUPLOADDIR);
575
  }
576
  }
577
-
578
  return str_replace('\\','/',trailingslashit($dir));
579
  }
580
-
581
  function backwpup_get_exclude_wp_dirs($folder) {
582
  $folder=trailingslashit(str_replace('\\','/',$folder));
583
  $excludedir=array();
@@ -593,13 +603,127 @@ if ( !defined('ABSPATH') )
593
  $excludedir[]=backwpup_get_upload_dir();
594
  //Exclude Backup dirs
595
  $jobs=get_option('backwpup_jobs');
596
- foreach($jobs as $jobsvale) {
597
  if (!empty($jobsvale['backupdir']) and $jobsvale['backupdir']!='/')
598
  $excludedir[]=trailingslashit(str_replace('\\','/',$jobsvale['backupdir']));
599
  }
600
  return $excludedir;
601
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
602
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  //ajax/normal get buckests select box
604
  function backwpup_get_aws_buckets($args='') {
605
  if (is_array($args)) {
@@ -619,13 +743,13 @@ if ( !defined('ABSPATH') )
619
  if (empty($awsSecretKey)) {
620
  echo '<span id="awsBucket" style="color:red;">'.__('Missing Secret Access Key!','backwpup').'</span>';
621
  die();
622
- }
623
  $s3 = new S3($awsAccessKey, $awsSecretKey, false);
624
  $buckets=@$s3->listBuckets();
625
  if (!is_array($buckets)) {
626
  echo '<span id="awsBucket" style="color:red;">'.__('No Buckets found! Or wrong Keys!','backwpup').'</span>';
627
  die();
628
- }
629
  echo '<select name="awsBucket" id="awsBucket">';
630
  foreach ($buckets as $bucket) {
631
  echo "<option ".selected(strtolower($selected),strtolower($bucket),false).">".$bucket."</option>";
@@ -634,7 +758,7 @@ if ( !defined('ABSPATH') )
634
  if ($ajax)
635
  die();
636
  }
637
-
638
  // add all action and so on only if plugin loaded.
639
  function backwpup_init() {
640
  //Disabele WP_Corn
@@ -644,19 +768,19 @@ if ( !defined('ABSPATH') )
644
  //add Menu
645
  add_action('admin_menu', 'backwpup_menu_entry');
646
  //Additional links on the plugin page
647
- if (current_user_can(10))
648
  add_filter('plugin_action_links_'.BACKWPUP_PLUGIN_BASEDIR.'/backwpup.php', 'backwpup_plugin_options_link');
649
- if (current_user_can('install_plugins'))
650
  add_filter('plugin_row_meta', 'backwpup_plugin_links',10,2);
651
  //add cron intervals
652
  add_filter('cron_schedules', 'backwpup_intervals');
653
  //Actions for Cron job
654
  add_action('backwpup_cron', 'backwpup_dojob');
655
  //add Dashboard widget
656
- if (current_user_can(10))
657
  add_action('wp_dashboard_setup', 'backwpup_add_dashboard');
658
  // add ajax function
659
  add_action('wp_ajax_backwpup_get_aws_buckets', 'backwpup_get_aws_buckets');
660
- }
661
 
662
  ?>
1
  <?PHP
2
+ // don't load directly
3
+ if ( !defined('ABSPATH') )
4
  die('-1');
5
+
6
  //Thems Option menu entry
7
  function backwpup_menu_entry() {
8
  $hook = add_management_page(__('BackWPup','backwpup'), __('BackWPup','backwpup'), '10', 'BackWPup','backwpup_options_page') ;
10
  add_contextual_help($hook,backwpup_show_help());
11
  switch($_REQUEST['action']) {
12
  case 'logs':
13
+ case 'delete-logs':
14
  register_column_headers($hook,array('cb'=>'<input type="checkbox" />','id'=>__('Job','backwpup'),'type'=>__('Type','backwpup'),'log'=>__('Backup/Log Date/Time','backwpup'),'status'=>__('Status','backwpup'),'size'=>__('Size','backwpup'),'runtime'=>__('Runtime','backwpup')));
15
  break;
16
  case 'edit':
19
  break;
20
  case 'tools':
21
  break;
22
+ case 'backups':
23
+ case 'delete-backup':
24
+ register_column_headers($hook,array('cb'=>'<input type="checkbox" />','id'=>__('Job','backwpup'),'backup'=>__('Backupfile','backwpup'),'size'=>__('Size','backwpup')));
25
+ break;
26
  case 'runnow':
27
  add_action('load-'.$hook, 'backwpup_send_no_cache_header');
28
  add_action('admin_head-'.$hook, 'backwpup_meta_no_cache');
29
  break;
30
  case 'view_log':
31
  break;
32
+ case 'delete':
33
+ case 'copy':
34
  default:
35
  register_column_headers($hook,array('cb'=>'<input type="checkbox" />','id'=>__('ID','backwpup'),'jobname'=>__('Job Name','backwpup'),'type'=>__('Type','backwpup'),'next'=>__('Next Run','backwpup'),'last'=>__('Last Run','backwpup')));
36
  break;
37
  }
38
+ }
39
+
40
  // Help too display
41
  function backwpup_show_help() {
42
  $help .= '<div class="metabox-prefs">';
49
  var flattr_btn = 'compact';
50
  var flattr_url = 'http://danielhuesken.de/portfolio/backwpup/';
51
  </script><script src=\"http://api.flattr.com/button/load.js\" type=\"text/javascript\"></script>";
52
+ $help .= "</div>\n";
53
  $help .= '<div class="metabox-prefs">';
54
  $help .= __('Version:', 'backwpup').' '.BACKWPUP_VERSION.' | ';
55
  $help .= __('Author:', 'backwpup').' <a href="http://danielhuesken.de" target="_blank">Daniel H&uuml;sken</a>';
56
  $help .= "</div>\n";
57
  return $help;
58
  }
59
+
60
  //Options Page
61
  function backwpup_options_page() {
62
  global $wpdb,$backwpup_message,$page_hook;
63
+ if (!current_user_can(10))
64
  wp_die('No rights');
65
+ if(!empty($backwpup_message))
66
  echo '<div id="message" class="updated fade"><p><strong>'.$backwpup_message.'</strong></p></div>';
67
  switch($_REQUEST['action']) {
68
  case 'edit':
82
  case 'tools':
83
  require_once(plugin_dir_path(__FILE__).'options-tools.php');
84
  break;
85
+ case 'backups':
86
+ require_once(plugin_dir_path(__FILE__).'options-backups.php');
87
+ break;
88
  case 'runnow':
89
  $jobid = (int) $_GET['jobid'];
90
  check_admin_referer('runnow-job_' . $jobid);
99
  $jobs=get_option('backwpup_jobs');
100
  require_once(plugin_dir_path(__FILE__).'options.php');
101
  break;
102
+ }
103
  }
104
+
105
  //Options Page
106
  function backwpup_options_load() {
107
  global $wpdb,$backwpup_message;
108
+ if (!current_user_can(10))
109
  wp_die('No rights');
110
  //Css for Admin Section
111
  wp_enqueue_style('BackWpup',plugins_url('css/options.css',__FILE__),'',BACKWPUP_VERSION,'screen');
113
  //For save Options
114
  require_once(plugin_dir_path(__FILE__).'options-save.php');
115
  }
116
+
117
  //delete Otions
118
  function backwpup_plugin_uninstall() {
119
  delete_option('backwpup');
134
  $jobsettings['type']=implode('+',$todo);
135
  if (empty($jobsettings['type']))
136
  $jobsettings['type']='DB+FILE';
137
+
138
  if (empty($jobsettings['name']) or !is_string($jobsettings['name']))
139
  $jobsettings['name']= __('New');
140
+
141
+ if (!isset($jobsettings['activated']) or !is_bool($jobsettings['activated']))
142
  $jobsettings['activated']=false;
143
+
144
  if (!isset($jobsettings['scheduletime']) or !is_numeric($jobsettings['scheduletime']))
145
  $jobsettings['scheduletime']=current_time('timestamp');
146
+
147
+ if (!isset($jobsettings['scheduleintervaltype']) or !is_int($jobsettings['scheduleintervaltype']))
148
  $jobsettings['scheduleintervaltype']=3600;
149
  if ($jobsettings['scheduleintervaltype']!=60 and $jobsettings['scheduleintervaltype']!=3600 and $jobsettings['scheduleintervaltype']!=86400)
150
  $jobsettings['scheduleintervaltype']=3600;
151
+
152
  if (!isset($jobsettings['scheduleintervalteimes']) or !is_int($jobsettings['scheduleintervalteimes']) or ($jobsettings['scheduleintervalteimes']<1 and $jobsettings['scheduleintervalteimes']>100))
153
  $jobsettings['scheduleintervalteimes']=1;
154
+
155
  $jobsettings['scheduleinterval']=$jobsettings['scheduleintervaltype']*$jobsettings['scheduleintervalteimes'];
156
+
157
  if (!is_string($jobsettings['mailaddresslog']) or false === $pos=strpos($jobsettings['mailaddresslog'],'@') or false === strpos($jobsettings['mailaddresslog'],'.',$pos))
158
  $jobsettings['mailaddresslog']=get_option('admin_email');
159
+
160
  if (!isset($jobsettings['mailerroronly']) or !is_bool($jobsettings['mailerroronly']))
161
  $jobsettings['mailerroronly']=true;
162
+
163
  if (!isset($jobsettings['dbexclude']) or !is_array($jobsettings['dbexclude'])) {
164
  $jobsettings['dbexclude']=array();
165
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
166
  foreach ($tables as $table) {
167
  if (substr($table,0,strlen($wpdb->prefix))!=$wpdb->prefix)
168
  $jobsettings['dbexclude'][]=$table;
169
+ }
170
  }
171
  $tables=$wpdb->get_col('SHOW TABLES FROM `'.DB_NAME.'`');
172
  foreach($jobsettings['dbexclude'] as $key => $value) {
174
  unset($jobsettings['dbexclude'][$key]);
175
  }
176
  sort($jobsettings['dbexclude']);
177
+
178
  if (!isset($jobsettings['dbshortinsert']) or !is_bool($jobsettings['dbshortinsert']))
179
  $jobsettings['dbshortinsert']=false;
180
+
181
  if (!isset($jobsettings['maintenance']) or !is_bool($jobsettings['maintenance']))
182
  $jobsettings['maintenance']=false;
183
+
184
  if (!isset($jobsettings['fileexclude']) or !is_string($jobsettings['fileexclude']))
185
  $jobsettings['fileexclude']='';
186
  $fileexclude=explode(',',$jobsettings['fileexclude']);
190
  unset($fileexclude[$key]);
191
  }
192
  sort($fileexclude);
193
+ $jobsettings['fileexclude']=implode(',',$fileexclude);
194
+
195
  if (!isset($jobsettings['dirinclude']) or !is_string($jobsettings['dirinclude']))
196
  $jobsettings['dirinclude']='';
197
  $dirinclude=explode(',',$jobsettings['dirinclude']);
201
  unset($dirinclude[$key]);
202
  }
203
  sort($dirinclude);
204
+ $jobsettings['dirinclude']=implode(',',$dirinclude);
205
 
206
  if (!isset($jobsettings['backuproot']) or !is_bool($jobsettings['backuproot']))
207
  $jobsettings['backuproot']=true;
208
+
209
  if (!isset($jobsettings['backupcontent']) or !is_bool($jobsettings['backupcontent']))
210
  $jobsettings['backupcontent']=true;
211
+
212
  if (!isset($jobsettings['backupplugins']) or !is_bool($jobsettings['backupplugins']))
213
  $jobsettings['backupplugins']=true;
214
+
215
  if (!isset($jobsettings['backupthemes']) or !is_bool($jobsettings['backupthemes']))
216
  $jobsettings['backupthemes']=true;
217
 
262
  unset($jobsettings['backupuploadsexcludedirs'][$key]);
263
  }
264
  sort($jobsettings['backupuploadsexcludedirs']);
265
+
266
  $fileformarts=array('.zip','.tar.gz','tar.bz2','.tar');
267
  if (!isset($jobsettings['fileformart']) or !in_array($jobsettings['fileformart'],$fileformarts))
268
  $jobsettings['fileformart']='.zip';
269
+
270
  if (!isset($jobsettings['mailefilesize']) or !is_float($jobsettings['mailefilesize']))
271
  $jobsettings['mailefilesize']=0;
272
+
273
  if (!isset($jobsettings['backupdir']) or (!is_dir($jobsettings['backupdir']) and !empty($jobsettings['backupdir']))) {
274
  $rand = substr( md5( md5( SECURE_AUTH_KEY ) ), -5 );
275
+ $jobsettings['backupdir']=str_replace('\\','/',trailingslashit(WP_CONTENT_DIR)).'backwpup-'.$rand.'/';
276
  }
277
  $jobsettings['backupdir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['backupdir']))));
278
  if ($jobsettings['backupdir']=='/')
279
  $jobsettings['backupdir']='';
280
+
281
  if (!isset($jobsettings['maxbackups']) or !is_int($jobsettings['maxbackups']))
282
  $jobsettings['maxbackups']=0;
283
+
284
  if (!isset($jobsettings['ftphost']) or !is_string($jobsettings['ftphost']))
285
  $jobsettings['ftphost']='';
286
+
287
+ if (!isset($jobsettings['ftpuser']) or !is_string($jobsettings['ftpuser']))
288
  $jobsettings['ftpuser']='';
289
+
290
  if (!isset($jobsettings['ftppass']) or !is_string($jobsettings['ftppass']))
291
  $jobsettings['ftppass']='';
292
 
293
+ if (!isset($jobsettings['ftpdir']) or !is_string($jobsettings['ftpdir']) or $jobsettings['ftpdir']=='/')
294
  $jobsettings['ftpdir']='';
295
  $jobsettings['ftpdir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['ftpdir']))));
296
+ if (substr($jobsettings['ftpdir'],0,1)!='/')
297
+ $jobsettings['ftpdir']='/'.$jobsettings['ftpdir'];
298
+
299
  if (!isset($jobsettings['ftpmaxbackups']) or !is_int($jobsettings['ftpmaxbackups']))
300
  $jobsettings['ftpmaxbackups']=0;
301
+
302
  if (!isset($jobsettings['awsAccessKey']) or !is_string($jobsettings['awsAccessKey']))
303
  $jobsettings['awsAccessKey']='';
304
+
305
  if (!isset($jobsettings['awsSecretKey']) or !is_string($jobsettings['awsSecretKey']))
306
  $jobsettings['awsSecretKey']='';
307
+
308
  if (!isset($jobsettings['awsSSL']) or !is_bool($jobsettings['awsSSL']))
309
  $jobsettings['awsSSL']=true;
310
+
311
  if (!isset($jobsettings['awsBucket']) or !is_string($jobsettings['awsBucket']))
312
  $jobsettings['awsBucket']='';
313
+
314
+ if (!isset($jobsettings['awsdir']) or !is_string($jobsettings['awsdir']) or $jobsettings['awsdir']=='/')
315
  $jobsettings['awsdir']='';
316
  $jobsettings['awsdir']=trailingslashit(str_replace('//','/',str_replace('\\','/',trim($jobsettings['awsdir']))));
317
  if (substr($jobsettings['awsdir'],0,1)=='/')
318
  $jobsettings['awsdir']=substr($jobsettings['awsdir'],1);
319
+
320
  if (!isset($jobsettings['awsmaxbackups']) or !is_int($jobsettings['awsmaxbackups']))
321
+ $jobsettings['awsmaxbackups']=0;
322
+
323
  if (!is_string($jobsettings['mailaddress']) or false === $pos=strpos($jobsettings['mailaddress'],'@') or false === strpos($jobsettings['mailaddress'],'.',$pos))
324
  $jobsettings['mailaddress']='';
325
 
326
  return $jobsettings;
327
  }
328
 
329
+
330
  //On Plugin activate
331
  function backwpup_plugin_activate() {
332
  //add cron jobs
333
  $jobs=get_option('backwpup_jobs');
334
+ if (is_array($jobs)) {
335
  foreach ($jobs as $jobid => $jobvalue) {
336
+ if ($jobvalue['activated'] and wp_get_schedule('backwpup_cron',array('jobid'=>$jobid)) === false)
337
  wp_schedule_event($jobvalue['scheduletime'], 'backwpup_int_'.$jobid, 'backwpup_cron',array('jobid'=>$jobid));
338
  }
339
  }
350
  }
351
  if (empty($cfg['dirlogs'])) {
352
  $rand = substr( md5( md5( SECURE_AUTH_KEY ) ), -5 );
353
+ $cfg['dirlogs']=str_replace('\\','/',trailingslashit(WP_CONTENT_DIR)).'backwpup-'.$rand.'-logs/';
354
  }
355
  update_option('backwpup',$cfg);
356
  }
357
+
358
  //on Plugin deaktivate
359
  function backwpup_plugin_deactivate() {
360
  //remove cron jobs
361
  $jobs=get_option('backwpup_jobs');
362
  wp_clear_scheduled_hook('backwpup_cron');
363
  }
364
+
365
  //add edit setting to plugins page
366
  function backwpup_plugin_options_link($links) {
367
  $settings_link='<a href="admin.php?page=BackWPup" title="' . __('Go to Settings Page','backwpup') . '" class="edit">' . __('Settings') . '</a>';
368
+ array_unshift( $links, $settings_link );
369
  return $links;
370
  }
371
+
372
  //add links on plugins page
373
  function backwpup_plugin_links($links, $file) {
374
  if ($file == BACKWPUP_PLUGIN_BASEDIR.'/backwpup.php') {
378
  }
379
  return $links;
380
  }
381
+
382
  //Add cron interval
383
  function backwpup_intervals($schedules) {
384
  $jobs=get_option('backwpup_jobs'); //Load Settings
387
  if (!empty($jobvalue['scheduleinterval']))
388
  $intervals['backwpup_int_'.$jobkey]=array('interval' => $jobvalue['scheduleinterval'], 'display' => __('BackWPup Job '.$jobkey, 'backwpup'));
389
  }
390
+ if (is_array($intervals))
391
  $schedules=array_merge($intervals,$schedules);
392
+ }
393
  return $schedules;
394
  }
395
 
400
  extract($args, EXTR_SKIP );
401
  else
402
  $jobid=$args;
403
+ if (empty($jobid))
404
  return false;
405
  require_once('backwpup_dojob.php');
406
  $backwpup_dojob= new backwpup_dojob($jobid);
407
  unset($backwpup_dojob);
408
  return $backwpup_logfile;
409
  }
410
+
411
  //file size
412
  function backwpup_formatBytes($bytes, $precision = 2) {
413
  $units = array('B', 'KB', 'MB', 'GB', 'TB');
416
  $pow = min($pow, count($units) - 1);
417
  $bytes /= pow(1024, $pow);
418
  return round($bytes, $precision) . ' ' . $units[$pow];
419
+ }
420
+
421
  //echo long backup type name
422
  function backwpup_backup_types($type='',$echo=false) {
423
  $typename='';
430
  break;
431
  case 'DB':
432
  $typename.=__('Database Backup','backwpup')."<br />";
433
+ break;
434
  case 'FILE':
435
  $typename.=__('File Backup','backwpup')."<br />";
436
  break;
445
  } else {
446
  $typename=array('WPEXP','DB','FILE','OPTIMIZE','CHECK');
447
  }
448
+
449
+ if ($echo)
450
  echo $typename;
451
  else
452
  return $typename;
453
  }
454
+
455
  //read log file header
456
  function backwpup_read_logheader($logfile) {
457
+ $headers=array("backwpup_version" => "version","backwpup_logtime" => "logtime","backwpup_errors" => "errors","backwpup_warnings" => "warnings","backwpup_jobid" => "jobid","backwpup_jobname" => "name","backwpup_jobtype" => "type","backwpup_jobruntime" => "runtime","backwpup_backupfile" => "backupfile","backwpup_backupfilesize" => "backupfilesize");
458
  if (!is_readable($logfile))
459
  return false;
460
  //Read file
470
  else
471
  $joddata[$field]='';
472
  }
473
+
474
  if (empty($joddata['logtime']))
475
  $joddata['logtime']=filectime($logfile);
476
+
477
  return $joddata;
478
  }
479
+
480
+
481
  //Dashboard widget
482
  function backwpup_dashboard_output() {
483
  global $wpdb;
493
  closedir( $dir );
494
  rsort($logfiles);
495
  }
496
+
497
  if (is_array($logfiles)) {
498
  $count=0;
499
  foreach ($logfiles as $logfile) {
500
  $logdata=backwpup_read_logheader($cfg['dirlogs'].'/'.$logfile);
501
  echo '<a href="'.wp_nonce_url('admin.php?page=BackWPup&action=view_log&logfile='.$cfg['dirlogs'].'/'.$logfile, 'view-log_'.$logfile).'" title="'.__('View Log','backwpup').'">'.date_i18n(get_option('date_format'),$logdata['logtime']).' '.date_i18n(get_option('time_format'),$logdata['logtime']).': <i>';
502
+ if (empty($logdata['name']))
503
  echo $logdata['type'];
504
  else
505
  echo $logdata['name'];
506
  echo '</i>';
507
+ if($logdata['errors']>0 or $logdata['warnings']>0) {
508
  if ($logdata['errors']>0)
509
+ echo ' <span style="color:red;">'.$logdata['errors'].' '.__('ERROR(S)','backwpup').'</span>';
510
  if ($logdata['warnings']>0)
511
+ echo ' <span style="color:yellow;">'.$logdata['warnings'].' '.__('WARNING(S)','backwpup').'</span>';
512
+ } else {
513
+ echo ' <span style="color:green;">'.__('OK','backwpup').'</span>';
514
+ }
515
  echo '</a><br />';
516
  $count++;
517
  if ($count>=5)
522
  }
523
  $jobs=get_option('backwpup_jobs');
524
  echo '<strong>'.__('Scheduled Jobs:','backwpup').'</strong><br />';
525
+ if (is_array($jobs)) {
526
  foreach ($jobs as $jobid => $jobvalue) {
527
  if (wp_next_scheduled('backwpup_cron',array('jobid'=>$jobid))) {
528
  echo '<a href="'.wp_nonce_url('admin.php?page=BackWPup&action=edit&jobid='.$jobid, 'edit-job').'" title="'.__('Edit Job','backwpup').'">';
539
  echo '<i>'.__('none','backwpup').'</i><br />';
540
  }
541
  }
542
+
543
  //add dashboard widget
544
  function backwpup_add_dashboard() {
545
+ wp_add_dashboard_widget( 'backwpup_dashboard_widget', 'BackWPup', 'backwpup_dashboard_output' );
546
  }
547
+
548
  //turn cache off
549
  function backwpup_meta_no_cache() {
550
  echo "<meta http-equiv=\"expires\" content=\"0\" />\n";
551
  echo "<meta http-equiv=\"pragma\" content=\"no-cache\" />\n";
552
  echo "<meta http-equiv=\"cache-control\" content=\"no-cache\" />\n";
553
  }
554
+
555
  function backwpup_send_no_cache_header() {
556
  header("Expires: 0");
557
  header("Cache-Control: no-cache, must-revalidate");
574
  // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
575
  $dir = path_join( ABSPATH, $dir );
576
  }
577
+ }
578
  if ( defined('UPLOADS') && !$main_override && ( !isset( $switched ) || $switched === false ) ) {
579
  $dir = ABSPATH . UPLOADS;
580
  }
584
  $dir = untrailingslashit(BLOGUPLOADDIR);
585
  }
586
  }
587
+
588
  return str_replace('\\','/',trailingslashit($dir));
589
  }
590
+
591
  function backwpup_get_exclude_wp_dirs($folder) {
592
  $folder=trailingslashit(str_replace('\\','/',$folder));
593
  $excludedir=array();
603
  $excludedir[]=backwpup_get_upload_dir();
604
  //Exclude Backup dirs
605
  $jobs=get_option('backwpup_jobs');
606
+ foreach((array)$jobs as $jobsvale) {
607
  if (!empty($jobsvale['backupdir']) and $jobsvale['backupdir']!='/')
608
  $excludedir[]=trailingslashit(str_replace('\\','/',$jobsvale['backupdir']));
609
  }
610
  return $excludedir;
611
  }
612
+
613
+ //ajax/normal get backup files and infos
614
+ function backwpup_get_backup_files() {
615
+ $jobs=get_option('backwpup_jobs'); //Load jobs
616
+ $filecounter=0;
617
+ $files=array();
618
+ if (extension_loaded('curl') or @dl(PHP_SHLIB_SUFFIX == 'so' ? 'curl.so' : 'php_curl.dll')) {
619
+ if (!class_exists('S3'))
620
+ require_once(plugin_dir_path(__FILE__).'libs/S3.php');
621
+ }
622
+
623
+ if (!is_array($jobs)) //return is Jobs empty
624
+ return false;
625
 
626
+ foreach ($jobs as $jobid => $jobvalue) { //go job by job
627
+ $jobvalue=backwpup_check_job_vars($jobvalue); //Check job values
628
+ $todo=explode('+',$jobvalue['type']); //only for backup jobs
629
+ if (!in_array('FILE',$todo) and !in_array('DB',$todo) and !in_array('WPEXP',$todo))
630
+ continue;
631
+
632
+ //Get files/filinfo in backup folder
633
+ if (!empty($jobvalue['backupdir'])) {
634
+ if ( $dir = @opendir( $jobvalue['backupdir'] ) ) {
635
+ while (($file = readdir( $dir ) ) !== false ) {
636
+ if (substr($file,0,1)=='.' or strtolower(substr($file,-4))=='.zip' or !(strtolower(substr($file,-4))=='.tar' or strtolower(substr($file,-7))=='.tar.gz' or strtolower(substr($file,-4))=='.tar.bz2'))
637
+ continue;
638
+ if (is_file($jobvalue['backupdir'].$file)) {
639
+ $files[$filecounter]['type']='FOLDER';
640
+ $files[$filecounter]['jobid']=$jobid;
641
+ $files[$filecounter]['file']=$jobvalue['backupdir'].$file;
642
+ $files[$filecounter]['filename']=$file;
643
+ $files[$filecounter]['downloadurl']=wp_nonce_url('admin.php?page=BackWPup&action=download&file='.$jobvalue['backupdir'].$file, 'download-backup_'.$file);
644
+ $files[$filecounter]['filesize']=filesize($jobvalue['backupdir'].$file);
645
+ $files[$filecounter]['time']=filemtime($jobvalue['backupdir'].$file);
646
+ $filecounter++;
647
+ }
648
+ }
649
+ closedir( $dir );
650
+ }
651
+ }
652
+ //Get files/filinfo from S3
653
+ if (class_exists('S3')) {
654
+ if (!empty($jobvalue['awsAccessKey']) and !empty($jobvalue['awsSecretKey']) and !empty($jobvalue['awsBucket'])) {
655
+ $s3 = new S3($jobvalue['awsAccessKey'], $jobvalue['awsSecretKey'], $jobvalue['awsSSL']);
656
+ if (($contents = $s3->getBucket($jobvalue['awsBucket'],$jobvalue['awsdir'])) !== false) {
657
+ foreach ($contents as $object) {
658
+ if (strtolower(substr($object['name'],-4))=='.zip' or strtolower(substr($object['name'],-4))=='.tar' or strtolower(substr($object['name'],-7))=='.tar.gz' or strtolower(substr($object['name'],-4))=='.tar.bz2') {
659
+ $files[$filecounter]['type']='S3';
660
+ $files[$filecounter]['jobid']=$jobid;
661
+ $files[$filecounter]['file']=$object['name'];
662
+ $files[$filecounter]['filename']=basename($object['name']);
663
+ $files[$filecounter]['downloadurl']=wp_nonce_url('admin.php?page=BackWPup&action=downloads3&file='.$object['name'].'&jobid='.$jobid, 'downloads3-backup_'.$object['name']);
664
+ $files[$filecounter]['filesize']=$object['size'];
665
+ $files[$filecounter]['time']=$object['time'];
666
+ $filecounter++;
667
+ }
668
+ }
669
+ }
670
+ }
671
+ }
672
+ //Get files/filinfo from FTP
673
+ if (!empty($jobvalue['ftphost']) and !empty($jobvalue['ftpuser']) and !empty($jobvalue['ftppass'])) {
674
+ $ftpport=21;
675
+ $ftphost=$jobvalue['ftphost'];
676
+ if (false !== strpos($jobvalue['ftphost'],':')) //look for port
677
+ list($ftphost,$ftpport)=explode(':',$jobvalue,2);
678
+
679
+ $SSL=false;
680
+ if (function_exists('ftp_ssl_connect')) { //make SSL FTP connection
681
+ $ftp_conn_id = ftp_ssl_connect($ftphost,$ftpport,10);
682
+ if ($ftp_conn_id)
683
+ $SSL=true;
684
+ }
685
+ if (!$ftp_conn_id) { //make normal FTP conection if SSL not work
686
+ $ftp_conn_id = ftp_connect($ftphost,$ftpport,10);
687
+ }
688
+ if ($ftp_conn_id) {
689
+ //FTP Login
690
+ $loginok=false;
691
+ if (@ftp_login($ftp_conn_id, $jobvalue['ftpuser'], base64_decode($jobvalue['ftppass']))) {
692
+ $loginok=true;
693
+ } else { //if PHP ftp login don't work use raw login
694
+ if (substr(trim(ftp_raw($ftp_conn_id,'USER '.$jobvalue['ftpuser'])),0,3)<400) {
695
+ if (substr(trim(ftp_raw($ftp_conn_id,'PASS '.base64_decode($jobvalue['ftppass']))),0,3)<400) {
696
+ $loginok=true;
697
+ }
698
+ }
699
+ }
700
+ }
701
+ if ($loginok) {
702
+ ftp_pasv($ftp_conn_id, true);
703
+ if ($ftpfilelist=ftp_nlist($ftp_conn_id, $jobvalue['ftpdir'])) {
704
+ foreach($ftpfilelist as $ftpfiles) {
705
+ if (basename($ftpfiles)=='.' or basename($ftpfiles)=='..' or substr(basename($ftpfiles),0,1)=='.' or !(strtolower(substr($ftpfiles,-4))=='.zip' or strtolower(substr($ftpfiles,-4))=='.tar' or strtolower(substr($ftpfiles,-7))=='.tar.gz' or strtolower(substr($ftpfiles,-4))=='.tar.bz2'))
706
+ continue;
707
+ $files[$filecounter]['type']='FTP';
708
+ $files[$filecounter]['jobid']=$jobid;
709
+ $files[$filecounter]['file']=$ftpfiles;
710
+ $files[$filecounter]['filename']=basename($ftpfiles);
711
+ $files[$filecounter]['downloadurl']="ftp://".$jobvalue['ftpuser'].":".base64_decode($jobvalue['ftppass'])."@".$jobvalue['ftphost'].$ftpfiles;
712
+ $files[$filecounter]['filesize']=ftp_size($ftp_conn_id,$ftpfiles);
713
+ $filecounter++;
714
+ }
715
+ }
716
+ }
717
+ }
718
+ }
719
+ //Sort list
720
+ $tmp = Array();
721
+ foreach($files as &$ma)
722
+ $tmp[] = &$ma["filename"];
723
+ array_multisort($tmp, SORT_DESC, $files);
724
+ return $files;
725
+ }
726
+
727
  //ajax/normal get buckests select box
728
  function backwpup_get_aws_buckets($args='') {
729
  if (is_array($args)) {
743
  if (empty($awsSecretKey)) {
744
  echo '<span id="awsBucket" style="color:red;">'.__('Missing Secret Access Key!','backwpup').'</span>';
745
  die();
746
+ }
747
  $s3 = new S3($awsAccessKey, $awsSecretKey, false);
748
  $buckets=@$s3->listBuckets();
749
  if (!is_array($buckets)) {
750
  echo '<span id="awsBucket" style="color:red;">'.__('No Buckets found! Or wrong Keys!','backwpup').'</span>';
751
  die();
752
+ }
753
  echo '<select name="awsBucket" id="awsBucket">';
754
  foreach ($buckets as $bucket) {
755
  echo "<option ".selected(strtolower($selected),strtolower($bucket),false).">".$bucket."</option>";
758
  if ($ajax)
759
  die();
760
  }
761
+
762
  // add all action and so on only if plugin loaded.
763
  function backwpup_init() {
764
  //Disabele WP_Corn
768
  //add Menu
769
  add_action('admin_menu', 'backwpup_menu_entry');
770
  //Additional links on the plugin page
771
+ if (current_user_can(10))
772
  add_filter('plugin_action_links_'.BACKWPUP_PLUGIN_BASEDIR.'/backwpup.php', 'backwpup_plugin_options_link');
773
+ if (current_user_can('install_plugins'))
774
  add_filter('plugin_row_meta', 'backwpup_plugin_links',10,2);
775
  //add cron intervals
776
  add_filter('cron_schedules', 'backwpup_intervals');
777
  //Actions for Cron job
778
  add_action('backwpup_cron', 'backwpup_dojob');
779
  //add Dashboard widget
780
+ if (current_user_can(10))
781
  add_action('wp_dashboard_setup', 'backwpup_add_dashboard');
782
  // add ajax function
783
  add_action('wp_ajax_backwpup_get_aws_buckets', 'backwpup_get_aws_buckets');
784
+ }
785
 
786
  ?>
app/libs/S3.php CHANGED
@@ -1,1365 +1,1365 @@
1
- <?php
2
- /**
3
- * $Id: S3.php 47 2009-07-20 01:25:40Z don.schonknecht $
4
- *
5
- * Copyright (c) 2008, Donovan Schönknecht. All rights reserved.
6
- *
7
- * Redistribution and use in source and binary forms, with or without
8
- * modification, are permitted provided that the following conditions are met:
9
- *
10
- * - Redistributions of source code must retain the above copyright notice,
11
- * this list of conditions and the following disclaimer.
12
- * - Redistributions in binary form must reproduce the above copyright
13
- * notice, this list of conditions and the following disclaimer in the
14
- * documentation and/or other materials provided with the distribution.
15
- *
16
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
- * POSSIBILITY OF SUCH DAMAGE.
27
- *
28
- * Amazon S3 is a trademark of Amazon.com, Inc. or its affiliates.
29
- */
30
-
31
- /**
32
- * Amazon S3 PHP class
33
- *
34
- * @link http://undesigned.org.za/2007/10/22/amazon-s3-php-class
35
- * @version 0.4.0
36
- */
37
- class S3 {
38
- // ACL flags
39
- const ACL_PRIVATE = 'private';
40
- const ACL_PUBLIC_READ = 'public-read';
41
- const ACL_PUBLIC_READ_WRITE = 'public-read-write';
42
- const ACL_AUTHENTICATED_READ = 'authenticated-read';
43
-
44
- public static $useSSL = true;
45
-
46
- private static $__accessKey; // AWS Access key
47
- private static $__secretKey; // AWS Secret key
48
-
49
-
50
- /**
51
- * Constructor - if you're not using the class statically
52
- *
53
- * @param string $accessKey Access key
54
- * @param string $secretKey Secret key
55
- * @param boolean $useSSL Enable SSL
56
- * @return void
57
- */
58
- public function __construct($accessKey = null, $secretKey = null, $useSSL = true) {
59
- if ($accessKey !== null && $secretKey !== null)
60
- self::setAuth($accessKey, $secretKey);
61
- self::$useSSL = $useSSL;
62
- }
63
-
64
-
65
- /**
66
- * Set AWS access key and secret key
67
- *
68
- * @param string $accessKey Access key
69
- * @param string $secretKey Secret key
70
- * @return void
71
- */
72
- public static function setAuth($accessKey, $secretKey) {
73
- self::$__accessKey = $accessKey;
74
- self::$__secretKey = $secretKey;
75
- }
76
-
77
-
78
- /**
79
- * Get a list of buckets
80
- *
81
- * @param boolean $detailed Returns detailed bucket list when true
82
- * @return array | false
83
- */
84
- public static function listBuckets($detailed = false) {
85
- $rest = new S3Request('GET', '', '');
86
- $rest = $rest->getResponse();
87
- if ($rest->error === false && $rest->code !== 200)
88
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
89
- if ($rest->error !== false) {
90
- trigger_error(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
91
- return false;
92
- }
93
- $results = array();
94
- if (!isset($rest->body->Buckets)) return $results;
95
-
96
- if ($detailed) {
97
- if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
98
- $results['owner'] = array(
99
- 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID
100
- );
101
- $results['buckets'] = array();
102
- foreach ($rest->body->Buckets->Bucket as $b)
103
- $results['buckets'][] = array(
104
- 'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate)
105
- );
106
- } else
107
- foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name;
108
-
109
- return $results;
110
- }
111
-
112
-
113
- /*
114
- * Get contents for a bucket
115
- *
116
- * If maxKeys is null this method will loop through truncated result sets
117
- *
118
- * @param string $bucket Bucket name
119
- * @param string $prefix Prefix
120
- * @param string $marker Marker (last file listed)
121
- * @param string $maxKeys Max keys (maximum number of keys to return)
122
- * @param string $delimiter Delimiter
123
- * @param boolean $returnCommonPrefixes Set to true to return CommonPrefixes
124
- * @return array | false
125
- */
126
- public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false) {
127
- $rest = new S3Request('GET', $bucket, '');
128
- if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
129
- if ($marker !== null && $marker !== '') $rest->setParameter('marker', $marker);
130
- if ($maxKeys !== null && $maxKeys !== '') $rest->setParameter('max-keys', $maxKeys);
131
- if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
132
- $response = $rest->getResponse();
133
- if ($response->error === false && $response->code !== 200)
134
- $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
135
- if ($response->error !== false) {
136
- trigger_error(sprintf("S3::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING);
137
- return false;
138
- }
139
-
140
- $results = array();
141
-
142
- $nextMarker = null;
143
- if (isset($response->body, $response->body->Contents))
144
- foreach ($response->body->Contents as $c) {
145
- $results[(string)$c->Key] = array(
146
- 'name' => (string)$c->Key,
147
- 'time' => strtotime((string)$c->LastModified),
148
- 'size' => (int)$c->Size,
149
- 'hash' => substr((string)$c->ETag, 1, -1)
150
- );
151
- $nextMarker = (string)$c->Key;
152
- }
153
-
154
- if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
155
- foreach ($response->body->CommonPrefixes as $c)
156
- $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
157
-
158
- if (isset($response->body, $response->body->IsTruncated) &&
159
- (string)$response->body->IsTruncated == 'false') return $results;
160
-
161
- if (isset($response->body, $response->body->NextMarker))
162
- $nextMarker = (string)$response->body->NextMarker;
163
-
164
- // Loop through truncated results if maxKeys isn't specified
165
- if ($maxKeys == null && $nextMarker !== null && (string)$response->body->IsTruncated == 'true')
166
- do {
167
- $rest = new S3Request('GET', $bucket, '');
168
- if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
169
- $rest->setParameter('marker', $nextMarker);
170
- if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
171
-
172
- if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break;
173
-
174
- if (isset($response->body, $response->body->Contents))
175
- foreach ($response->body->Contents as $c) {
176
- $results[(string)$c->Key] = array(
177
- 'name' => (string)$c->Key,
178
- 'time' => strtotime((string)$c->LastModified),
179
- 'size' => (int)$c->Size,
180
- 'hash' => substr((string)$c->ETag, 1, -1)
181
- );
182
- $nextMarker = (string)$c->Key;
183
- }
184
-
185
- if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
186
- foreach ($response->body->CommonPrefixes as $c)
187
- $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
188
-
189
- if (isset($response->body, $response->body->NextMarker))
190
- $nextMarker = (string)$response->body->NextMarker;
191
-
192
- } while ($response !== false && (string)$response->body->IsTruncated == 'true');
193
-
194
- return $results;
195
- }
196
-
197
-
198
- /**
199
- * Put a bucket
200
- *
201
- * @param string $bucket Bucket name
202
- * @param constant $acl ACL flag
203
- * @param string $location Set as "EU" to create buckets hosted in Europe
204
- * @return boolean
205
- */
206
- public static function putBucket($bucket, $acl = self::ACL_PRIVATE, $location = false) {
207
- $rest = new S3Request('PUT', $bucket, '');
208
- $rest->setAmzHeader('x-amz-acl', $acl);
209
-
210
- if ($location !== false) {
211
- $dom = new DOMDocument;
212
- $createBucketConfiguration = $dom->createElement('CreateBucketConfiguration');
213
- $locationConstraint = $dom->createElement('LocationConstraint', strtoupper($location));
214
- $createBucketConfiguration->appendChild($locationConstraint);
215
- $dom->appendChild($createBucketConfiguration);
216
- $rest->data = $dom->saveXML();
217
- $rest->size = strlen($rest->data);
218
- $rest->setHeader('Content-Type', 'application/xml');
219
- }
220
- $rest = $rest->getResponse();
221
-
222
- if ($rest->error === false && $rest->code !== 200)
223
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
224
- if ($rest->error !== false) {
225
- trigger_error(sprintf("S3::putBucket({$bucket}, {$acl}, {$location}): [%s] %s",
226
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
227
- return false;
228
- }
229
- return true;
230
- }
231
-
232
-
233
- /**
234
- * Delete an empty bucket
235
- *
236
- * @param string $bucket Bucket name
237
- * @return boolean
238
- */
239
- public static function deleteBucket($bucket) {
240
- $rest = new S3Request('DELETE', $bucket);
241
- $rest = $rest->getResponse();
242
- if ($rest->error === false && $rest->code !== 204)
243
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
244
- if ($rest->error !== false) {
245
- trigger_error(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
246
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
247
- return false;
248
- }
249
- return true;
250
- }
251
-
252
-
253
- /**
254
- * Create input info array for putObject()
255
- *
256
- * @param string $file Input file
257
- * @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own)
258
- * @return array | false
259
- */
260
- public static function inputFile($file, $md5sum = true) {
261
- if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
262
- trigger_error('S3::inputFile(): Unable to open input file: '.$file, E_USER_WARNING);
263
- return false;
264
- }
265
- return array('file' => $file, 'size' => filesize($file),
266
- 'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum :
267
- base64_encode(md5_file($file, true))) : '');
268
- }
269
-
270
-
271
- /**
272
- * Create input array info for putObject() with a resource
273
- *
274
- * @param string $resource Input resource to read from
275
- * @param integer $bufferSize Input byte size
276
- * @param string $md5sum MD5 hash to send (optional)
277
- * @return array | false
278
- */
279
- public static function inputResource(&$resource, $bufferSize, $md5sum = '') {
280
- if (!is_resource($resource) || $bufferSize < 0) {
281
- trigger_error('S3::inputResource(): Invalid resource or buffer size', E_USER_WARNING);
282
- return false;
283
- }
284
- $input = array('size' => $bufferSize, 'md5sum' => $md5sum);
285
- $input['fp'] =& $resource;
286
- return $input;
287
- }
288
-
289
-
290
- /**
291
- * Put an object
292
- *
293
- * @param mixed $input Input data
294
- * @param string $bucket Bucket name
295
- * @param string $uri Object URI
296
- * @param constant $acl ACL constant
297
- * @param array $metaHeaders Array of x-amz-meta-* headers
298
- * @param array $requestHeaders Array of request headers or content type as a string
299
- * @return boolean
300
- */
301
- public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) {
302
- if ($input === false) return false;
303
- $rest = new S3Request('PUT', $bucket, $uri);
304
-
305
- if (is_string($input)) $input = array(
306
- 'data' => $input, 'size' => strlen($input),
307
- 'md5sum' => base64_encode(md5($input, true))
308
- );
309
-
310
- // Data
311
- if (isset($input['fp']))
312
- $rest->fp =& $input['fp'];
313
- elseif (isset($input['file']))
314
- $rest->fp = @fopen($input['file'], 'rb');
315
- elseif (isset($input['data']))
316
- $rest->data = $input['data'];
317
-
318
- // Content-Length (required)
319
- if (isset($input['size']) && $input['size'] >= 0)
320
- $rest->size = $input['size'];
321
- else {
322
- if (isset($input['file']))
323
- $rest->size = filesize($input['file']);
324
- elseif (isset($input['data']))
325
- $rest->size = strlen($input['data']);
326
- }
327
-
328
- // Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
329
- if (is_array($requestHeaders))
330
- foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
331
- elseif (is_string($requestHeaders)) // Support for legacy contentType parameter
332
- $input['type'] = $requestHeaders;
333
-
334
- // Content-Type
335
- if (!isset($input['type'])) {
336
- if (isset($requestHeaders['Content-Type']))
337
- $input['type'] =& $requestHeaders['Content-Type'];
338
- elseif (isset($input['file']))
339
- $input['type'] = self::__getMimeType($input['file']);
340
- else
341
- $input['type'] = 'application/octet-stream';
342
- }
343
-
344
- // We need to post with Content-Length and Content-Type, MD5 is optional
345
- if ($rest->size >= 0 && ($rest->fp !== false || $rest->data !== false)) {
346
- $rest->setHeader('Content-Type', $input['type']);
347
- if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']);
348
-
349
- $rest->setAmzHeader('x-amz-acl', $acl);
350
- foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
351
- $rest->getResponse();
352
- } else
353
- $rest->response->error = array('code' => 0, 'message' => 'Missing input parameters');
354
-
355
- if ($rest->response->error === false && $rest->response->code !== 200)
356
- $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
357
- if ($rest->response->error !== false) {
358
- trigger_error(sprintf("S3::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
359
- return false;
360
- }
361
- return true;
362
- }
363
-
364
-
365
- /**
366
- * Put an object from a file (legacy function)
367
- *
368
- * @param string $file Input file path
369
- * @param string $bucket Bucket name
370
- * @param string $uri Object URI
371
- * @param constant $acl ACL constant
372
- * @param array $metaHeaders Array of x-amz-meta-* headers
373
- * @param string $contentType Content type
374
- * @return boolean
375
- */
376
- public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
377
- return self::putObject(self::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType);
378
- }
379
-
380
-
381
- /**
382
- * Put an object from a string (legacy function)
383
- *
384
- * @param string $string Input data
385
- * @param string $bucket Bucket name
386
- * @param string $uri Object URI
387
- * @param constant $acl ACL constant
388
- * @param array $metaHeaders Array of x-amz-meta-* headers
389
- * @param string $contentType Content type
390
- * @return boolean
391
- */
392
- public static function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') {
393
- return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType);
394
- }
395
-
396
-
397
- /**
398
- * Get an object
399
- *
400
- * @param string $bucket Bucket name
401
- * @param string $uri Object URI
402
- * @param mixed $saveTo Filename or resource to write to
403
- * @return mixed
404
- */
405
- public static function getObject($bucket, $uri, $saveTo = false) {
406
- $rest = new S3Request('GET', $bucket, $uri);
407
- if ($saveTo !== false) {
408
- if (is_resource($saveTo))
409
- $rest->fp =& $saveTo;
410
- else
411
- if (($rest->fp = @fopen($saveTo, 'wb')) !== false)
412
- $rest->file = realpath($saveTo);
413
- else
414
- $rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
415
- }
416
- if ($rest->response->error === false) $rest->getResponse();
417
-
418
- if ($rest->response->error === false && $rest->response->code !== 200)
419
- $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
420
- if ($rest->response->error !== false) {
421
- trigger_error(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
422
- $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
423
- return false;
424
- }
425
- return $rest->response;
426
- }
427
-
428
-
429
- /**
430
- * Get object information
431
- *
432
- * @param string $bucket Bucket name
433
- * @param string $uri Object URI
434
- * @param boolean $returnInfo Return response information
435
- * @return mixed | false
436
- */
437
- public static function getObjectInfo($bucket, $uri, $returnInfo = true) {
438
- $rest = new S3Request('HEAD', $bucket, $uri);
439
- $rest = $rest->getResponse();
440
- if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404))
441
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
442
- if ($rest->error !== false) {
443
- trigger_error(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
444
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
445
- return false;
446
- }
447
- return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false;
448
- }
449
-
450
-
451
- /**
452
- * Copy an object
453
- *
454
- * @param string $bucket Source bucket name
455
- * @param string $uri Source object URI
456
- * @param string $bucket Destination bucket name
457
- * @param string $uri Destination object URI
458
- * @param constant $acl ACL constant
459
- * @param array $metaHeaders Optional array of x-amz-meta-* headers
460
- * @param array $requestHeaders Optional array of request headers (content type, disposition, etc.)
461
- * @return mixed | false
462
- */
463
- public static function copyObject($srcBucket, $srcUri, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) {
464
- $rest = new S3Request('PUT', $bucket, $uri);
465
- $rest->setHeader('Content-Length', 0);
466
- foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
467
- foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
468
- $rest->setAmzHeader('x-amz-acl', $acl);
469
- $rest->setAmzHeader('x-amz-copy-source', sprintf('/%s/%s', $srcBucket, $srcUri));
470
- if (sizeof($requestHeaders) > 0 || sizeof($metaHeaders) > 0)
471
- $rest->setAmzHeader('x-amz-metadata-directive', 'REPLACE');
472
- $rest = $rest->getResponse();
473
- if ($rest->error === false && $rest->code !== 200)
474
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
475
- if ($rest->error !== false) {
476
- trigger_error(sprintf("S3::copyObject({$srcBucket}, {$srcUri}, {$bucket}, {$uri}): [%s] %s",
477
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
478
- return false;
479
- }
480
- return isset($rest->body->LastModified, $rest->body->ETag) ? array(
481
- 'time' => strtotime((string)$rest->body->LastModified),
482
- 'hash' => substr((string)$rest->body->ETag, 1, -1)
483
- ) : false;
484
- }
485
-
486
-
487
- /**
488
- * Set logging for a bucket
489
- *
490
- * @param string $bucket Bucket name
491
- * @param string $targetBucket Target bucket (where logs are stored)
492
- * @param string $targetPrefix Log prefix (e,g; domain.com-)
493
- * @return boolean
494
- */
495
- public static function setBucketLogging($bucket, $targetBucket, $targetPrefix = null) {
496
- // The S3 log delivery group has to be added to the target bucket's ACP
497
- if ($targetBucket !== null && ($acp = self::getAccessControlPolicy($targetBucket, '')) !== false) {
498
- // Only add permissions to the target bucket when they do not exist
499
- $aclWriteSet = false;
500
- $aclReadSet = false;
501
- foreach ($acp['acl'] as $acl)
502
- if ($acl['type'] == 'Group' && $acl['uri'] == 'http://acs.amazonaws.com/groups/s3/LogDelivery') {
503
- if ($acl['permission'] == 'WRITE') $aclWriteSet = true;
504
- elseif ($acl['permission'] == 'READ_ACP') $aclReadSet = true;
505
- }
506
- if (!$aclWriteSet) $acp['acl'][] = array(
507
- 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'WRITE'
508
- );
509
- if (!$aclReadSet) $acp['acl'][] = array(
510
- 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'READ_ACP'
511
- );
512
- if (!$aclReadSet || !$aclWriteSet) self::setAccessControlPolicy($targetBucket, '', $acp);
513
- }
514
-
515
- $dom = new DOMDocument;
516
- $bucketLoggingStatus = $dom->createElement('BucketLoggingStatus');
517
- $bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
518
- if ($targetBucket !== null) {
519
- if ($targetPrefix == null) $targetPrefix = $bucket . '-';
520
- $loggingEnabled = $dom->createElement('LoggingEnabled');
521
- $loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket));
522
- $loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix));
523
- // TODO: Add TargetGrants?
524
- $bucketLoggingStatus->appendChild($loggingEnabled);
525
- }
526
- $dom->appendChild($bucketLoggingStatus);
527
-
528
- $rest = new S3Request('PUT', $bucket, '');
529
- $rest->setParameter('logging', null);
530
- $rest->data = $dom->saveXML();
531
- $rest->size = strlen($rest->data);
532
- $rest->setHeader('Content-Type', 'application/xml');
533
- $rest = $rest->getResponse();
534
- if ($rest->error === false && $rest->code !== 200)
535
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
536
- if ($rest->error !== false) {
537
- trigger_error(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s",
538
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
539
- return false;
540
- }
541
- return true;
542
- }
543
-
544
-
545
- /**
546
- * Get logging status for a bucket
547
- *
548
- * This will return false if logging is not enabled.
549
- * Note: To enable logging, you also need to grant write access to the log group
550
- *
551
- * @param string $bucket Bucket name
552
- * @return array | false
553
- */
554
- public static function getBucketLogging($bucket) {
555
- $rest = new S3Request('GET', $bucket, '');
556
- $rest->setParameter('logging', null);
557
- $rest = $rest->getResponse();
558
- if ($rest->error === false && $rest->code !== 200)
559
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
560
- if ($rest->error !== false) {
561
- trigger_error(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
562
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
563
- return false;
564
- }
565
- if (!isset($rest->body->LoggingEnabled)) return false; // No logging
566
- return array(
567
- 'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket,
568
- 'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix,
569
- );
570
- }
571
-
572
-
573
- /**
574
- * Disable bucket logging
575
- *
576
- * @param string $bucket Bucket name
577
- * @return boolean
578
- */
579
- public static function disableBucketLogging($bucket) {
580
- return self::setBucketLogging($bucket, null);
581
- }
582
-
583
-
584
- /**
585
- * Get a bucket's location
586
- *
587
- * @param string $bucket Bucket name
588
- * @return string | false
589
- */
590
- public static function getBucketLocation($bucket) {
591
- $rest = new S3Request('GET', $bucket, '');
592
- $rest->setParameter('location', null);
593
- $rest = $rest->getResponse();
594
- if ($rest->error === false && $rest->code !== 200)
595
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
596
- if ($rest->error !== false) {
597
- trigger_error(sprintf("S3::getBucketLocation({$bucket}): [%s] %s",
598
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
599
- return false;
600
- }
601
- return (isset($rest->body[0]) && (string)$rest->body[0] !== '') ? (string)$rest->body[0] : 'US';
602
- }
603
-
604
-
605
- /**
606
- * Set object or bucket Access Control Policy
607
- *
608
- * @param string $bucket Bucket name
609
- * @param string $uri Object URI
610
- * @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy)
611
- * @return boolean
612
- */
613
- public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) {
614
- $dom = new DOMDocument;
615
- $dom->formatOutput = true;
616
- $accessControlPolicy = $dom->createElement('AccessControlPolicy');
617
- $accessControlList = $dom->createElement('AccessControlList');
618
-
619
- // It seems the owner has to be passed along too
620
- $owner = $dom->createElement('Owner');
621
- $owner->appendChild($dom->createElement('ID', $acp['owner']['id']));
622
- $owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name']));
623
- $accessControlPolicy->appendChild($owner);
624
-
625
- foreach ($acp['acl'] as $g) {
626
- $grant = $dom->createElement('Grant');
627
- $grantee = $dom->createElement('Grantee');
628
- $grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
629
- if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted)
630
- $grantee->setAttribute('xsi:type', 'CanonicalUser');
631
- $grantee->appendChild($dom->createElement('ID', $g['id']));
632
- } elseif (isset($g['email'])) { // AmazonCustomerByEmail
633
- $grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail');
634
- $grantee->appendChild($dom->createElement('EmailAddress', $g['email']));
635
- } elseif ($g['type'] == 'Group') { // Group
636
- $grantee->setAttribute('xsi:type', 'Group');
637
- $grantee->appendChild($dom->createElement('URI', $g['uri']));
638
- }
639
- $grant->appendChild($grantee);
640
- $grant->appendChild($dom->createElement('Permission', $g['permission']));
641
- $accessControlList->appendChild($grant);
642
- }
643
-
644
- $accessControlPolicy->appendChild($accessControlList);
645
- $dom->appendChild($accessControlPolicy);
646
-
647
- $rest = new S3Request('PUT', $bucket, $uri);
648
- $rest->setParameter('acl', null);
649
- $rest->data = $dom->saveXML();
650
- $rest->size = strlen($rest->data);
651
- $rest->setHeader('Content-Type', 'application/xml');
652
- $rest = $rest->getResponse();
653
- if ($rest->error === false && $rest->code !== 200)
654
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
655
- if ($rest->error !== false) {
656
- trigger_error(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
657
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
658
- return false;
659
- }
660
- return true;
661
- }
662
-
663
-
664
- /**
665
- * Get object or bucket Access Control Policy
666
- *
667
- * @param string $bucket Bucket name
668
- * @param string $uri Object URI
669
- * @return mixed | false
670
- */
671
- public static function getAccessControlPolicy($bucket, $uri = '') {
672
- $rest = new S3Request('GET', $bucket, $uri);
673
- $rest->setParameter('acl', null);
674
- $rest = $rest->getResponse();
675
- if ($rest->error === false && $rest->code !== 200)
676
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
677
- if ($rest->error !== false) {
678
- trigger_error(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
679
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
680
- return false;
681
- }
682
-
683
- $acp = array();
684
- if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) {
685
- $acp['owner'] = array(
686
- 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName
687
- );
688
- }
689
- if (isset($rest->body->AccessControlList)) {
690
- $acp['acl'] = array();
691
- foreach ($rest->body->AccessControlList->Grant as $grant) {
692
- foreach ($grant->Grantee as $grantee) {
693
- if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser
694
- $acp['acl'][] = array(
695
- 'type' => 'CanonicalUser',
696
- 'id' => (string)$grantee->ID,
697
- 'name' => (string)$grantee->DisplayName,
698
- 'permission' => (string)$grant->Permission
699
- );
700
- elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail
701
- $acp['acl'][] = array(
702
- 'type' => 'AmazonCustomerByEmail',
703
- 'email' => (string)$grantee->EmailAddress,
704
- 'permission' => (string)$grant->Permission
705
- );
706
- elseif (isset($grantee->URI)) // Group
707
- $acp['acl'][] = array(
708
- 'type' => 'Group',
709
- 'uri' => (string)$grantee->URI,
710
- 'permission' => (string)$grant->Permission
711
- );
712
- else continue;
713
- }
714
- }
715
- }
716
- return $acp;
717
- }
718
-
719
-
720
- /**
721
- * Delete an object
722
- *
723
- * @param string $bucket Bucket name
724
- * @param string $uri Object URI
725
- * @return boolean
726
- */
727
- public static function deleteObject($bucket, $uri) {
728
- $rest = new S3Request('DELETE', $bucket, $uri);
729
- $rest = $rest->getResponse();
730
- if ($rest->error === false && $rest->code !== 204)
731
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
732
- if ($rest->error !== false) {
733
- trigger_error(sprintf("S3::deleteObject(): [%s] %s",
734
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
735
- return false;
736
- }
737
- return true;
738
- }
739
-
740
-
741
- /**
742
- * Get a query string authenticated URL
743
- *
744
- * @param string $bucket Bucket name
745
- * @param string $uri Object URI
746
- * @param integer $lifetime Lifetime in seconds
747
- * @param boolean $hostBucket Use the bucket name as the hostname
748
- * @param boolean $https Use HTTPS ($hostBucket should be false for SSL verification)
749
- * @return string
750
- */
751
- public static function getAuthenticatedURL($bucket, $uri, $lifetime, $hostBucket = false, $https = false) {
752
- $expires = time() + $lifetime;
753
- $uri = str_replace('%2F', '/', rawurlencode($uri)); // URI should be encoded (thanks Sean O'Dea)
754
- return sprintf(($https ? 'https' : 'http').'://%s/%s?AWSAccessKeyId=%s&Expires=%u&Signature=%s',
755
- $hostBucket ? $bucket : $bucket.'.s3.amazonaws.com', $uri, self::$__accessKey, $expires,
756
- urlencode(self::__getHash("GET\n\n\n{$expires}\n/{$bucket}/{$uri}")));
757
- }
758
-
759
- /**
760
- * Get upload POST parameters for form uploads
761
- *
762
- * @param string $bucket Bucket name
763
- * @param string $uriPrefix Object URI prefix
764
- * @param constant $acl ACL constant
765
- * @param integer $lifetime Lifetime in seconds
766
- * @param integer $maxFileSize Maximum filesize in bytes (default 5MB)
767
- * @param string $successRedirect Redirect URL or 200 / 201 status code
768
- * @param array $amzHeaders Array of x-amz-meta-* headers
769
- * @param array $headers Array of request headers or content type as a string
770
- * @param boolean $flashVars Includes additional "Filename" variable posted by Flash
771
- * @return object
772
- */
773
- public static function getHttpUploadPostParams($bucket, $uriPrefix = '', $acl = self::ACL_PRIVATE, $lifetime = 3600, $maxFileSize = 5242880, $successRedirect = "201", $amzHeaders = array(), $headers = array(), $flashVars = false) {
774
- // Create policy object
775
- $policy = new stdClass;
776
- $policy->expiration = gmdate('Y-m-d\TH:i:s\Z', (time() + $lifetime));
777
- $policy->conditions = array();
778
- $obj = new stdClass; $obj->bucket = $bucket; array_push($policy->conditions, $obj);
779
- $obj = new stdClass; $obj->acl = $acl; array_push($policy->conditions, $obj);
780
-
781
- $obj = new stdClass; // 200 for non-redirect uploads
782
- if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
783
- $obj->success_action_status = (string)$successRedirect;
784
- else // URL
785
- $obj->success_action_redirect = $successRedirect;
786
- array_push($policy->conditions, $obj);
787
-
788
- array_push($policy->conditions, array('starts-with', '$key', $uriPrefix));
789
- if ($flashVars) array_push($policy->conditions, array('starts-with', '$Filename', ''));
790
- foreach (array_keys($headers) as $headerKey)
791
- array_push($policy->conditions, array('starts-with', '$'.$headerKey, ''));
792
- foreach ($amzHeaders as $headerKey => $headerVal) {
793
- $obj = new stdClass; $obj->{$headerKey} = (string)$headerVal; array_push($policy->conditions, $obj);
794
- }
795
- array_push($policy->conditions, array('content-length-range', 0, $maxFileSize));
796
- $policy = base64_encode(str_replace('\/', '/', json_encode($policy)));
797
-
798
- // Create parameters
799
- $params = new stdClass;
800
- $params->AWSAccessKeyId = self::$__accessKey;
801
- $params->key = $uriPrefix.'${filename}';
802
- $params->acl = $acl;
803
- $params->policy = $policy; unset($policy);
804
- $params->signature = self::__getHash($params->policy);
805
- if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
806
- $params->success_action_status = (string)$successRedirect;
807
- else
808
- $params->success_action_redirect = $successRedirect;
809
- foreach ($headers as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
810
- foreach ($amzHeaders as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
811
- return $params;
812
- }
813
-
814
- /**
815
- * Create a CloudFront distribution
816
- *
817
- * @param string $bucket Bucket name
818
- * @param boolean $enabled Enabled (true/false)
819
- * @param array $cnames Array containing CNAME aliases
820
- * @param string $comment Use the bucket name as the hostname
821
- * @return array | false
822
- */
823
- public static function createDistribution($bucket, $enabled = true, $cnames = array(), $comment = '') {
824
- self::$useSSL = true; // CloudFront requires SSL
825
- $rest = new S3Request('POST', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com');
826
- $rest->data = self::__getCloudFrontDistributionConfigXML($bucket.'.s3.amazonaws.com', $enabled, $comment, (string)microtime(true), $cnames);
827
- $rest->size = strlen($rest->data);
828
- $rest->setHeader('Content-Type', 'application/xml');
829
- $rest = self::__getCloudFrontResponse($rest);
830
-
831
- if ($rest->error === false && $rest->code !== 201)
832
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
833
- if ($rest->error !== false) {
834
- trigger_error(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", '$comment'): [%s] %s",
835
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
836
- return false;
837
- } elseif ($rest->body instanceof SimpleXMLElement)
838
- return self::__parseCloudFrontDistributionConfig($rest->body);
839
- return false;
840
- }
841
-
842
-
843
- /**
844
- * Get CloudFront distribution info
845
- *
846
- * @param string $distributionId Distribution ID from listDistributions()
847
- * @return array | false
848
- */
849
- public static function getDistribution($distributionId) {
850
- self::$useSSL = true; // CloudFront requires SSL
851
- $rest = new S3Request('GET', '', '2008-06-30/distribution/'.$distributionId, 'cloudfront.amazonaws.com');
852
- $rest = self::__getCloudFrontResponse($rest);
853
-
854
- if ($rest->error === false && $rest->code !== 200)
855
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
856
- if ($rest->error !== false) {
857
- trigger_error(sprintf("S3::getDistribution($distributionId): [%s] %s",
858
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
859
- return false;
860
- } elseif ($rest->body instanceof SimpleXMLElement) {
861
- $dist = self::__parseCloudFrontDistributionConfig($rest->body);
862
- $dist['hash'] = $rest->headers['hash'];
863
- return $dist;
864
- }
865
- return false;
866
- }
867
-
868
-
869
- /**
870
- * Update a CloudFront distribution
871
- *
872
- * @param array $dist Distribution array info identical to output of getDistribution()
873
- * @return array | false
874
- */
875
- public static function updateDistribution($dist) {
876
- self::$useSSL = true; // CloudFront requires SSL
877
- $rest = new S3Request('PUT', '', '2008-06-30/distribution/'.$dist['id'].'/config', 'cloudfront.amazonaws.com');
878
- $rest->data = self::__getCloudFrontDistributionConfigXML($dist['origin'], $dist['enabled'], $dist['comment'], $dist['callerReference'], $dist['cnames']);
879
- $rest->size = strlen($rest->data);
880
- $rest->setHeader('If-Match', $dist['hash']);
881
- $rest = self::__getCloudFrontResponse($rest);
882
-
883
- if ($rest->error === false && $rest->code !== 200)
884
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
885
- if ($rest->error !== false) {
886
- trigger_error(sprintf("S3::updateDistribution({$dist['id']}, ".(int)$enabled.", '$comment'): [%s] %s",
887
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
888
- return false;
889
- } else {
890
- $dist = self::__parseCloudFrontDistributionConfig($rest->body);
891
- $dist['hash'] = $rest->headers['hash'];
892
- return $dist;
893
- }
894
- return false;
895
- }
896
-
897
-
898
- /**
899
- * Delete a CloudFront distribution
900
- *
901
- * @param array $dist Distribution array info identical to output of getDistribution()
902
- * @return boolean
903
- */
904
- public static function deleteDistribution($dist) {
905
- self::$useSSL = true; // CloudFront requires SSL
906
- $rest = new S3Request('DELETE', '', '2008-06-30/distribution/'.$dist['id'], 'cloudfront.amazonaws.com');
907
- $rest->setHeader('If-Match', $dist['hash']);
908
- $rest = self::__getCloudFrontResponse($rest);
909
-
910
- if ($rest->error === false && $rest->code !== 204)
911
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
912
- if ($rest->error !== false) {
913
- trigger_error(sprintf("S3::deleteDistribution({$dist['id']}): [%s] %s",
914
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
915
- return false;
916
- }
917
- return true;
918
- }
919
-
920
-
921
- /**
922
- * Get a list of CloudFront distributions
923
- *
924
- * @return array
925
- */
926
- public static function listDistributions() {
927
- self::$useSSL = true; // CloudFront requires SSL
928
- $rest = new S3Request('GET', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com');
929
- $rest = self::__getCloudFrontResponse($rest);
930
-
931
- if ($rest->error === false && $rest->code !== 200)
932
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
933
- if ($rest->error !== false) {
934
- trigger_error(sprintf("S3::listDistributions(): [%s] %s",
935
- $rest->error['code'], $rest->error['message']), E_USER_WARNING);
936
- return false;
937
- } elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary)) {
938
- $list = array();
939
- if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated)) {
940
- //$info['marker'] = (string)$rest->body->Marker;
941
- //$info['maxItems'] = (int)$rest->body->MaxItems;
942
- //$info['isTruncated'] = (string)$rest->body->IsTruncated == 'true' ? true : false;
943
- }
944
- foreach ($rest->body->DistributionSummary as $summary) {
945
- $list[(string)$summary->Id] = self::__parseCloudFrontDistributionConfig($summary);
946
- }
947
- return $list;
948
- }
949
- return array();
950
- }
951
-
952
-
953
- /**
954
- * Get a DistributionConfig DOMDocument
955
- *
956
- * @internal Used to create XML in createDistribution() and updateDistribution()
957
- * @param string $bucket Origin bucket
958
- * @param boolean $enabled Enabled (true/false)
959
- * @param string $comment Comment to append
960
- * @param string $callerReference Caller reference
961
- * @param array $cnames Array of CNAME aliases
962
- * @return string
963
- */
964
- private static function __getCloudFrontDistributionConfigXML($bucket, $enabled, $comment, $callerReference = '0', $cnames = array()) {
965
- $dom = new DOMDocument('1.0', 'UTF-8');
966
- $dom->formatOutput = true;
967
- $distributionConfig = $dom->createElement('DistributionConfig');
968
- $distributionConfig->setAttribute('xmlns', 'http://cloudfront.amazonaws.com/doc/2008-06-30/');
969
- $distributionConfig->appendChild($dom->createElement('Origin', $bucket));
970
- $distributionConfig->appendChild($dom->createElement('CallerReference', $callerReference));
971
- foreach ($cnames as $cname)
972
- $distributionConfig->appendChild($dom->createElement('CNAME', $cname));
973
- if ($comment !== '') $distributionConfig->appendChild($dom->createElement('Comment', $comment));
974
- $distributionConfig->appendChild($dom->createElement('Enabled', $enabled ? 'true' : 'false'));
975
- $dom->appendChild($distributionConfig);
976
- return $dom->saveXML();
977
- }
978
-
979
-
980
- /**
981
- * Parse a CloudFront distribution config
982
- *
983
- * @internal Used to parse the CloudFront DistributionConfig node to an array
984
- * @param object &$node DOMNode
985
- * @return array
986
- */
987
- private static function __parseCloudFrontDistributionConfig(&$node) {
988
- $dist = array();
989
- if (isset($node->Id, $node->Status, $node->LastModifiedTime, $node->DomainName)) {
990
- $dist['id'] = (string)$node->Id;
991
- $dist['status'] = (string)$node->Status;
992
- $dist['time'] = strtotime((string)$node->LastModifiedTime);
993
- $dist['domain'] = (string)$node->DomainName;
994
- }
995
- if (isset($node->CallerReference))
996
- $dist['callerReference'] = (string)$node->CallerReference;
997
- if (isset($node->Comment))
998
- $dist['comment'] = (string)$node->Comment;
999
- if (isset($node->Enabled, $node->Origin)) {
1000
- $dist['origin'] = (string)$node->Origin;
1001
- $dist['enabled'] = (string)$node->Enabled == 'true' ? true : false;
1002
- } elseif (isset($node->DistributionConfig)) {
1003
- $dist = array_merge($dist, self::__parseCloudFrontDistributionConfig($node->DistributionConfig));
1004
- }
1005
- if (isset($node->CNAME)) {
1006
- $dist['cnames'] = array();
1007
- foreach ($node->CNAME as $cname) $dist['cnames'][(string)$cname] = (string)$cname;
1008
- }
1009
- return $dist;
1010
- }
1011
-
1012
-
1013
- /**
1014
- * Grab CloudFront response
1015
- *
1016
- * @internal Used to parse the CloudFront S3Request::getResponse() output
1017
- * @param object &$rest S3Request instance
1018
- * @return object
1019
- */
1020
- private static function __getCloudFrontResponse(&$rest) {
1021
- $rest->getResponse();
1022
- if ($rest->response->error === false && isset($rest->response->body) &&
1023
- is_string($rest->response->body) && substr($rest->response->body, 0, 5) == '<?xml') {
1024
- $rest->response->body = simplexml_load_string($rest->response->body);
1025
- // Grab CloudFront errors
1026
- if (isset($rest->response->body->Error, $rest->response->body->Error->Code,
1027
- $rest->response->body->Error->Message)) {
1028
- $rest->response->error = array(
1029
- 'code' => (string)$rest->response->body->Error->Code,
1030
- 'message' => (string)$rest->response->body->Error->Message
1031
- );
1032
- unset($rest->response->body);
1033
- }
1034
- }
1035
- return $rest->response;
1036
- }
1037
-
1038
-
1039
- /**
1040
- * Get MIME type for file
1041
- *
1042
- * @internal Used to get mime types
1043
- * @param string &$file File path
1044
- * @return string
1045
- */
1046
- public static function __getMimeType(&$file) {
1047
- $type = false;
1048
- // Fileinfo documentation says fileinfo_open() will use the
1049
- // MAGIC env var for the magic file
1050
- if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
1051
- ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) {
1052
- if (($type = finfo_file($finfo, $file)) !== false) {
1053
- // Remove the charset and grab the last content-type
1054
- $type = explode(' ', str_replace('; charset=', ';charset=', $type));
1055
- $type = array_pop($type);
1056
- $type = explode(';', $type);
1057
- $type = trim(array_shift($type));
1058
- }
1059
- finfo_close($finfo);
1060
-
1061
- // If anyone is still using mime_content_type()
1062
- } elseif (function_exists('mime_content_type'))
1063
- $type = trim(mime_content_type($file));
1064
-
1065
- if ($type !== false && strlen($type) > 0) return $type;
1066
-
1067
- // Otherwise do it the old fashioned way
1068
- static $exts = array(
1069
- 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
1070
- 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
1071
- 'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
1072
- 'zip' => 'application/zip', 'gz' => 'application/x-gzip',
1073
- 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
1074
- 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
1075
- 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
1076
- 'css' => 'text/css', 'js' => 'text/javascript',
1077
- 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
1078
- 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
1079
- 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
1080
- 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
1081
- );
1082
- $ext = strtolower(pathInfo($file, PATHINFO_EXTENSION));
1083
- return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
1084
- }
1085
-
1086
-
1087
- /**
1088
- * Generate the auth string: "AWS AccessKey:Signature"
1089
- *
1090
- * @internal Used by S3Request::getResponse()
1091
- * @param string $string String to sign
1092
- * @return string
1093
- */
1094
- public static function __getSignature($string) {
1095
- return 'AWS '.self::$__accessKey.':'.self::__getHash($string);
1096
- }
1097
-
1098
-
1099
- /**
1100
- * Creates a HMAC-SHA1 hash
1101
- *
1102
- * This uses the hash extension if loaded
1103
- *
1104
- * @internal Used by __getSignature()
1105
- * @param string $string String to sign
1106
- * @return string
1107
- */
1108
- private static function __getHash($string) {
1109
- return base64_encode(extension_loaded('hash') ?
1110
- hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
1111
- (str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
1112
- pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00)) ^
1113
- (str_repeat(chr(0x36), 64))) . $string)))));
1114
- }
1115
-
1116
- }
1117
-
1118
- final class S3Request {
1119
- private $verb, $bucket, $uri, $resource = '', $parameters = array(),
1120
- $amzHeaders = array(), $headers = array(
1121
- 'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => ''
1122
- );
1123
- public $fp = false, $size = 0, $data = false, $response;
1124
-
1125
-
1126
- /**
1127
- * Constructor
1128
- *
1129
- * @param string $verb Verb
1130
- * @param string $bucket Bucket name
1131
- * @param string $uri Object URI
1132
- * @return mixed
1133
- */
1134
- function __construct($verb, $bucket = '', $uri = '', $defaultHost = 's3.amazonaws.com') {
1135
- $this->verb = $verb;
1136
- $this->bucket = strtolower($bucket);
1137
- $this->uri = $uri !== '' ? '/'.str_replace('%2F', '/', rawurlencode($uri)) : '/';
1138
-
1139
- if ($this->bucket !== '') {
1140
- $this->headers['Host'] = $this->bucket.'.'.$defaultHost;
1141
- $this->resource = '/'.$this->bucket.$this->uri;
1142
- } else {
1143
- $this->headers['Host'] = $defaultHost;
1144
- //$this->resource = strlen($this->uri) > 1 ? '/'.$this->bucket.$this->uri : $this->uri;
1145
- $this->resource = $this->uri;
1146
- }
1147
- $this->headers['Date'] = gmdate('D, d M Y H:i:s T');
1148
-
1149
- $this->response = new STDClass;
1150
- $this->response->error = false;
1151
- }
1152
-
1153
-
1154
- /**
1155
- * Set request parameter
1156
- *
1157
- * @param string $key Key
1158
- * @param string $value Value
1159
- * @return void
1160
- */
1161
- public function setParameter($key, $value) {
1162
- $this->parameters[$key] = $value;
1163
- }
1164
-
1165
-
1166
- /**
1167
- * Set request header
1168
- *
1169
- * @param string $key Key
1170
- * @param string $value Value
1171
- * @return void
1172
- */
1173
- public function setHeader($key, $value) {
1174
- $this->headers[$key] = $value;
1175
- }
1176
-
1177
-
1178
- /**
1179
- * Set x-amz-meta-* header
1180
- *
1181
- * @param string $key Key
1182
- * @param string $value Value
1183
- * @return void
1184
- */
1185
- public function setAmzHeader($key, $value) {
1186
- $this->amzHeaders[$key] = $value;
1187
- }
1188
-
1189
-
1190
- /**
1191
- * Get the S3 response
1192
- *
1193
- * @return object | false
1194
- */
1195
- public function getResponse() {
1196
- $query = '';
1197
- if (sizeof($this->parameters) > 0) {
1198
- $query = substr($this->uri, -1) !== '?' ? '?' : '&';
1199
- foreach ($this->parameters as $var => $value)
1200
- if ($value == null || $value == '') $query .= $var.'&';
1201
- // Parameters should be encoded (thanks Sean O'Dea)
1202
- else $query .= $var.'='.rawurlencode($value).'&';
1203
- $query = substr($query, 0, -1);
1204
- $this->uri .= $query;
1205
-
1206
- if (array_key_exists('acl', $this->parameters) ||
1207
- array_key_exists('location', $this->parameters) ||
1208
- array_key_exists('torrent', $this->parameters) ||
1209
- array_key_exists('logging', $this->parameters))
1210
- $this->resource .= $query;
1211
- }
1212
- $url = ((S3::$useSSL && extension_loaded('openssl')) ?
1213
- 'https://':'http://').$this->headers['Host'].$this->uri;
1214
- //var_dump($this->bucket, $this->uri, $this->resource, $url);
1215
-
1216
- // Basic setup
1217
- $curl = curl_init();
1218
- curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php');
1219
-
1220
- if (S3::$useSSL) {
1221
- curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);
1222
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
1223
- }
1224
-
1225
- curl_setopt($curl, CURLOPT_URL, $url);
1226
-
1227
- // Headers
1228
- $headers = array(); $amz = array();
1229
- foreach ($this->amzHeaders as $header => $value)
1230
- if (strlen($value) > 0) $headers[] = $header.': '.$value;
1231
- foreach ($this->headers as $header => $value)
1232
- if (strlen($value) > 0) $headers[] = $header.': '.$value;
1233
-
1234
- // Collect AMZ headers for signature
1235
- foreach ($this->amzHeaders as $header => $value)
1236
- if (strlen($value) > 0) $amz[] = strtolower($header).':'.$value;
1237
-
1238
- // AMZ headers must be sorted
1239
- if (sizeof($amz) > 0) {
1240
- sort($amz);
1241
- $amz = "\n".implode("\n", $amz);
1242
- } else $amz = '';
1243
-
1244
- // Authorization string (CloudFront stringToSign should only contain a date)
1245
- $headers[] = 'Authorization: ' . S3::__getSignature(
1246
- $this->headers['Host'] == 'cloudfront.amazonaws.com' ? $this->headers['Date'] :
1247
- $this->verb."\n".$this->headers['Content-MD5']."\n".
1248
- $this->headers['Content-Type']."\n".$this->headers['Date'].$amz."\n".$this->resource
1249
- );
1250
-
1251
- curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
1252
- curl_setopt($curl, CURLOPT_HEADER, false);
1253
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
1254
- curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
1255
- curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback'));
1256
- //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
1257
-
1258
- // Request types
1259
- switch ($this->verb) {
1260
- case 'GET': break;
1261
- case 'PUT': case 'POST': // POST only used for CloudFront
1262
- if ($this->fp !== false) {
1263
- curl_setopt($curl, CURLOPT_PUT, true);
1264
- curl_setopt($curl, CURLOPT_INFILE, $this->fp);
1265
- if ($this->size >= 0)
1266
- curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
1267
- } elseif ($this->data !== false) {
1268
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
1269
- curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
1270
- if ($this->size >= 0)
1271
- curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size);
1272
- } else
1273
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
1274
- break;
1275
- case 'HEAD':
1276
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
1277
- curl_setopt($curl, CURLOPT_NOBODY, true);
1278
- break;
1279
- case 'DELETE':
1280
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
1281
- break;
1282
- default: break;
1283
- }
1284
-
1285
- // Execute, grab errors
1286
- if (curl_exec($curl))
1287
- $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
1288
- else
1289
- $this->response->error = array(
1290
- 'code' => curl_errno($curl),
1291
- 'message' => curl_error($curl),
1292
- 'resource' => $this->resource
1293
- );
1294
-
1295
- @curl_close($curl);
1296
-
1297
- // Parse body into XML
1298
- if ($this->response->error === false && isset($this->response->headers['type']) &&
1299
- $this->response->headers['type'] == 'application/xml' && isset($this->response->body)) {
1300
- $this->response->body = simplexml_load_string($this->response->body);
1301
-
1302
- // Grab S3 errors
1303
- if (!in_array($this->response->code, array(200, 204)) &&
1304
- isset($this->response->body->Code, $this->response->body->Message)) {
1305
- $this->response->error = array(
1306
- 'code' => (string)$this->response->body->Code,
1307
- 'message' => (string)$this->response->body->Message
1308
- );
1309
- if (isset($this->response->body->Resource))
1310
- $this->response->error['resource'] = (string)$this->response->body->Resource;
1311
- unset($this->response->body);
1312
- }
1313
- }
1314
-
1315
- // Clean up file resources
1316
- if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp);
1317
-
1318
- return $this->response;
1319
- }
1320
-
1321
-
1322
- /**
1323
- * CURL write callback
1324
- *
1325
- * @param resource &$curl CURL resource
1326
- * @param string &$data Data
1327
- * @return integer
1328
- */
1329
- private function __responseWriteCallback(&$curl, &$data) {
1330
- if ($this->response->code == 200 && $this->fp !== false)
1331
- return fwrite($this->fp, $data);
1332
- else
1333
- $this->response->body .= $data;
1334
- return strlen($data);
1335
- }
1336
-
1337
-
1338
- /**
1339
- * CURL header callback
1340
- *
1341
- * @param resource &$curl CURL resource
1342
- * @param string &$data Data
1343
- * @return integer
1344
- */
1345
- private function __responseHeaderCallback(&$curl, &$data) {
1346
- if (($strlen = strlen($data)) <= 2) return $strlen;
1347
- if (substr($data, 0, 4) == 'HTTP')
1348
- $this->response->code = (int)substr($data, 9, 3);
1349
- else {
1350
- list($header, $value) = explode(': ', trim($data), 2);
1351
- if ($header == 'Last-Modified')
1352
- $this->response->headers['time'] = strtotime($value);
1353
- elseif ($header == 'Content-Length')
1354
- $this->response->headers['size'] = (int)$value;
1355
- elseif ($header == 'Content-Type')
1356
- $this->response->headers['type'] = $value;
1357
- elseif ($header == 'ETag')
1358
- $this->response->headers['hash'] = $value{0} == '"' ? substr($value, 1, -1) : $value;
1359
- elseif (preg_match('/^x-amz-meta-.*$/', $header))
1360
- $this->response->headers[$header] = is_numeric($value) ? (int)$value : $value;
1361
- }
1362
- return $strlen;
1363
- }
1364
-
1365
- }
1
+ <?php
2
+ /**
3
+ * $Id: S3.php 47 2009-07-20 01:25:40Z don.schonknecht $
4
+ *
5
+ * Copyright (c) 2008, Donovan Schönknecht. All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * - Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * - Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ * POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ * Amazon S3 is a trademark of Amazon.com, Inc. or its affiliates.
29
+ */
30
+
31
+ /**
32
+ * Amazon S3 PHP class
33
+ *
34
+ * @link http://undesigned.org.za/2007/10/22/amazon-s3-php-class
35
+ * @version 0.4.0
36
+ */
37
+ class S3 {
38
+ // ACL flags
39
+ const ACL_PRIVATE = 'private';
40
+ const ACL_PUBLIC_READ = 'public-read';
41
+ const ACL_PUBLIC_READ_WRITE = 'public-read-write';
42
+ const ACL_AUTHENTICATED_READ = 'authenticated-read';
43
+
44
+ public static $useSSL = true;
45
+
46
+ private static $__accessKey; // AWS Access key
47
+ private static $__secretKey; // AWS Secret key
48
+
49
+
50
+ /**
51
+ * Constructor - if you're not using the class statically
52
+ *
53
+ * @param string $accessKey Access key
54
+ * @param string $secretKey Secret key
55
+ * @param boolean $useSSL Enable SSL
56
+ * @return void
57
+ */
58
+ public function __construct($accessKey = null, $secretKey = null, $useSSL = true) {
59
+ if ($accessKey !== null && $secretKey !== null)
60
+ self::setAuth($accessKey, $secretKey);
61
+ self::$useSSL = $useSSL;
62
+ }
63
+
64
+
65
+ /**
66
+ * Set AWS access key and secret key
67
+ *
68
+ * @param string $accessKey Access key
69
+ * @param string $secretKey Secret key
70
+ * @return void
71
+ */
72
+ public static function setAuth($accessKey, $secretKey) {
73
+ self::$__accessKey = $accessKey;
74
+ self::$__secretKey = $secretKey;
75
+ }
76
+
77
+
78
+ /**
79
+ * Get a list of buckets
80
+ *
81
+ * @param boolean $detailed Returns detailed bucket list when true
82
+ * @return array | false
83
+ */
84
+ public static function listBuckets($detailed = false) {
85
+ $rest = new S3Request('GET', '', '');
86
+ $rest = $rest->getResponse();
87
+ if ($rest->error === false && $rest->code !== 200)
88
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
89
+ if ($rest->error !== false) {
90
+ trigger_error(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
91
+ return false;
92
+ }
93
+ $results = array();
94
+ if (!isset($rest->body->Buckets)) return $results;
95
+
96
+ if ($detailed) {
97
+ if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
98
+ $results['owner'] = array(
99
+ 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID
100
+ );
101
+ $results['buckets'] = array();
102
+ foreach ($rest->body->Buckets->Bucket as $b)
103
+ $results['buckets'][] = array(
104
+ 'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate)
105
+ );
106
+ } else
107
+ foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name;
108
+
109
+ return $results;
110
+ }
111
+
112
+
113
+ /*
114
+ * Get contents for a bucket
115
+ *
116
+ * If maxKeys is null this method will loop through truncated result sets
117
+ *
118
+ * @param string $bucket Bucket name
119
+ * @param string $prefix Prefix
120
+ * @param string $marker Marker (last file listed)
121
+ * @param string $maxKeys Max keys (maximum number of keys to return)
122
+ * @param string $delimiter Delimiter
123
+ * @param boolean $returnCommonPrefixes Set to true to return CommonPrefixes
124
+ * @return array | false
125
+ */
126
+ public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false) {
127
+ $rest = new S3Request('GET', $bucket, '');
128
+ if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
129
+ if ($marker !== null && $marker !== '') $rest->setParameter('marker', $marker);
130
+ if ($maxKeys !== null && $maxKeys !== '') $rest->setParameter('max-keys', $maxKeys);
131
+ if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
132
+ $response = $rest->getResponse();
133
+ if ($response->error === false && $response->code !== 200)
134
+ $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
135
+ if ($response->error !== false) {
136
+ trigger_error(sprintf("S3::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING);
137
+ return false;
138
+ }
139
+
140
+ $results = array();
141
+
142
+ $nextMarker = null;
143
+ if (isset($response->body, $response->body->Contents))
144
+ foreach ($response->body->Contents as $c) {
145
+ $results[(string)$c->Key] = array(
146
+ 'name' => (string)$c->Key,
147
+ 'time' => strtotime((string)$c->LastModified),
148
+ 'size' => (int)$c->Size,
149
+ 'hash' => substr((string)$c->ETag, 1, -1)
150
+ );
151
+ $nextMarker = (string)$c->Key;
152
+ }
153
+
154
+ if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
155
+ foreach ($response->body->CommonPrefixes as $c)
156
+ $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
157
+
158
+ if (isset($response->body, $response->body->IsTruncated) &&
159
+ (string)$response->body->IsTruncated == 'false') return $results;
160
+
161
+ if (isset($response->body, $response->body->NextMarker))
162
+ $nextMarker = (string)$response->body->NextMarker;
163
+
164
+ // Loop through truncated results if maxKeys isn't specified
165
+ if ($maxKeys == null && $nextMarker !== null && (string)$response->body->IsTruncated == 'true')
166
+ do {
167
+ $rest = new S3Request('GET', $bucket, '');
168
+ if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
169
+ $rest->setParameter('marker', $nextMarker);
170
+ if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
171
+
172
+ if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break;
173
+
174
+ if (isset($response->body, $response->body->Contents))
175
+ foreach ($response->body->Contents as $c) {
176
+ $results[(string)$c->Key] = array(
177
+ 'name' => (string)$c->Key,
178
+ 'time' => strtotime((string)$c->LastModified),
179
+ 'size' => (int)$c->Size,
180
+ 'hash' => substr((string)$c->ETag, 1, -1)
181
+ );
182
+ $nextMarker = (string)$c->Key;
183
+ }
184
+
185
+ if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
186
+ foreach ($response->body->CommonPrefixes as $c)
187
+ $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
188
+
189
+ if (isset($response->body, $response->body->NextMarker))
190
+ $nextMarker = (string)$response->body->NextMarker;
191
+
192
+ } while ($response !== false && (string)$response->body->IsTruncated == 'true');
193
+
194
+ return $results;
195
+ }
196
+
197
+
198
+ /**
199
+ * Put a bucket
200
+ *
201
+ * @param string $bucket Bucket name
202
+ * @param constant $acl ACL flag
203
+ * @param string $location Set as "EU" to create buckets hosted in Europe
204
+ * @return boolean
205
+ */
206
+ public static function putBucket($bucket, $acl = self::ACL_PRIVATE, $location = false) {
207
+ $rest = new S3Request('PUT', $bucket, '');
208
+ $rest->setAmzHeader('x-amz-acl', $acl);
209
+
210
+ if ($location !== false) {
211
+ $dom = new DOMDocument;
212
+ $createBucketConfiguration = $dom->createElement('CreateBucketConfiguration');
213
+ $locationConstraint = $dom->createElement('LocationConstraint', strtoupper($location));
214
+ $createBucketConfiguration->appendChild($locationConstraint);
215
+ $dom->appendChild($createBucketConfiguration);
216
+ $rest->data = $dom->saveXML();
217
+ $rest->size = strlen($rest->data);
218
+ $rest->setHeader('Content-Type', 'application/xml');
219
+ }
220
+ $rest = $rest->getResponse();
221
+
222
+ if ($rest->error === false && $rest->code !== 200)
223
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
224
+ if ($rest->error !== false) {
225
+ trigger_error(sprintf("S3::putBucket({$bucket}, {$acl}, {$location}): [%s] %s",
226
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
227
+ return false;
228
+ }
229
+ return true;
230
+ }
231
+
232
+
233
+ /**
234
+ * Delete an empty bucket
235
+ *
236
+ * @param string $bucket Bucket name
237
+ * @return boolean
238
+ */
239
+ public static function deleteBucket($bucket) {
240
+ $rest = new S3Request('DELETE', $bucket);
241
+ $rest = $rest->getResponse();
242
+ if ($rest->error === false && $rest->code !== 204)
243
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
244
+ if ($rest->error !== false) {
245
+ trigger_error(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
246
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
247
+ return false;
248
+ }
249
+ return true;
250
+ }
251
+
252
+
253
+ /**
254
+ * Create input info array for putObject()
255
+ *
256
+ * @param string $file Input file
257
+ * @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own)
258
+ * @return array | false
259
+ */
260
+ public static function inputFile($file, $md5sum = true) {
261
+ if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
262
+ trigger_error('S3::inputFile(): Unable to open input file: '.$file, E_USER_WARNING);
263
+ return false;
264
+ }
265
+ return array('file' => $file, 'size' => filesize($file),
266
+ 'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum :
267
+ base64_encode(md5_file($file, true))) : '');
268
+ }
269
+
270
+
271
+ /**
272
+ * Create input array info for putObject() with a resource
273
+ *
274
+ * @param string $resource Input resource to read from
275
+ * @param integer $bufferSize Input byte size
276
+ * @param string $md5sum MD5 hash to send (optional)
277
+ * @return array | false
278
+ */
279
+ public static function inputResource(&$resource, $bufferSize, $md5sum = '') {
280
+ if (!is_resource($resource) || $bufferSize < 0) {
281
+ trigger_error('S3::inputResource(): Invalid resource or buffer size', E_USER_WARNING);
282
+ return false;
283
+ }
284
+ $input = array('size' => $bufferSize, 'md5sum' => $md5sum);
285
+ $input['fp'] =& $resource;
286
+ return $input;
287
+ }
288
+
289
+
290
+ /**
291
+ * Put an object
292
+ *
293
+ * @param mixed $input Input data
294
+ * @param string $bucket Bucket name
295
+ * @param string $uri Object URI
296
+ * @param constant $acl ACL constant
297
+ * @param array $metaHeaders Array of x-amz-meta-* headers
298
+ * @param array $requestHeaders Array of request headers or content type as a string
299
+ * @return boolean
300
+ */
301
+ public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) {
302
+ if ($input === false) return false;
303
+ $rest = new S3Request('PUT', $bucket, $uri);
304
+
305
+ if (is_string($input)) $input = array(
306
+ 'data' => $input, 'size' => strlen($input),
307
+ 'md5sum' => base64_encode(md5($input, true))
308
+ );
309
+
310
+ // Data
311
+ if (isset($input['fp']))
312
+ $rest->fp =& $input['fp'];
313
+ elseif (isset($input['file']))
314
+ $rest->fp = @fopen($input['file'], 'rb');
315
+ elseif (isset($input['data']))
316
+ $rest->data = $input['data'];
317
+
318
+ // Content-Length (required)
319
+ if (isset($input['size']) && $input['size'] >= 0)
320
+ $rest->size = $input['size'];
321
+ else {
322
+ if (isset($input['file']))
323
+ $rest->size = filesize($input['file']);
324
+ elseif (isset($input['data']))
325
+ $rest->size = strlen($input['data']);
326
+ }
327
+
328
+ // Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
329
+ if (is_array($requestHeaders))
330
+ foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
331
+ elseif (is_string($requestHeaders)) // Support for legacy contentType parameter
332
+ $input['type'] = $requestHeaders;
333
+
334
+ // Content-Type
335
+ if (!isset($input['type'])) {
336
+ if (isset($requestHeaders['Content-Type']))
337
+ $input['type'] =& $requestHeaders['Content-Type'];
338
+ elseif (isset($input['file']))
339
+ $input['type'] = self::__getMimeType($input['file']);
340
+ else
341
+ $input['type'] = 'application/octet-stream';
342
+ }
343
+
344
+ // We need to post with Content-Length and Content-Type, MD5 is optional
345
+ if ($rest->size >= 0 && ($rest->fp !== false || $rest->data !== false)) {
346
+ $rest->setHeader('Content-Type', $input['type']);
347
+ if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']);
348
+
349
+ $rest->setAmzHeader('x-amz-acl', $acl);
350
+ foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
351
+ $rest->getResponse();
352
+ } else
353
+ $rest->response->error = array('code' => 0, 'message' => 'Missing input parameters');
354
+
355
+ if ($rest->response->error === false && $rest->response->code !== 200)
356
+ $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
357
+ if ($rest->response->error !== false) {
358
+ trigger_error(sprintf("S3::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
359
+ return false;
360
+ }
361
+ return true;
362
+ }
363
+
364
+
365
+ /**
366
+ * Put an object from a file (legacy function)
367
+ *
368
+ * @param string $file Input file path
369
+ * @param string $bucket Bucket name
370
+ * @param string $uri Object URI
371
+ * @param constant $acl ACL constant
372
+ * @param array $metaHeaders Array of x-amz-meta-* headers
373
+ * @param string $contentType Content type
374
+ * @return boolean
375
+ */
376
+ public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
377
+ return self::putObject(self::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType);
378
+ }
379
+
380
+
381
+ /**
382
+ * Put an object from a string (legacy function)
383
+ *
384
+ * @param string $string Input data
385
+ * @param string $bucket Bucket name
386
+ * @param string $uri Object URI
387
+ * @param constant $acl ACL constant
388
+ * @param array $metaHeaders Array of x-amz-meta-* headers
389
+ * @param string $contentType Content type
390
+ * @return boolean
391
+ */
392
+ public static function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') {
393
+ return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType);
394
+ }
395
+
396
+
397
+ /**
398
+ * Get an object
399
+ *
400
+ * @param string $bucket Bucket name
401
+ * @param string $uri Object URI
402
+ * @param mixed $saveTo Filename or resource to write to
403
+ * @return mixed
404
+ */
405
+ public static function getObject($bucket, $uri, $saveTo = false) {
406
+ $rest = new S3Request('GET', $bucket, $uri);
407
+ if ($saveTo !== false) {
408
+ if (is_resource($saveTo))
409
+ $rest->fp =& $saveTo;
410
+ else
411
+ if (($rest->fp = @fopen($saveTo, 'wb')) !== false)
412
+ $rest->file = realpath($saveTo);
413
+ else
414
+ $rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
415
+ }
416
+ if ($rest->response->error === false) $rest->getResponse();
417
+
418
+ if ($rest->response->error === false && $rest->response->code !== 200)
419
+ $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
420
+ if ($rest->response->error !== false) {
421
+ trigger_error(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
422
+ $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
423
+ return false;
424
+ }
425
+ return $rest->response;
426
+ }
427
+
428
+
429
+ /**
430
+ * Get object information
431
+ *
432
+ * @param string $bucket Bucket name
433
+ * @param string $uri Object URI
434
+ * @param boolean $returnInfo Return response information
435
+ * @return mixed | false
436
+ */
437
+ public static function getObjectInfo($bucket, $uri, $returnInfo = true) {
438
+ $rest = new S3Request('HEAD', $bucket, $uri);
439
+ $rest = $rest->getResponse();
440
+ if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404))
441
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
442
+ if ($rest->error !== false) {
443
+ trigger_error(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
444
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
445
+ return false;
446
+ }
447
+ return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false;
448
+ }
449
+
450
+
451
+ /**
452
+ * Copy an object
453
+ *
454
+ * @param string $bucket Source bucket name
455
+ * @param string $uri Source object URI
456
+ * @param string $bucket Destination bucket name
457
+ * @param string $uri Destination object URI
458
+ * @param constant $acl ACL constant
459
+ * @param array $metaHeaders Optional array of x-amz-meta-* headers
460
+ * @param array $requestHeaders Optional array of request headers (content type, disposition, etc.)
461
+ * @return mixed | false
462
+ */
463
+ public static function copyObject($srcBucket, $srcUri, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) {
464
+ $rest = new S3Request('PUT', $bucket, $uri);
465
+ $rest->setHeader('Content-Length', 0);
466
+ foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
467
+ foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
468
+ $rest->setAmzHeader('x-amz-acl', $acl);
469
+ $rest->setAmzHeader('x-amz-copy-source', sprintf('/%s/%s', $srcBucket, $srcUri));
470
+ if (sizeof($requestHeaders) > 0 || sizeof($metaHeaders) > 0)
471
+ $rest->setAmzHeader('x-amz-metadata-directive', 'REPLACE');
472
+ $rest = $rest->getResponse();
473
+ if ($rest->error === false && $rest->code !== 200)
474
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
475
+ if ($rest->error !== false) {
476
+ trigger_error(sprintf("S3::copyObject({$srcBucket}, {$srcUri}, {$bucket}, {$uri}): [%s] %s",
477
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
478
+ return false;
479
+ }
480
+ return isset($rest->body->LastModified, $rest->body->ETag) ? array(
481
+ 'time' => strtotime((string)$rest->body->LastModified),
482
+ 'hash' => substr((string)$rest->body->ETag, 1, -1)
483
+ ) : false;
484
+ }
485
+
486
+
487
+ /**
488
+ * Set logging for a bucket
489
+ *
490
+ * @param string $bucket Bucket name
491
+ * @param string $targetBucket Target bucket (where logs are stored)
492
+ * @param string $targetPrefix Log prefix (e,g; domain.com-)
493
+ * @return boolean
494
+ */
495
+ public static function setBucketLogging($bucket, $targetBucket, $targetPrefix = null) {
496
+ // The S3 log delivery group has to be added to the target bucket's ACP
497
+ if ($targetBucket !== null && ($acp = self::getAccessControlPolicy($targetBucket, '')) !== false) {
498
+ // Only add permissions to the target bucket when they do not exist
499
+ $aclWriteSet = false;
500
+ $aclReadSet = false;
501
+ foreach ($acp['acl'] as $acl)
502
+ if ($acl['type'] == 'Group' && $acl['uri'] == 'http://acs.amazonaws.com/groups/s3/LogDelivery') {
503
+ if ($acl['permission'] == 'WRITE') $aclWriteSet = true;
504
+ elseif ($acl['permission'] == 'READ_ACP') $aclReadSet = true;
505
+ }
506
+ if (!$aclWriteSet) $acp['acl'][] = array(
507
+ 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'WRITE'
508
+ );
509
+ if (!$aclReadSet) $acp['acl'][] = array(
510
+ 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'READ_ACP'
511
+ );
512
+ if (!$aclReadSet || !$aclWriteSet) self::setAccessControlPolicy($targetBucket, '', $acp);
513
+ }
514
+
515
+ $dom = new DOMDocument;
516
+ $bucketLoggingStatus = $dom->createElement('BucketLoggingStatus');
517
+ $bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
518
+ if ($targetBucket !== null) {
519
+ if ($targetPrefix == null) $targetPrefix = $bucket . '-';
520
+ $loggingEnabled = $dom->createElement('LoggingEnabled');
521
+ $loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket));
522
+ $loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix));
523
+ // TODO: Add TargetGrants?
524
+ $bucketLoggingStatus->appendChild($loggingEnabled);
525
+ }
526
+ $dom->appendChild($bucketLoggingStatus);
527
+
528
+ $rest = new S3Request('PUT', $bucket, '');
529
+ $rest->setParameter('logging', null);
530
+ $rest->data = $dom->saveXML();
531
+ $rest->size = strlen($rest->data);
532
+ $rest->setHeader('Content-Type', 'application/xml');
533
+ $rest = $rest->getResponse();
534
+ if ($rest->error === false && $rest->code !== 200)
535
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
536
+ if ($rest->error !== false) {
537
+ trigger_error(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s",
538
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
539
+ return false;
540
+ }
541
+ return true;
542
+ }
543
+
544
+
545
+ /**
546
+ * Get logging status for a bucket
547
+ *
548
+ * This will return false if logging is not enabled.
549
+ * Note: To enable logging, you also need to grant write access to the log group
550
+ *
551
+ * @param string $bucket Bucket name
552
+ * @return array | false
553
+ */
554
+ public static function getBucketLogging($bucket) {
555
+ $rest = new S3Request('GET', $bucket, '');
556
+ $rest->setParameter('logging', null);
557
+ $rest = $rest->getResponse();
558
+ if ($rest->error === false && $rest->code !== 200)
559
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
560
+ if ($rest->error !== false) {
561
+ trigger_error(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
562
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
563
+ return false;
564
+ }
565
+ if (!isset($rest->body->LoggingEnabled)) return false; // No logging
566
+ return array(
567
+ 'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket,
568
+ 'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix,
569
+ );
570
+ }
571
+
572
+
573
+ /**
574
+ * Disable bucket logging
575
+ *
576
+ * @param string $bucket Bucket name
577
+ * @return boolean
578
+ */
579
+ public static function disableBucketLogging($bucket) {
580
+ return self::setBucketLogging($bucket, null);
581
+ }
582
+
583
+
584
+ /**
585
+ * Get a bucket's location
586
+ *
587
+ * @param string $bucket Bucket name
588
+ * @return string | false
589
+ */
590
+ public static function getBucketLocation($bucket) {
591
+ $rest = new S3Request('GET', $bucket, '');
592
+ $rest->setParameter('location', null);
593
+ $rest = $rest->getResponse();
594
+ if ($rest->error === false && $rest->code !== 200)
595
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
596
+ if ($rest->error !== false) {
597
+ trigger_error(sprintf("S3::getBucketLocation({$bucket}): [%s] %s",
598
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
599
+ return false;
600
+ }
601
+ return (isset($rest->body[0]) && (string)$rest->body[0] !== '') ? (string)$rest->body[0] : 'US';
602
+ }
603
+
604
+
605
+ /**
606
+ * Set object or bucket Access Control Policy
607
+ *
608
+ * @param string $bucket Bucket name
609
+ * @param string $uri Object URI
610
+ * @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy)
611
+ * @return boolean
612
+ */
613
+ public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) {
614
+ $dom = new DOMDocument;
615
+ $dom->formatOutput = true;
616
+ $accessControlPolicy = $dom->createElement('AccessControlPolicy');
617
+ $accessControlList = $dom->createElement('AccessControlList');
618
+
619
+ // It seems the owner has to be passed along too
620
+ $owner = $dom->createElement('Owner');
621
+ $owner->appendChild($dom->createElement('ID', $acp['owner']['id']));
622
+ $owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name']));
623
+ $accessControlPolicy->appendChild($owner);
624
+
625
+ foreach ($acp['acl'] as $g) {
626
+ $grant = $dom->createElement('Grant');
627
+ $grantee = $dom->createElement('Grantee');
628
+ $grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
629
+ if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted)
630
+ $grantee->setAttribute('xsi:type', 'CanonicalUser');
631
+ $grantee->appendChild($dom->createElement('ID', $g['id']));
632
+ } elseif (isset($g['email'])) { // AmazonCustomerByEmail
633
+ $grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail');
634
+ $grantee->appendChild($dom->createElement('EmailAddress', $g['email']));
635
+ } elseif ($g['type'] == 'Group') { // Group
636
+ $grantee->setAttribute('xsi:type', 'Group');
637
+ $grantee->appendChild($dom->createElement('URI', $g['uri']));
638
+ }
639
+ $grant->appendChild($grantee);
640
+ $grant->appendChild($dom->createElement('Permission', $g['permission']));
641
+ $accessControlList->appendChild($grant);
642
+ }
643
+
644
+ $accessControlPolicy->appendChild($accessControlList);
645
+ $dom->appendChild($accessControlPolicy);
646
+
647
+ $rest = new S3Request('PUT', $bucket, $uri);
648
+ $rest->setParameter('acl', null);
649
+ $rest->data = $dom->saveXML();
650
+ $rest->size = strlen($rest->data);
651
+ $rest->setHeader('Content-Type', 'application/xml');
652
+ $rest = $rest->getResponse();
653
+ if ($rest->error === false && $rest->code !== 200)
654
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
655
+ if ($rest->error !== false) {
656
+ trigger_error(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
657
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
658
+ return false;
659
+ }
660
+ return true;
661
+ }
662
+
663
+
664
+ /**
665
+ * Get object or bucket Access Control Policy
666
+ *
667
+ * @param string $bucket Bucket name
668
+ * @param string $uri Object URI
669
+ * @return mixed | false
670
+ */
671
+ public static function getAccessControlPolicy($bucket, $uri = '') {
672
+ $rest = new S3Request('GET', $bucket, $uri);
673
+ $rest->setParameter('acl', null);
674
+ $rest = $rest->getResponse();
675
+ if ($rest->error === false && $rest->code !== 200)
676
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
677
+ if ($rest->error !== false) {
678
+ trigger_error(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
679
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
680
+ return false;
681
+ }
682
+
683
+ $acp = array();
684
+ if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) {
685
+ $acp['owner'] = array(
686
+ 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName
687
+ );
688
+ }
689
+ if (isset($rest->body->AccessControlList)) {
690
+ $acp['acl'] = array();
691
+ foreach ($rest->body->AccessControlList->Grant as $grant) {
692
+ foreach ($grant->Grantee as $grantee) {
693
+ if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser
694
+ $acp['acl'][] = array(
695
+ 'type' => 'CanonicalUser',
696
+ 'id' => (string)$grantee->ID,
697
+ 'name' => (string)$grantee->DisplayName,
698
+ 'permission' => (string)$grant->Permission
699
+ );
700
+ elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail
701
+ $acp['acl'][] = array(
702
+ 'type' => 'AmazonCustomerByEmail',
703
+ 'email' => (string)$grantee->EmailAddress,
704
+ 'permission' => (string)$grant->Permission
705
+ );
706
+ elseif (isset($grantee->URI)) // Group
707
+ $acp['acl'][] = array(
708
+ 'type' => 'Group',
709
+ 'uri' => (string)$grantee->URI,
710
+ 'permission' => (string)$grant->Permission
711
+ );
712
+ else continue;
713
+ }
714
+ }
715
+ }
716
+ return $acp;
717
+ }
718
+
719
+
720
+ /**
721
+ * Delete an object
722
+ *
723
+ * @param string $bucket Bucket name
724
+ * @param string $uri Object URI
725
+ * @return boolean
726
+ */
727
+ public static function deleteObject($bucket, $uri) {
728
+ $rest = new S3Request('DELETE', $bucket, $uri);
729
+ $rest = $rest->getResponse();
730
+ if ($rest->error === false && $rest->code !== 204)
731
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
732
+ if ($rest->error !== false) {
733
+ trigger_error(sprintf("S3::deleteObject(): [%s] %s",
734
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
735
+ return false;
736
+ }
737
+ return true;
738
+ }
739
+
740
+
741
+ /**
742
+ * Get a query string authenticated URL
743
+ *
744
+ * @param string $bucket Bucket name
745
+ * @param string $uri Object URI
746
+ * @param integer $lifetime Lifetime in seconds
747
+ * @param boolean $hostBucket Use the bucket name as the hostname
748
+ * @param boolean $https Use HTTPS ($hostBucket should be false for SSL verification)
749
+ * @return string
750
+ */
751
+ public static function getAuthenticatedURL($bucket, $uri, $lifetime, $hostBucket = false, $https = false) {
752
+ $expires = time() + $lifetime;
753
+ $uri = str_replace('%2F', '/', rawurlencode($uri)); // URI should be encoded (thanks Sean O'Dea)
754
+ return sprintf(($https ? 'https' : 'http').'://%s/%s?AWSAccessKeyId=%s&Expires=%u&Signature=%s',
755
+ $hostBucket ? $bucket : $bucket.'.s3.amazonaws.com', $uri, self::$__accessKey, $expires,
756
+ urlencode(self::__getHash("GET\n\n\n{$expires}\n/{$bucket}/{$uri}")));
757
+ }
758
+
759
+ /**
760
+ * Get upload POST parameters for form uploads
761
+ *
762
+ * @param string $bucket Bucket name
763
+ * @param string $uriPrefix Object URI prefix
764
+ * @param constant $acl ACL constant
765
+ * @param integer $lifetime Lifetime in seconds
766
+ * @param integer $maxFileSize Maximum filesize in bytes (default 5MB)
767
+ * @param string $successRedirect Redirect URL or 200 / 201 status code
768
+ * @param array $amzHeaders Array of x-amz-meta-* headers
769
+ * @param array $headers Array of request headers or content type as a string
770
+ * @param boolean $flashVars Includes additional "Filename" variable posted by Flash
771
+ * @return object
772
+ */
773
+ public static function getHttpUploadPostParams($bucket, $uriPrefix = '', $acl = self::ACL_PRIVATE, $lifetime = 3600, $maxFileSize = 5242880, $successRedirect = "201", $amzHeaders = array(), $headers = array(), $flashVars = false) {
774
+ // Create policy object
775
+ $policy = new stdClass;
776
+ $policy->expiration = gmdate('Y-m-d\TH:i:s\Z', (time() + $lifetime));
777
+ $policy->conditions = array();
778
+ $obj = new stdClass; $obj->bucket = $bucket; array_push($policy->conditions, $obj);
779
+ $obj = new stdClass; $obj->acl = $acl; array_push($policy->conditions, $obj);
780
+
781
+ $obj = new stdClass; // 200 for non-redirect uploads
782
+ if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
783
+ $obj->success_action_status = (string)$successRedirect;
784
+ else // URL
785
+ $obj->success_action_redirect = $successRedirect;
786
+ array_push($policy->conditions, $obj);
787
+
788
+ array_push($policy->conditions, array('starts-with', '$key', $uriPrefix));
789
+ if ($flashVars) array_push($policy->conditions, array('starts-with', '$Filename', ''));
790
+ foreach (array_keys($headers) as $headerKey)
791
+ array_push($policy->conditions, array('starts-with', '$'.$headerKey, ''));
792
+ foreach ($amzHeaders as $headerKey => $headerVal) {
793
+ $obj = new stdClass; $obj->{$headerKey} = (string)$headerVal; array_push($policy->conditions, $obj);
794
+ }
795
+ array_push($policy->conditions, array('content-length-range', 0, $maxFileSize));
796
+ $policy = base64_encode(str_replace('\/', '/', json_encode($policy)));
797
+
798
+ // Create parameters
799
+ $params = new stdClass;
800
+ $params->AWSAccessKeyId = self::$__accessKey;
801
+ $params->key = $uriPrefix.'${filename}';
802
+ $params->acl = $acl;
803
+ $params->policy = $policy; unset($policy);
804
+ $params->signature = self::__getHash($params->policy);
805
+ if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
806
+ $params->success_action_status = (string)$successRedirect;
807
+ else
808
+ $params->success_action_redirect = $successRedirect;
809
+ foreach ($headers as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
810
+ foreach ($amzHeaders as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
811
+ return $params;
812
+ }
813
+
814
+ /**
815
+ * Create a CloudFront distribution
816
+ *
817
+ * @param string $bucket Bucket name
818
+ * @param boolean $enabled Enabled (true/false)
819
+ * @param array $cnames Array containing CNAME aliases
820
+ * @param string $comment Use the bucket name as the hostname
821
+ * @return array | false
822
+ */
823
+ public static function createDistribution($bucket, $enabled = true, $cnames = array(), $comment = '') {
824
+ self::$useSSL = true; // CloudFront requires SSL
825
+ $rest = new S3Request('POST', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com');
826
+ $rest->data = self::__getCloudFrontDistributionConfigXML($bucket.'.s3.amazonaws.com', $enabled, $comment, (string)microtime(true), $cnames);
827
+ $rest->size = strlen($rest->data);
828
+ $rest->setHeader('Content-Type', 'application/xml');
829
+ $rest = self::__getCloudFrontResponse($rest);
830
+
831
+ if ($rest->error === false && $rest->code !== 201)
832
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
833
+ if ($rest->error !== false) {
834
+ trigger_error(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", '$comment'): [%s] %s",
835
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
836
+ return false;
837
+ } elseif ($rest->body instanceof SimpleXMLElement)
838
+ return self::__parseCloudFrontDistributionConfig($rest->body);
839
+ return false;
840
+ }
841
+
842
+
843
+ /**
844
+ * Get CloudFront distribution info
845
+ *
846
+ * @param string $distributionId Distribution ID from listDistributions()
847
+ * @return array | false
848
+ */
849
+ public static function getDistribution($distributionId) {
850
+ self::$useSSL = true; // CloudFront requires SSL
851
+ $rest = new S3Request('GET', '', '2008-06-30/distribution/'.$distributionId, 'cloudfront.amazonaws.com');
852
+ $rest = self::__getCloudFrontResponse($rest);
853
+
854
+ if ($rest->error === false && $rest->code !== 200)
855
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
856
+ if ($rest->error !== false) {
857
+ trigger_error(sprintf("S3::getDistribution($distributionId): [%s] %s",
858
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
859
+ return false;
860
+ } elseif ($rest->body instanceof SimpleXMLElement) {
861
+ $dist = self::__parseCloudFrontDistributionConfig($rest->body);
862
+ $dist['hash'] = $rest->headers['hash'];
863
+ return $dist;
864
+ }
865
+ return false;
866
+ }
867
+
868
+
869
+ /**
870
+ * Update a CloudFront distribution
871
+ *
872
+ * @param array $dist Distribution array info identical to output of getDistribution()
873
+ * @return array | false
874
+ */
875
+ public static function updateDistribution($dist) {
876
+ self::$useSSL = true; // CloudFront requires SSL
877
+ $rest = new S3Request('PUT', '', '2008-06-30/distribution/'.$dist['id'].'/config', 'cloudfront.amazonaws.com');
878
+ $rest->data = self::__getCloudFrontDistributionConfigXML($dist['origin'], $dist['enabled'], $dist['comment'], $dist['callerReference'], $dist['cnames']);
879
+ $rest->size = strlen($rest->data);
880
+ $rest->setHeader('If-Match', $dist['hash']);
881
+ $rest = self::__getCloudFrontResponse($rest);
882
+
883
+ if ($rest->error === false && $rest->code !== 200)
884
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
885
+ if ($rest->error !== false) {
886
+ trigger_error(sprintf("S3::updateDistribution({$dist['id']}, ".(int)$enabled.", '$comment'): [%s] %s",
887
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
888
+ return false;
889
+ } else {
890
+ $dist = self::__parseCloudFrontDistributionConfig($rest->body);
891
+ $dist['hash'] = $rest->headers['hash'];
892
+ return $dist;
893
+ }
894
+ return false;
895
+ }
896
+
897
+
898
+ /**
899
+ * Delete a CloudFront distribution
900
+ *
901
+ * @param array $dist Distribution array info identical to output of getDistribution()
902
+ * @return boolean
903
+ */
904
+ public static function deleteDistribution($dist) {
905
+ self::$useSSL = true; // CloudFront requires SSL
906
+ $rest = new S3Request('DELETE', '', '2008-06-30/distribution/'.$dist['id'], 'cloudfront.amazonaws.com');
907
+ $rest->setHeader('If-Match', $dist['hash']);
908
+ $rest = self::__getCloudFrontResponse($rest);
909
+
910
+ if ($rest->error === false && $rest->code !== 204)
911
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
912
+ if ($rest->error !== false) {
913
+ trigger_error(sprintf("S3::deleteDistribution({$dist['id']}): [%s] %s",
914
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
915
+ return false;
916
+ }
917
+ return true;
918
+ }
919
+
920
+
921
+ /**
922
+ * Get a list of CloudFront distributions
923
+ *
924
+ * @return array
925
+ */
926
+ public static function listDistributions() {
927
+ self::$useSSL = true; // CloudFront requires SSL
928
+ $rest = new S3Request('GET', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com');
929
+ $rest = self::__getCloudFrontResponse($rest);
930
+
931
+ if ($rest->error === false && $rest->code !== 200)
932
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
933
+ if ($rest->error !== false) {
934
+ trigger_error(sprintf("S3::listDistributions(): [%s] %s",
935
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
936
+ return false;
937
+ } elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary)) {
938
+ $list = array();
939
+ if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated)) {
940
+ //$info['marker'] = (string)$rest->body->Marker;
941
+ //$info['maxItems'] = (int)$rest->body->MaxItems;
942
+ //$info['isTruncated'] = (string)$rest->body->IsTruncated == 'true' ? true : false;
943
+ }
944
+ foreach ($rest->body->DistributionSummary as $summary) {
945
+ $list[(string)$summary->Id] = self::__parseCloudFrontDistributionConfig($summary);
946
+ }
947
+ return $list;
948
+ }
949
+ return array();
950
+ }
951
+
952
+
953
+ /**
954
+ * Get a DistributionConfig DOMDocument
955
+ *
956
+ * @internal Used to create XML in createDistribution() and updateDistribution()
957
+ * @param string $bucket Origin bucket
958
+ * @param boolean $enabled Enabled (true/false)
959
+ * @param string $comment Comment to append
960
+ * @param string $callerReference Caller reference
961
+ * @param array $cnames Array of CNAME aliases
962
+ * @return string
963
+ */
964
+ private static function __getCloudFrontDistributionConfigXML($bucket, $enabled, $comment, $callerReference = '0', $cnames = array()) {
965
+ $dom = new DOMDocument('1.0', 'UTF-8');
966
+ $dom->formatOutput = true;
967
+ $distributionConfig = $dom->createElement('DistributionConfig');
968
+ $distributionConfig->setAttribute('xmlns', 'http://cloudfront.amazonaws.com/doc/2008-06-30/');
969
+ $distributionConfig->appendChild($dom->createElement('Origin', $bucket));
970
+ $distributionConfig->appendChild($dom->createElement('CallerReference', $callerReference));
971
+ foreach ($cnames as $cname)
972
+ $distributionConfig->appendChild($dom->createElement('CNAME', $cname));
973
+ if ($comment !== '') $distributionConfig->appendChild($dom->createElement('Comment', $comment));
974
+ $distributionConfig->appendChild($dom->createElement('Enabled', $enabled ? 'true' : 'false'));
975
+ $dom->appendChild($distributionConfig);
976
+ return $dom->saveXML();
977
+ }
978
+
979
+
980
+ /**
981
+ * Parse a CloudFront distribution config
982
+ *
983
+ * @internal Used to parse the CloudFront DistributionConfig node to an array
984
+ * @param object &$node DOMNode
985
+ * @return array
986
+ */
987
+ private static function __parseCloudFrontDistributionConfig(&$node) {
988
+ $dist = array();
989
+ if (isset($node->Id, $node->Status, $node->LastModifiedTime, $node->DomainName)) {
990
+ $dist['id'] = (string)$node->Id;
991
+ $dist['status'] = (string)$node->Status;
992
+ $dist['time'] = strtotime((string)$node->LastModifiedTime);
993
+ $dist['domain'] = (string)$node->DomainName;
994
+ }
995
+ if (isset($node->CallerReference))
996
+ $dist['callerReference'] = (string)$node->CallerReference;
997
+ if (isset($node->Comment))
998
+ $dist['comment'] = (string)$node->Comment;
999
+ if (isset($node->Enabled, $node->Origin)) {
1000
+ $dist['origin'] = (string)$node->Origin;
1001
+ $dist['enabled'] = (string)$node->Enabled == 'true' ? true : false;
1002
+ } elseif (isset($node->DistributionConfig)) {
1003
+ $dist = array_merge($dist, self::__parseCloudFrontDistributionConfig($node->DistributionConfig));
1004
+ }
1005
+ if (isset($node->CNAME)) {
1006
+ $dist['cnames'] = array();
1007
+ foreach ($node->CNAME as $cname) $dist['cnames'][(string)$cname] = (string)$cname;
1008
+ }
1009
+ return $dist;
1010
+ }
1011
+
1012
+
1013
+ /**
1014
+ * Grab CloudFront response
1015
+ *
1016
+ * @internal Used to parse the CloudFront S3Request::getResponse() output
1017
+ * @param object &$rest S3Request instance
1018
+ * @return object
1019
+ */
1020
+ private static function __getCloudFrontResponse(&$rest) {
1021
+ $rest->getResponse();
1022
+ if ($rest->response->error === false && isset($rest->response->body) &&
1023
+ is_string($rest->response->body) && substr($rest->response->body, 0, 5) == '<?xml') {
1024
+ $rest->response->body = simplexml_load_string($rest->response->body);
1025
+ // Grab CloudFront errors
1026
+ if (isset($rest->response->body->Error, $rest->response->body->Error->Code,
1027
+ $rest->response->body->Error->Message)) {
1028
+ $rest->response->error = array(
1029
+ 'code' => (string)$rest->response->body->Error->Code,
1030
+ 'message' => (string)$rest->response->body->Error->Message
1031
+ );
1032
+ unset($rest->response->body);
1033
+ }
1034
+ }
1035
+ return $rest->response;
1036
+ }
1037
+
1038
+
1039
+ /**
1040
+ * Get MIME type for file
1041
+ *
1042
+ * @internal Used to get mime types
1043
+ * @param string &$file File path
1044
+ * @return string
1045
+ */
1046
+ public static function __getMimeType(&$file) {
1047
+ $type = false;
1048
+ // Fileinfo documentation says fileinfo_open() will use the
1049
+ // MAGIC env var for the magic file
1050
+ if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
1051
+ ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) {
1052
+ if (($type = finfo_file($finfo, $file)) !== false) {
1053
+ // Remove the charset and grab the last content-type
1054
+ $type = explode(' ', str_replace('; charset=', ';charset=', $type));
1055
+ $type = array_pop($type);
1056
+ $type = explode(';', $type);
1057
+ $type = trim(array_shift($type));
1058
+ }
1059
+ finfo_close($finfo);
1060
+
1061
+ // If anyone is still using mime_content_type()
1062
+ } elseif (function_exists('mime_content_type'))
1063
+ $type = trim(mime_content_type($file));
1064
+
1065
+ if ($type !== false && strlen($type) > 0) return $type;
1066
+
1067
+ // Otherwise do it the old fashioned way
1068
+ static $exts = array(
1069
+ 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
1070
+ 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
1071
+ 'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
1072
+ 'zip' => 'application/zip', 'gz' => 'application/x-gzip',
1073
+ 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
1074
+ 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
1075
+ 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
1076
+ 'css' => 'text/css', 'js' => 'text/javascript',
1077
+ 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
1078
+ 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
1079
+ 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
1080
+ 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
1081
+ );
1082
+ $ext = strtolower(pathInfo($file, PATHINFO_EXTENSION));
1083
+ return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
1084
+ }
1085
+
1086
+
1087
+ /**
1088
+ * Generate the auth string: "AWS AccessKey:Signature"
1089
+ *
1090
+ * @internal Used by S3Request::getResponse()
1091
+ * @param string $string String to sign
1092
+ * @return string
1093
+ */
1094
+ public static function __getSignature($string) {
1095
+ return 'AWS '.self::$__accessKey.':'.self::__getHash($string);
1096
+ }
1097
+
1098
+
1099
+ /**
1100
+ * Creates a HMAC-SHA1 hash
1101
+ *
1102
+ * This uses the hash extension if loaded
1103
+ *
1104
+ * @internal Used by __getSignature()
1105
+ * @param string $string String to sign
1106
+ * @return string
1107
+ */
1108
+ private static function __getHash($string) {
1109
+ return base64_encode(extension_loaded('hash') ?
1110
+ hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
1111
+ (str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
1112
+ pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00)) ^
1113
+ (str_repeat(chr(0x36), 64))) . $string)))));
1114
+ }
1115
+
1116
+ }
1117
+
1118
+ final class S3Request {
1119
+ private $verb, $bucket, $uri, $resource = '', $parameters = array(),
1120
+ $amzHeaders = array(), $headers = array(
1121
+ 'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => ''
1122
+ );
1123
+ public $fp = false, $size = 0, $data = false, $response;
1124
+
1125
+
1126
+ /**
1127
+ * Constructor
1128
+ *
1129
+ * @param string $verb Verb
1130
+ * @param string $bucket Bucket name
1131
+ * @param string $uri Object URI
1132
+ * @return mixed
1133
+ */
1134
+ function __construct($verb, $bucket = '', $uri = '', $defaultHost = 's3.amazonaws.com') {
1135
+ $this->verb = $verb;
1136
+ $this->bucket = strtolower($bucket);
1137
+ $this->uri = $uri !== '' ? '/'.str_replace('%2F', '/', rawurlencode($uri)) : '/';
1138
+
1139
+ if ($this->bucket !== '') {
1140
+ $this->headers['Host'] = $this->bucket.'.'.$defaultHost;
1141
+ $this->resource = '/'.$this->bucket.$this->uri;
1142
+ } else {
1143
+ $this->headers['Host'] = $defaultHost;
1144
+ //$this->resource = strlen($this->uri) > 1 ? '/'.$this->bucket.$this->uri : $this->uri;
1145
+ $this->resource = $this->uri;
1146
+ }
1147
+ $this->headers['Date'] = gmdate('D, d M Y H:i:s T');
1148
+
1149
+ $this->response = new STDClass;
1150
+ $this->response->error = false;
1151
+ }
1152
+
1153
+
1154
+ /**
1155
+ * Set request parameter
1156
+ *
1157
+ * @param string $key Key
1158
+ * @param string $value Value
1159
+ * @return void
1160
+ */
1161
+ public function setParameter($key, $value) {
1162
+ $this->parameters[$key] = $value;
1163
+ }
1164
+
1165
+
1166
+ /**
1167
+ * Set request header
1168
+ *
1169
+ * @param string $key Key
1170
+ * @param string $value Value
1171
+ * @return void
1172
+ */
1173
+ public function setHeader($key, $value) {
1174
+ $this->headers[$key] = $value;
1175
+ }
1176
+
1177
+
1178
+ /**
1179
+ * Set x-amz-meta-* header
1180
+ *
1181
+ * @param string $key Key
1182
+ * @param string $value Value
1183
+ * @return void
1184
+ */
1185
+ public function setAmzHeader($key, $value) {
1186
+ $this->amzHeaders[$key] = $value;
1187
+ }
1188
+
1189
+
1190
+ /**
1191
+ * Get the S3 response
1192
+ *
1193
+ * @return object | false
1194
+ */
1195
+ public function getResponse() {
1196
+ $query = '';
1197
+ if (sizeof($this->parameters) > 0) {
1198
+ $query = substr($this->uri, -1) !== '?' ? '?' : '&';
1199
+ foreach ($this->parameters as $var => $value)
1200
+ if ($value == null || $value == '') $query .= $var.'&';
1201
+ // Parameters should be encoded (thanks Sean O'Dea)
1202
+ else $query .= $var.'='.rawurlencode($value).'&';
1203
+ $query = substr($query, 0, -1);
1204
+ $this->uri .= $query;
1205
+
1206
+ if (array_key_exists('acl', $this->parameters) ||
1207
+ array_key_exists('location', $this->parameters) ||
1208
+ array_key_exists('torrent', $this->parameters) ||
1209
+ array_key_exists('logging', $this->parameters))
1210
+ $this->resource .= $query;
1211
+ }
1212
+ $url = ((S3::$useSSL && extension_loaded('openssl')) ?
1213
+ 'https://':'http://').$this->headers['Host'].$this->uri;
1214
+ //var_dump($this->bucket, $this->uri, $this->resource, $url);
1215
+
1216
+ // Basic setup
1217
+ $curl = curl_init();
1218
+ curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php');
1219
+
1220
+ if (S3::$useSSL) {
1221
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);
1222
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
1223
+ }
1224
+
1225
+ curl_setopt($curl, CURLOPT_URL, $url);
1226
+
1227
+ // Headers
1228
+ $headers = array(); $amz = array();
1229
+ foreach ($this->amzHeaders as $header => $value)
1230
+ if (strlen($value) > 0) $headers[] = $header.': '.$value;
1231
+ foreach ($this->headers as $header => $value)
1232
+ if (strlen($value) > 0) $headers[] = $header.': '.$value;
1233
+
1234
+ // Collect AMZ headers for signature
1235
+ foreach ($this->amzHeaders as $header => $value)
1236
+ if (strlen($value) > 0) $amz[] = strtolower($header).':'.$value;
1237
+
1238
+ // AMZ headers must be sorted
1239
+ if (sizeof($amz) > 0) {
1240
+ sort($amz);
1241
+ $amz = "\n".implode("\n", $amz);
1242
+ } else $amz = '';
1243
+
1244
+ // Authorization string (CloudFront stringToSign should only contain a date)
1245
+ $headers[] = 'Authorization: ' . S3::__getSignature(
1246
+ $this->headers['Host'] == 'cloudfront.amazonaws.com' ? $this->headers['Date'] :
1247
+ $this->verb."\n".$this->headers['Content-MD5']."\n".
1248
+ $this->headers['Content-Type']."\n".$this->headers['Date'].$amz."\n".$this->resource
1249
+ );
1250
+
1251
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
1252
+ curl_setopt($curl, CURLOPT_HEADER, false);
1253
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
1254
+ curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
1255
+ curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback'));
1256
+ //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
1257
+
1258
+ // Request types
1259
+ switch ($this->verb) {
1260
+ case 'GET': break;
1261
+ case 'PUT': case 'POST': // POST only used for CloudFront
1262
+ if ($this->fp !== false) {
1263
+ curl_setopt($curl, CURLOPT_PUT, true);
1264
+ curl_setopt($curl, CURLOPT_INFILE, $this->fp);
1265
+ if ($this->size >= 0)
1266
+ curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
1267
+ } elseif ($this->data !== false) {
1268
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
1269
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
1270
+ if ($this->size >= 0)
1271
+ curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size);
1272
+ } else
1273
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
1274
+ break;
1275
+ case 'HEAD':
1276
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
1277
+ curl_setopt($curl, CURLOPT_NOBODY, true);
1278
+ break;
1279
+ case 'DELETE':
1280
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
1281
+ break;
1282
+ default: break;
1283
+ }
1284
+
1285
+ // Execute, grab errors
1286
+ if (curl_exec($curl))
1287
+ $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
1288
+ else
1289
+ $this->response->error = array(
1290
+ 'code' => curl_errno($curl),
1291
+ 'message' => curl_error($curl),
1292
+ 'resource' => $this->resource
1293
+ );
1294
+
1295
+ @curl_close($curl);
1296
+
1297
+ // Parse body into XML
1298
+ if ($this->response->error === false && isset($this->response->headers['type']) &&
1299
+ $this->response->headers['type'] == 'application/xml' && isset($this->response->body)) {
1300
+ $this->response->body = simplexml_load_string($this->response->body);
1301
+
1302
+ // Grab S3 errors
1303
+ if (!in_array($this->response->code, array(200, 204)) &&
1304
+ isset($this->response->body->Code, $this->response->body->Message)) {
1305
+ $this->response->error = array(
1306
+ 'code' => (string)$this->response->body->Code,
1307
+ 'message' => (string)$this->response->body->Message
1308
+ );
1309
+ if (isset($this->response->body->Resource))
1310
+ $this->response->error['resource'] = (string)$this->response->body->Resource;
1311
+ unset($this->response->body);
1312
+ }
1313
+ }
1314
+
1315
+ // Clean up file resources
1316
+ if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp);
1317
+
1318
+ return $this->response;
1319
+ }
1320
+
1321
+
1322
+ /**
1323
+ * CURL write callback
1324
+ *
1325
+ * @param resource &$curl CURL resource
1326
+ * @param string &$data Data
1327
+ * @return integer
1328
+ */
1329
+ private function __responseWriteCallback(&$curl, &$data) {
1330
+ if ($this->response->code == 200 && $this->fp !== false)
1331
+ return fwrite($this->fp, $data);
1332
+ else
1333
+ $this->response->body .= $data;
1334
+ return strlen($data);
1335
+ }
1336
+
1337
+
1338
+ /**
1339
+ * CURL header callback
1340
+ *
1341
+ * @param resource &$curl CURL resource
1342
+ * @param string &$data Data
1343
+ * @return integer
1344
+ */
1345
+ private function __responseHeaderCallback(&$curl, &$data) {
1346
+ if (($strlen = strlen($data)) <= 2) return $strlen;
1347
+ if (substr($data, 0, 4) == 'HTTP')
1348
+ $this->response->code = (int)substr($data, 9, 3);
1349
+ else {
1350
+ list($header, $value) = explode(': ', trim($data), 2);
1351
+ if ($header == 'Last-Modified')
1352
+ $this->response->headers['time'] = strtotime($value);
1353
+ elseif ($header == 'Content-Length')
1354
+ $this->response->headers['size'] = (int)$value;
1355
+ elseif ($header == 'Content-Type')
1356
+ $this->response->headers['type'] = $value;
1357
+ elseif ($header == 'ETag')
1358
+ $this->response->headers['hash'] = $value{0} == '"' ? substr($value, 1, -1) : $value;
1359
+ elseif (preg_match('/^x-amz-meta-.*$/', $header))
1360
+ $this->response->headers[$header] = is_numeric($value) ? (int)$value : $value;
1361
+ }
1362
+ return $strlen;
1363
+ }
1364
+
1365
+ }
app/options-backups.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?PHP
2
+ // don't load directly
3
+ if ( !defined('ABSPATH') )
4
+ die('-1');
5
+
6
+ //get GET data
7
+ if (isset($_GET['paged'])) $paged=$_GET['paged'];
8
+
9
+ //Get Backup files
10
+ $backups=backwpup_get_backup_files();
11
+
12
+ //Page links
13
+ $per_page = 20;
14
+
15
+ $pagenum = isset( $paged ) ? absint( $paged ) : 0;
16
+ if ( empty($pagenum) )
17
+ $pagenum = 1;
18
+
19
+ $num_backups = count($backups);
20
+ $num_pages = ceil($num_backups / $per_page);
21
+
22
+ $page_links = paginate_links( array(
23
+ 'base' => add_query_arg('paged', '%#%'),
24
+ 'format' => '',
25
+ 'prev_text' => __('&laquo;'),
26
+ 'next_text' => __('&raquo;'),
27
+ 'total' => $num_pages,
28
+ 'current' => $pagenum
29
+ ));
30
+ ?>
31
+ <div class="wrap">
32
+ <div id="icon-tools" class="icon32"><br /></div>
33
+ <h2><?php _e("BackWPup Manage Backups", "backwpup"); ?></h2>
34
+ <ul class="subsubsub">
35
+ <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
36
+ <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
37
+ <li><a href="admin.php?page=BackWPup&amp;action=backups" class="current"><?PHP _e('Backups','backwpup'); ?></a> |</li>
38
+ <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
39
+ <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
40
+ </ul>
41
+
42
+ <form id="logs-filter" action="" method="post">
43
+ <?php wp_nonce_field('actions-backups'); ?>
44
+ <input type="hidden" name="page" value="BackWPup" />
45
+ <div class="tablenav">
46
+
47
+ <div class="alignleft actions">
48
+ <select name="action" class="select-action">
49
+ <option value="backups" selected="selected"><?PHP _e('Bulk Actions','backwpup'); ?></option>
50
+ <option value="delete-backup"><?PHP _e('Delete','backwpup'); ?></option>
51
+ </select>
52
+ <input type="submit" value="<?PHP _e('Apply','backwpup'); ?>" name="doaction" id="doaction" class="button-secondary action" />
53
+ </div>
54
+
55
+ <?php if ( $page_links ) { ?>
56
+ <div class="tablenav-pages"><?php $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
57
+ number_format_i18n( ( $pagenum - 1 ) * $per_page + 1 ),
58
+ number_format_i18n( min( $pagenum * $per_page, $num_backups ) ),
59
+ number_format_i18n( $num_backups ),
60
+ $page_links
61
+ ); echo $page_links_text; ?></div>
62
+ <?php } ?>
63
+ <div class="clear"></div>
64
+ </div>
65
+
66
+ <div class="clear"></div>
67
+
68
+ <table class="widefat" cellspacing="0">
69
+ <thead>
70
+ <tr>
71
+ <?php print_column_headers($page_hook); ?>
72
+ </tr>
73
+ </thead>
74
+
75
+ <tfoot>
76
+ <tr>
77
+ <?php print_column_headers($page_hook, false); ?>
78
+ </tr>
79
+ </tfoot>
80
+
81
+ <tbody id="the-list" class="list:post">
82
+
83
+ <?php
84
+ $item_columns = get_column_headers($page_hook);
85
+ $hidden = get_hidden_columns($page_hook);
86
+ $jobs=get_option('backwpup_jobs'); //Load jobs
87
+
88
+ foreach ($backups as $backupnum => $backup) {
89
+ if (!($backupnum>=($pagenum*$per_page-$per_page) and $backupnum<($pagenum*$per_page)))
90
+ continue;
91
+ $jobvalue=backwpup_check_job_vars($jobs[$backup['jobid']]); //Check job values
92
+ ?><tr id="<?PHP echo $logfile?>" valign="top"><?PHP
93
+ foreach($item_columns as $column_name=>$column_display_name) {
94
+ $class = "class=\"column-$column_name\"";
95
+
96
+ $style = '';
97
+ if ( in_array($column_name, $hidden) )
98
+ $style = ' style="display:none;"';
99
+
100
+ $attributes = "$class$style";
101
+
102
+ switch($column_name) {
103
+ case 'cb':
104
+ echo '<th scope="row" class="check-column"><input type="checkbox" name="backupfiles[]" value="'. esc_attr($backup['file'].':'.$backup['jobid'].':'.$backup['type']) .'" /></th>';
105
+ break;
106
+ case 'id':
107
+ echo "<td $attributes>".$backup['jobid']."</td>";
108
+ break;
109
+ case 'backup':
110
+ if ($backup['type']=='FOLDER') {
111
+ echo "<td $attributes><strong>".basename($backup['file'])."</strong><br />".dirname($backup['file'])."/";
112
+ } elseif ($backup['type']=='S3') {
113
+ echo "<td $attributes><strong>".basename($backup['file'])."</strong><br />S3://".$jobvalue['awsBucket']."/".dirname($backup['file'])."/";
114
+ } elseif ($backup['type']=='FTP') {
115
+ echo "<td $attributes><strong>".basename($backup['file'])."</strong><br />ftp://".$jobvalue['ftphost'].dirname($backup['file'])."/";
116
+ }
117
+ $actions = array();
118
+ $actions['delete'] = "<a class=\"submitdelete\" href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=delete-backup&paged='.$paged.'&backupfile='.$backup['file'].'&jobid='.$backup['jobid'].'&type='.$backup['type'], 'delete-backup_'.basename($backup['file'])) . "\" onclick=\"if ( confirm('" . esc_js(__("You are about to delete this Backup Archive. \n 'Cancel' to stop, 'OK' to delete.","backwpup")) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
119
+ $actions['download'] = "<a class=\"submitdelete\" href=\"" . $backup['downloadurl'] . "\">" . __('Download','backwpup') . "</a>";
120
+ $action_count = count($actions);
121
+ $i = 0;
122
+ echo '<br /><div class="row-actions">';
123
+ foreach ( $actions as $action => $linkaction ) {
124
+ ++$i;
125
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
126
+ echo "<span class='$action'>$linkaction$sep</span>";
127
+ }
128
+ echo '</div>';
129
+ echo "</td>";
130
+ break;
131
+ case 'size':
132
+ echo "<td $attributes>";
133
+ if (!empty($backup['filesize']) and $backup['filesize']!=-1) {
134
+ echo backwpup_formatBytes($backup['filesize']);
135
+ } else {
136
+ _e('?','backwpup');
137
+ }
138
+ echo "</td>";
139
+ break;
140
+ }
141
+ }
142
+ echo "\n </tr>\n";
143
+ }
144
+ ?></tbody>
145
+ </table>
146
+
147
+ <div class="tablenav">
148
+ <div class="alignleft actions">
149
+ <select name="action2" class="select-action">
150
+ <option value="backups" selected="selected"><?PHP _e('Bulk Actions','backwpup'); ?></option>
151
+ <option value="delete-backup"><?PHP _e('Delete','backwpup'); ?></option>
152
+ </select>
153
+ <input type="submit" value="<?PHP _e('Apply','backwpup'); ?>" name="doaction2" id="doaction2" class="button-secondary action" />
154
+ </div>
155
+
156
+ <br class="clear" />
157
+ <?php
158
+ if ( $page_links )
159
+ echo "<div class='tablenav-pages'>$page_links_text</div>";
160
+ ?>
161
+ </div>
162
+ </form>
163
+ <br class="clear" />
164
+
165
+ </div>
app/options-logs.php CHANGED
@@ -2,6 +2,40 @@
2
  // don't load directly
3
  if ( !defined('ABSPATH') )
4
  die('-1');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  ?>
6
  <div class="wrap">
7
  <div id="icon-tools" class="icon32"><br /></div>
@@ -9,6 +43,7 @@ if ( !defined('ABSPATH') )
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs" class="current"><?PHP _e('Logs','backwpup'); ?></a> |</li>
 
12
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
14
  </ul>
@@ -20,13 +55,21 @@ if ( !defined('ABSPATH') )
20
 
21
  <div class="alignleft actions">
22
  <select name="action" class="select-action">
23
- <option value="-1" selected="selected"><?PHP _e('Bulk Actions','backwpup'); ?></option>
24
  <option value="delete-logs"><?PHP _e('Delete','backwpup'); ?></option>
25
  </select>
26
  <input type="submit" value="<?PHP _e('Apply','backwpup'); ?>" name="doaction" id="doaction" class="button-secondary action" />
27
  </div>
28
 
29
- <br class="clear" />
 
 
 
 
 
 
 
 
30
  </div>
31
 
32
  <div class="clear"></div>
@@ -50,19 +93,9 @@ if ( !defined('ABSPATH') )
50
  $item_columns = get_column_headers($page_hook);
51
  $hidden = get_hidden_columns($page_hook);
52
 
53
- //get log files
54
- $logfiles=array();
55
- if ( $dir = @opendir( $cfg['dirlogs'] ) ) {
56
- while (($file = readdir( $dir ) ) !== false ) {
57
- if (is_file($cfg['dirlogs'].'/'.$file) and 'backwpup_log_' == substr($file,0,strlen('backwpup_log_')) and '.html' == substr($file,-5))
58
- $logfiles[]=$file;
59
- }
60
- closedir( $dir );
61
- rsort($logfiles);
62
- }
63
-
64
-
65
- foreach ($logfiles as $logfile) {
66
  $logdata=backwpup_read_logheader($cfg['dirlogs'].'/'.$logfile);
67
  ?><tr id="<?PHP echo $logfile?>" valign="top"><?PHP
68
  foreach($item_columns as $column_name=>$column_display_name) {
@@ -94,10 +127,8 @@ if ( !defined('ABSPATH') )
94
  echo "<td $attributes><strong><a href=\"".wp_nonce_url('admin.php?page=BackWPup&action=view_log&logfile='.$cfg['dirlogs'].'/'.$logfile, 'view-log_'.$logfile)."\" title=\"".__('View log','backwpup')."\">".date_i18n(get_option('date_format'),$logdata['logtime'])." ".date_i18n(get_option('time_format'),$logdata['logtime']).": <i>".$logdata['name']."</i></a></strong>";
95
  $actions = array();
96
  $actions['view'] = "<a href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=view_log&logfile='.$cfg['dirlogs'].'/'.$logfile, 'view-log_'.$logfile) . "\">" . __('View','backwpup') . "</a>";
97
- $actions['delete'] = "<a class=\"submitdelete\" href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=delete-logs&logfile='.$logfile, 'delete-log_'.$logfile) . "\" onclick=\"if ( confirm('" . esc_js(__("You are about to delete this Job. \n 'Cancel' to stop, 'OK' to delete.","backwpup")) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
98
- $actions['downloadlog'] = "<a class=\"submitdelete\" href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=download&file='.$cfg['dirlogs'].'/'.$logfile, 'download-backup_'.$logfile) . "\">" . __('Download Log','backwpup') . "</a>";
99
- if (!empty($logdata['backupfile']) and is_file($logdata['backupfile']))
100
- $actions['downloadbackup'] = "<a class=\"submitdelete\" href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=download&file='.$logdata['backupfile'], 'download-backup_'.basename($logdata['backupfile'])) . "\">" . __('Download Backup','backwpup') . "</a>";
101
  $action_count = count($actions);
102
  $i = 0;
103
  echo '<br /><div class="row-actions">';
@@ -123,10 +154,10 @@ if ( !defined('ABSPATH') )
123
  break;
124
  case 'size':
125
  echo "<td $attributes>";
126
- if (!empty($logdata['backupfile']) and is_file($logdata['backupfile'])) {
127
- echo backwpup_formatBytes(filesize($logdata['backupfile']));
128
  } elseif (!empty($logdata['backupfile'])) {
129
- _e('File not exists','backwpup');
130
  } else {
131
  _e('only Log','backwpup');
132
  }
@@ -147,13 +178,17 @@ if ( !defined('ABSPATH') )
147
  <div class="tablenav">
148
  <div class="alignleft actions">
149
  <select name="action2" class="select-action">
150
- <option value="-1" selected="selected"><?PHP _e('Bulk Actions','backwpup'); ?></option>
151
  <option value="delete-logs"><?PHP _e('Delete','backwpup'); ?></option>
152
  </select>
153
  <input type="submit" value="<?PHP _e('Apply','backwpup'); ?>" name="doaction2" id="doaction2" class="button-secondary action" />
154
  </div>
155
 
156
- <br class="clear" />
 
 
 
 
157
  </div>
158
  </form>
159
  <br class="clear" />
2
  // don't load directly
3
  if ( !defined('ABSPATH') )
4
  die('-1');
5
+
6
+ //get GET data
7
+ if (isset($_GET['paged'])) $paged=$_GET['paged'];
8
+
9
+ //Get log files
10
+ $logfiles=array();
11
+ if ( $dir = @opendir( $cfg['dirlogs'] ) ) {
12
+ while (($file = readdir( $dir ) ) !== false ) {
13
+ if (is_file($cfg['dirlogs'].'/'.$file) and 'backwpup_log_' == substr($file,0,strlen('backwpup_log_')) and '.html' == substr($file,-5))
14
+ $logfiles[]=$file;
15
+ }
16
+ closedir( $dir );
17
+ rsort($logfiles);
18
+ }
19
+
20
+ //Page links
21
+ $per_page = 20;
22
+
23
+ $pagenum = isset( $paged ) ? absint( $paged ) : 0;
24
+ if ( empty($pagenum) )
25
+ $pagenum = 1;
26
+
27
+ $num_logs = count($logfiles);
28
+ $num_pages = ceil($num_logs / $per_page);
29
+
30
+ $page_links = paginate_links( array(
31
+ 'base' => add_query_arg('paged', '%#%'),
32
+ 'format' => '',
33
+ 'prev_text' => __('&laquo;'),
34
+ 'next_text' => __('&raquo;'),
35
+ 'total' => $num_pages,
36
+ 'current' => $pagenum
37
+ ));
38
+
39
  ?>
40
  <div class="wrap">
41
  <div id="icon-tools" class="icon32"><br /></div>
43
  <ul class="subsubsub">
44
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
45
  <li><a href="admin.php?page=BackWPup&amp;action=logs" class="current"><?PHP _e('Logs','backwpup'); ?></a> |</li>
46
+ <li><a href="admin.php?page=BackWPup&amp;action=backups"><?PHP _e('Backups','backwpup'); ?></a> |</li>
47
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
48
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
49
  </ul>
55
 
56
  <div class="alignleft actions">
57
  <select name="action" class="select-action">
58
+ <option value="logs" selected="selected"><?PHP _e('Bulk Actions','backwpup'); ?></option>
59
  <option value="delete-logs"><?PHP _e('Delete','backwpup'); ?></option>
60
  </select>
61
  <input type="submit" value="<?PHP _e('Apply','backwpup'); ?>" name="doaction" id="doaction" class="button-secondary action" />
62
  </div>
63
 
64
+ <?php if ( $page_links ) { ?>
65
+ <div class="tablenav-pages"><?php $page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
66
+ number_format_i18n( ( $pagenum - 1 ) * $per_page + 1 ),
67
+ number_format_i18n( min( $pagenum * $per_page, $num_logs ) ),
68
+ number_format_i18n( $num_logs ),
69
+ $page_links
70
+ ); echo $page_links_text; ?></div>
71
+ <?php } ?>
72
+ <div class="clear"></div>
73
  </div>
74
 
75
  <div class="clear"></div>
93
  $item_columns = get_column_headers($page_hook);
94
  $hidden = get_hidden_columns($page_hook);
95
 
96
+ foreach ($logfiles as $lognum => $logfile) {
97
+ if (!($lognum>=($pagenum*$per_page-$per_page) and $lognum<($pagenum*$per_page)))
98
+ continue;
 
 
 
 
 
 
 
 
 
 
99
  $logdata=backwpup_read_logheader($cfg['dirlogs'].'/'.$logfile);
100
  ?><tr id="<?PHP echo $logfile?>" valign="top"><?PHP
101
  foreach($item_columns as $column_name=>$column_display_name) {
127
  echo "<td $attributes><strong><a href=\"".wp_nonce_url('admin.php?page=BackWPup&action=view_log&logfile='.$cfg['dirlogs'].'/'.$logfile, 'view-log_'.$logfile)."\" title=\"".__('View log','backwpup')."\">".date_i18n(get_option('date_format'),$logdata['logtime'])." ".date_i18n(get_option('time_format'),$logdata['logtime']).": <i>".$logdata['name']."</i></a></strong>";
128
  $actions = array();
129
  $actions['view'] = "<a href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=view_log&logfile='.$cfg['dirlogs'].'/'.$logfile, 'view-log_'.$logfile) . "\">" . __('View','backwpup') . "</a>";
130
+ $actions['delete'] = "<a class=\"submitdelete\" href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=delete-logs&paged='.$paged.'&logfile='.$logfile, 'delete-log_'.$logfile) . "\" onclick=\"if ( confirm('" . esc_js(__("You are about to delete this Job. \n 'Cancel' to stop, 'OK' to delete.","backwpup")) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
131
+ $actions['download'] = "<a class=\"submitdelete\" href=\"" . wp_nonce_url('admin.php?page=BackWPup&action=download&file='.$cfg['dirlogs'].'/'.$logfile, 'download-backup_'.$logfile) . "\">" . __('Download','backwpup') . "</a>";
 
 
132
  $action_count = count($actions);
133
  $i = 0;
134
  echo '<br /><div class="row-actions">';
154
  break;
155
  case 'size':
156
  echo "<td $attributes>";
157
+ if (!empty($logdata['backupfile']) and !empty($logdata['backupfilesize'])) {
158
+ echo backwpup_formatBytes($logdata['backupfilesize']);
159
  } elseif (!empty($logdata['backupfile'])) {
160
+ _e('?','backwpup');
161
  } else {
162
  _e('only Log','backwpup');
163
  }
178
  <div class="tablenav">
179
  <div class="alignleft actions">
180
  <select name="action2" class="select-action">
181
+ <option value="logs" selected="selected"><?PHP _e('Bulk Actions','backwpup'); ?></option>
182
  <option value="delete-logs"><?PHP _e('Delete','backwpup'); ?></option>
183
  </select>
184
  <input type="submit" value="<?PHP _e('Apply','backwpup'); ?>" name="doaction2" id="doaction2" class="button-secondary action" />
185
  </div>
186
 
187
+ <br class="clear" />
188
+ <?php
189
+ if ( $page_links )
190
+ echo "<div class='tablenav-pages'>$page_links_text</div>";
191
+ ?>
192
  </div>
193
  </form>
194
  <br class="clear" />
app/options-runnow.php CHANGED
@@ -9,6 +9,7 @@ if ( !defined('ABSPATH') )
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
 
12
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
14
  </ul>
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
12
+ <li><a href="admin.php?page=BackWPup&amp;action=backups"><?PHP _e('Backups','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
14
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
15
  </ul>
app/options-save.php CHANGED
@@ -3,7 +3,7 @@
3
  if ( !defined('ABSPATH') )
4
  die('-1');
5
 
6
- if ($_REQUEST['action2']!='-1' and !empty($_REQUEST['doaction2']))
7
  $_REQUEST['action']=$_REQUEST['action2'];
8
 
9
  switch($_REQUEST['action']) {
@@ -49,6 +49,86 @@ case 'delete-logs': //Delete Log
49
  }
50
  $_REQUEST['action']='logs';
51
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  case 'savecfg': //Save config form Setings page
53
  check_admin_referer('backwpup-cfg');
54
  $cfg=get_option('backwpup'); //Load Settings
@@ -106,11 +186,34 @@ case 'download': //Download Backup
106
  header("Content-Transfer-Encoding: binary");
107
  header("Content-Length: ".filesize($_GET['file']));
108
  @readfile($_GET['file']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  } else {
110
  header('HTTP/1.0 404 Not Found');
111
  die(__('File does not exist.', 'backwpup'));
112
  }
113
- $_REQUEST['action']='logs';
114
  break;
115
  case 'saveeditjob': //Save Job settings
116
  $jobid = (int) $_POST['jobid'];
3
  if ( !defined('ABSPATH') )
4
  die('-1');
5
 
6
+ if ($_REQUEST['action2']!='backups' and $_REQUEST['action2']!='logs' and $_REQUEST['action2']!='-1' and !empty($_REQUEST['doaction2']))
7
  $_REQUEST['action']=$_REQUEST['action2'];
8
 
9
  switch($_REQUEST['action']) {
49
  }
50
  $_REQUEST['action']='logs';
51
  break;
52
+ case 'delete-backup': //Delete Backup archives
53
+ $deletebackups=array();
54
+ if (is_Array($_POST['backupfiles'])) {
55
+ check_admin_referer('actions-backups');
56
+ $i=0;
57
+ foreach ($_POST['backupfiles'] as $backupfile) {
58
+ list($deletebackups[$i]['file'],$deletebackups[$i]['jobid'],$deletebackups[$i]['type'])=explode(':',$backupfile,3);
59
+ $i++;
60
+ }
61
+ } else {
62
+ check_admin_referer('delete-backup_' . basename($_GET['backupfile']));
63
+ $deletebackups[0]['type']=$_GET['type'];
64
+ $deletebackups[0]['jobid']=$_GET['jobid'];
65
+ $deletebackups[0]['file']=$_GET['backupfile'];
66
+ }
67
+
68
+ if(empty($deletebackups)) {
69
+ $_REQUEST['action']='backups';
70
+ break;
71
+ }
72
+
73
+ $jobs=get_option('backwpup_jobs'); //Load jobs
74
+ if (extension_loaded('curl') or @dl(PHP_SHLIB_SUFFIX == 'so' ? 'curl.so' : 'php_curl.dll')) {
75
+ if (!class_exists('S3'))
76
+ require_once(plugin_dir_path(__FILE__).'libs/S3.php');
77
+ }
78
+
79
+ $num=0;
80
+ foreach ($deletebackups as $backups) {
81
+ $jobvalue=backwpup_check_job_vars($jobs[$backups['jobid']]); //Check job values
82
+ if ($backups['type']=='FOLDER') {
83
+ if (is_file($backups['file']))
84
+ unlink($backups['file']);
85
+ } elseif ($backups['type']=='S3') {
86
+ if (class_exists('S3')) {
87
+ if (!empty($jobvalue['awsAccessKey']) and !empty($jobvalue['awsSecretKey']) and !empty($jobvalue['awsBucket'])) {
88
+ $s3 = new S3($jobvalue['awsAccessKey'], $jobvalue['awsSecretKey'], $jobvalue['awsSSL']);
89
+ $s3->deleteObject($jobvalue['awsBucket'],$backups['file']);
90
+ }
91
+ }
92
+ } elseif ($backups['type']=='FTP') {
93
+ if (!empty($jobvalue['ftphost']) and !empty($jobvalue['ftpuser']) and !empty($jobvalue['ftppass'])) {
94
+ $ftpport=21;
95
+ $ftphost=$jobvalue['ftphost'];
96
+ if (false !== strpos($jobvalue['ftphost'],':')) //look for port
97
+ list($ftphost,$ftpport)=explode(':',$jobvalue,2);
98
+
99
+ $SSL=false;
100
+ if (function_exists('ftp_ssl_connect')) { //make SSL FTP connection
101
+ $ftp_conn_id = ftp_ssl_connect($ftphost,$ftpport,10);
102
+ if ($ftp_conn_id)
103
+ $SSL=true;
104
+ }
105
+ if (!$ftp_conn_id) { //make normal FTP conection if SSL not work
106
+ $ftp_conn_id = ftp_connect($ftphost,$ftpport,10);
107
+ }
108
+ if ($ftp_conn_id) {
109
+ //FTP Login
110
+ $loginok=false;
111
+ if (@ftp_login($ftp_conn_id, $jobvalue['ftpuser'], base64_decode($jobvalue['ftppass']))) {
112
+ $loginok=true;
113
+ } else { //if PHP ftp login don't work use raw login
114
+ if (substr(trim(ftp_raw($ftp_conn_id,'USER '.$jobvalue['ftpuser'])),0,3)<400) {
115
+ if (substr(trim(ftp_raw($ftp_conn_id,'PASS '.base64_decode($jobvalue['ftppass']))),0,3)<400) {
116
+ $loginok=true;
117
+ }
118
+ }
119
+ }
120
+ }
121
+ if ($loginok) {
122
+ ftp_pasv($ftp_conn_id, true);
123
+ ftp_delete($ftp_conn_id, $backups['file']);
124
+ }
125
+ }
126
+ }
127
+ $num++;
128
+ }
129
+ $backwpup_message=$num.' '.__('Backup Archives deleted', 'backwpup');
130
+ $_REQUEST['action']='backups';
131
+ break;
132
  case 'savecfg': //Save config form Setings page
133
  check_admin_referer('backwpup-cfg');
134
  $cfg=get_option('backwpup'); //Load Settings
186
  header("Content-Transfer-Encoding: binary");
187
  header("Content-Length: ".filesize($_GET['file']));
188
  @readfile($_GET['file']);
189
+ die();
190
+ } else {
191
+ header('HTTP/1.0 404 Not Found');
192
+ die(__('File does not exist.', 'backwpup'));
193
+ }
194
+ break;
195
+ case 'downloads3': //Download S3 Backup
196
+ //check_admin_referer('download-backup_'.basename($_GET['file']));
197
+ require_once(plugin_dir_path(__FILE__).'libs/S3.php');
198
+ $jobs=get_option('backwpup_jobs');
199
+ $jobid=$_GET['jobid'];
200
+ $s3 = new S3($jobs[$jobid]['awsAccessKey'], $jobs[$jobid]['awsSecretKey'],$jobs[$jobid]['awsSSL']);
201
+ if ($contents = $s3->getObjectInfo($jobs[$jobid]['awsBucket'],$_GET['file'])) {
202
+ header("Pragma: public");
203
+ header("Expires: 0");
204
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
205
+ header("Content-Type: application/force-download");
206
+ header("Content-Type: application/octet-stream");
207
+ header("Content-Type: application/download");
208
+ header("Content-Disposition: attachment; filename=".basename($_GET['file']).";");
209
+ header("Content-Transfer-Encoding: binary");
210
+ //header("Content-Length: ".$contents['size']);
211
+ var_dump($s3->getObject($jobs[$jobid]['awsBucket'], $_GET['file']));
212
+ die();
213
  } else {
214
  header('HTTP/1.0 404 Not Found');
215
  die(__('File does not exist.', 'backwpup'));
216
  }
 
217
  break;
218
  case 'saveeditjob': //Save Job settings
219
  $jobid = (int) $_POST['jobid'];
app/options-settings.php CHANGED
@@ -9,6 +9,7 @@ if ( !defined('ABSPATH') )
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
 
12
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=settings" class="current"><?PHP _e('Settings','backwpup'); ?></a></li>
14
  </ul>
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
12
+ <li><a href="admin.php?page=BackWPup&amp;action=backups"><?PHP _e('Backups','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
14
  <li><a href="admin.php?page=BackWPup&amp;action=settings" class="current"><?PHP _e('Settings','backwpup'); ?></a></li>
15
  </ul>
app/options-tools.php CHANGED
@@ -10,6 +10,7 @@ if ( !defined('ABSPATH') )
10
  <ul class="subsubsub">
11
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
12
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
 
13
  <li><a href="admin.php?page=BackWPup&amp;action=tools" class="current"><?PHP _e('Tools','backwpup'); ?></a> |</li>
14
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
15
  </ul>
10
  <ul class="subsubsub">
11
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
12
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
13
+ <li><a href="admin.php?page=BackWPup&amp;action=backups"><?PHP _e('Backups','backwpup'); ?></a> |</li>
14
  <li><a href="admin.php?page=BackWPup&amp;action=tools" class="current"><?PHP _e('Tools','backwpup'); ?></a> |</li>
15
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
16
  </ul>
app/options-view_log.php CHANGED
@@ -9,6 +9,7 @@ if ( !defined('ABSPATH') )
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
 
12
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
14
  </ul>
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
12
+ <li><a href="admin.php?page=BackWPup&amp;action=backups"><?PHP _e('Backups','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
14
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
15
  </ul>
app/options.php CHANGED
@@ -9,6 +9,7 @@ if ( !defined('ABSPATH') )
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup" class="current"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
 
12
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
14
  </ul>
9
  <ul class="subsubsub">
10
  <li><a href="admin.php?page=BackWPup" class="current"><?PHP _e('Jobs','backwpup'); ?></a> |</li>
11
  <li><a href="admin.php?page=BackWPup&amp;action=logs"><?PHP _e('Logs','backwpup'); ?></a> |</li>
12
+ <li><a href="admin.php?page=BackWPup&amp;action=backups"><?PHP _e('Backups','backwpup'); ?></a> |</li>
13
  <li><a href="admin.php?page=BackWPup&amp;action=tools"><?PHP _e('Tools','backwpup'); ?></a> |</li>
14
  <li><a href="admin.php?page=BackWPup&amp;action=settings"><?PHP _e('Settings','backwpup'); ?></a></li>
15
  </ul>
backwpup.php CHANGED
@@ -1,57 +1,57 @@
1
- <?php
2
- /*
3
- Plugin Name: BackWPup
4
- Plugin URI: http://danielhuesken.de/portfolio/backwpup/
5
- Description: Backup and more of your WordPress Blog Database and Files.
6
- Author: Daniel H&uuml;sken
7
- Version: 1.1.1
8
- Author URI: http://danielhuesken.de
9
- Text Domain: backwpup
10
- Domain Path: /lang/
11
- */
12
-
13
- /*
14
- Copyright 2009 Daniel H�sken (email : daniel@huesken-net.de)
15
-
16
- This program is free software; you can redistribute it and/or modify
17
- it under the terms of the GNU General Public License as published by
18
- the Free Software Foundation; either version 2 of the License, or
19
- (at your option) any later version.
20
-
21
- This program is distributed in the hope that it will be useful,
22
- but WITHOUT ANY WARRANTY; without even the implied warranty of
23
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
- GNU General Public License for more details.
25
-
26
- You should have received a copy of the GNU General Public License
27
- along with this program; if not, write to the Free Software
28
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
- */
30
-
31
- // don't load directly
32
- if ( !defined('ABSPATH') )
33
- die('-1');
34
-
35
- //Set plugin dirname
36
- define('BACKWPUP_PLUGIN_BASEDIR', dirname(plugin_basename(__FILE__)));
37
- //Set Plugin Version
38
- define('BACKWPUP_VERSION', '1.1.1');
39
- //load Text Domain
40
- load_plugin_textdomain('backwpup', false, BACKWPUP_PLUGIN_BASEDIR.'/lang');
41
- //Load functions file
42
- require_once(plugin_dir_path(__FILE__).'app/functions.php');
43
- //Plugin activate
44
- register_activation_hook(__FILE__, 'backwpup_plugin_activate');
45
- //Plugin deactivate
46
- register_deactivation_hook(__FILE__, 'backwpup_plugin_deactivate');
47
- //Plugin uninstall
48
- register_uninstall_hook(__FILE__, 'backwpup_plugin_uninstall');
49
-
50
- //Version check
51
- if (version_compare($wp_version, '2.8', '<') and version_compare(phpversion(), '5.0.0', '<')) { // Let only Activate on WordPress Version 2.8 or heiger
52
- add_action('admin_notices', create_function('', 'echo \'<div id="message" class="error fade"><p><strong>' . __('Sorry, BackWPup works only with WordPress 2.8 and PHP 5.0.0 or heigher!!!','backwpup') . '</strong></p></div>\';'));
53
- } else {
54
- //Plugin init
55
- add_action('plugins_loaded', 'backwpup_init');
56
- }
57
- ?>
1
+ <?php
2
+ /*
3
+ Plugin Name: BackWPup
4
+ Plugin URI: http://danielhuesken.de/portfolio/backwpup/
5
+ Description: Backup and more of your WordPress Blog Database and Files.
6
+ Author: Daniel H&uuml;sken
7
+ Version: 1.2.0
8
+ Author URI: http://danielhuesken.de
9
+ Text Domain: backwpup
10
+ Domain Path: /lang/
11
+ */
12
+
13
+ /*
14
+ Copyright 2009 Daniel H�sken (email : daniel@huesken-net.de)
15
+
16
+ This program is free software; you can redistribute it and/or modify
17
+ it under the terms of the GNU General Public License as published by
18
+ the Free Software Foundation; either version 2 of the License, or
19
+ (at your option) any later version.
20
+
21
+ This program is distributed in the hope that it will be useful,
22
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
23
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
+ GNU General Public License for more details.
25
+
26
+ You should have received a copy of the GNU General Public License
27
+ along with this program; if not, write to the Free Software
28
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
+ */
30
+
31
+ // don't load directly
32
+ if ( !defined('ABSPATH') )
33
+ die('-1');
34
+
35
+ //Set plugin dirname
36
+ define('BACKWPUP_PLUGIN_BASEDIR', dirname(plugin_basename(__FILE__)));
37
+ //Set Plugin Version
38
+ define('BACKWPUP_VERSION', '1.2.0');
39
+ //load Text Domain
40
+ load_plugin_textdomain('backwpup', false, BACKWPUP_PLUGIN_BASEDIR.'/lang');
41
+ //Load functions file
42
+ require_once(plugin_dir_path(__FILE__).'app/functions.php');
43
+ //Plugin activate
44
+ register_activation_hook(__FILE__, 'backwpup_plugin_activate');
45
+ //Plugin deactivate
46
+ register_deactivation_hook(__FILE__, 'backwpup_plugin_deactivate');
47
+ //Plugin uninstall
48
+ register_uninstall_hook(__FILE__, 'backwpup_plugin_uninstall');
49
+
50
+ //Version check
51
+ if (version_compare($wp_version, '2.8', '<') and version_compare(phpversion(), '5.0.0', '<')) { // Let only Activate on WordPress Version 2.8 or higher
52
+ add_action('admin_notices', create_function('', 'echo \'<div id="message" class="error fade"><p><strong>' . __('Sorry, BackWPup works only with WordPress 2.8 and PHP 5.0.0 or higher!!!','backwpup') . '</strong></p></div>\';'));
53
+ } else {
54
+ //Plugin init
55
+ add_action('plugins_loaded', 'backwpup_init');
56
+ }
57
+ ?>
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=danie
4
  Tags: backup, admin, file, Database, mysql, cron, ftp, S3, export
5
  Requires at least: 2.8
6
  Tested up to: 3.0.0
7
- Stable tag: 1.1.1
8
 
9
  Backup and more of your WordPress Blog Database and Files
10
 
@@ -13,11 +13,11 @@ Backup and more of your WordPress Blog Database and Files
13
  Backup and more your Blog.
14
 
15
  * Database Backup
16
- * Wordpress XML Export
17
  * Optimize Database
18
  * Check\Repair Database
19
  * File Backup
20
- * Backups in zip,tar,tar.gz,tar.bz2 formart
21
  * Store backup to Folder
22
  * Store backup to FTP Server
23
  * Store backup to Amazon S3
@@ -31,12 +31,12 @@ I can give no WARRANTY to any backups...
31
 
32
  1. Download BackWPup Plugin.
33
  1. Decompress and upload the contents of the archive into /wp-content/plugins/.
34
- 1. Activate the plugin through the 'Plugins' menu in WordPress
35
 
36
  == Frequently Asked Questions ==
37
  = Requires =
38
  * PHP 5.0.0
39
- * Wordpress 2.8
40
  * curl (for Amazon S3 Support)
41
  * gzip (for PCLZIP and gzip archives)
42
  * bzip2 (for bzip2 archives)
@@ -44,54 +44,61 @@ I can give no WARRANTY to any backups...
44
  = Where is the Database dump File =
45
  in the root folder of the Archive. <i>DBName</i>.sql
46
 
47
- = Where is the Wordpress Export File =
48
  in the root folder of the Archive. wordpress.<i>jjjj-mm-dd</i>.xml
49
 
50
  = Zip File Support =
51
- Plugin use PCLZIP lib if not php uses zip extension
52
 
53
- = Mantinance Mode =
54
  Supported Plugins
55
  * maintenance-mode
56
  * wp-maintenance-mode
57
- * Wordpress .mantinance file
58
 
59
- if your blog do not come back from Mantinace Mode switsh back from Mantinace Mode by changing the Plugin options or delete the <i>.mantinance</i> file in blog root folder.
60
 
61
- = Retore a Blog DataBase =
62
- Copy the <i>DBName</i>.sql in the root folder of the blog and go to the tools tab in the plugin.
63
- You kann use PHPMyAdmin also.
64
 
65
  = Abnormal Script aborts =
66
- Webserver normaly abort Scrips that works longer then 300s.
67
- PHP normaly abort Script that works langen then 30s but the plugin try too switch off the arbotion.
68
 
69
  = Memory usage =
70
  * The Plugin is coded to use low memory
71
- * The Plugin will try to increase Memory automaticly if needed
72
- * PCLZIP lib need 8MB free Memeory for ziping
73
  * Mail a archive need many Memory
74
 
75
- = Mail achives =
76
  I have build in many options to Optimize the Mailing but the mailing lib uses high Memory.
77
- Pleace mail only littele archives
78
 
79
  == Screenshots ==
80
 
81
  1. Job Page
82
 
83
  == Changelog ==
 
 
 
 
 
 
 
84
  = 1.1.1 =
85
  * fixed S3 lib not found bug again.
86
  * improved reschedule on activation problem.
87
 
88
  = 1.1.0 =
89
- * added fuction to check/update job settings
90
- * added no ajax bucket list to job page
91
- * changed error handling a bit and remove PHP errors that can't handeld
92
- * fixed problem with not compiled --enable-memory-limit in php
93
  * removed setting for memory limit use WP filter and default now (256M)
94
- * now a time limit of 5 mins is set again for job execution but it will be resettet on every message. (prevent never ending jobs.)
95
  * added a shutdown function if __destruct not called for job
96
  * added more flexible Backup file selection
97
 
@@ -99,11 +106,11 @@ Pleace mail only littele archives
99
  * fix "Undefined index: dbshortinsert"
100
 
101
  = 1.0.9 =
102
- * change s3 class to hide warnigs
103
- * add option to make MySQL INSERTs shorter (smaler dump file size.)
104
- * add requerments checks
105
- * ajaxed S3 bucket selection in job settings
106
- * add S3 Buckt can made in job settings
107
 
108
  = 1.0.8 =
109
  * fix temp backup file not deleted if no destination folder
@@ -124,42 +131,42 @@ Pleace mail only littele archives
124
 
125
  = 1.0.4 =
126
  * fixed bugs in DB restore
127
- * use WP functions to get plugin dirs
128
 
129
  = 1.0.3 =
130
- * hopfuly fixed a chche problem on runnow
131
 
132
  = 1.0.2 =
133
- * fiexd bug for file excludes
134
 
135
  = 1.0.1 =
136
- * fiexd bug for https
137
 
138
  = 1.0.0 =
139
- * now Worpress Exports to XML can made
140
  * new backup files formats tar, tar.gz, tar.bz2
141
  * all job types can made in one job
142
- * added php zip extension support (use pclzip only if not supported)
143
  * removed PclZip trace code
144
  * fixed time display and schedule bugs
145
  * added some security
146
- * Mantinance Mode on MySQL Operations
147
  * new Design on some Pages
148
 
149
  = 0.8.1 =
150
- * use global var instat of constant for log file
151
- * PCL Zip Trace included with setting for log Level
152
 
153
  = 0.8.0 =
154
- * Fiexed not working default setttings on settingspage
155
- * crate .htaccsses on Apache and index.html on other webserver
156
  * fixed global for $wp_version
157
- * set max execution time to 0 for unlimeted
158
  * use WP function to generate options tables
159
  * Backup file list and zip creation changes
160
  * Added support for Amazon S3
161
  * Only works with PHP 5 now
162
- * Cmplete rewrite of job doing as PHP5 class
163
  * PHP errors now in Backup log
164
  * Log now in files
165
 
@@ -169,15 +176,15 @@ Pleace mail only littele archives
169
  * make date with date_i18n
170
 
171
  = 0.7.1 =
172
- * FTP Conection test changes
173
  * no Errors in Log for FTP ALLO command.
174
 
175
  = 0.7.0 =
176
  * set ftp Connection timeout to 10 sec
177
  * fix bug for DB tables exclude
178
- * DB Backup in mySQL Client encoding now
179
  * Fixed missing ; in DB Backup
180
- * Added tool DB Restore with automatic Blog Url/Path change
181
 
182
  = 0.6.5 =
183
  * Prevent direct file loading
@@ -197,7 +204,7 @@ Pleace mail only littele archives
197
  * use ftp_row for login and other commands
198
  * Add option to send only email on errors
199
  * Internal structure changes
200
- * Add option to disable WP-Cron and use Hoster cron
201
  * bug fixes
202
 
203
  = 0.6.2 =
4
  Tags: backup, admin, file, Database, mysql, cron, ftp, S3, export
5
  Requires at least: 2.8
6
  Tested up to: 3.0.0
7
+ Stable tag: 1.2.0
8
 
9
  Backup and more of your WordPress Blog Database and Files
10
 
13
  Backup and more your Blog.
14
 
15
  * Database Backup
16
+ * WordPress XML Export
17
  * Optimize Database
18
  * Check\Repair Database
19
  * File Backup
20
+ * Backups in zip,tar,tar.gz,tar.bz2 format
21
  * Store backup to Folder
22
  * Store backup to FTP Server
23
  * Store backup to Amazon S3
31
 
32
  1. Download BackWPup Plugin.
33
  1. Decompress and upload the contents of the archive into /wp-content/plugins/.
34
+ 1. Activate the Plugin through the 'Plugins' menu in WordPress
35
 
36
  == Frequently Asked Questions ==
37
  = Requires =
38
  * PHP 5.0.0
39
+ * WordPress 2.8
40
  * curl (for Amazon S3 Support)
41
  * gzip (for PCLZIP and gzip archives)
42
  * bzip2 (for bzip2 archives)
44
  = Where is the Database dump File =
45
  in the root folder of the Archive. <i>DBName</i>.sql
46
 
47
+ = Where is the WordPress Export File =
48
  in the root folder of the Archive. wordpress.<i>jjjj-mm-dd</i>.xml
49
 
50
  = Zip File Support =
51
+ Plugin use PCLZIP lib if not PHP uses zip extension
52
 
53
+ = Maintenance Mode =
54
  Supported Plugins
55
  * maintenance-mode
56
  * wp-maintenance-mode
57
+ * WordPress .maintenance file
58
 
59
+ if your Blog do not come back from Maintenance Mode switch back from Maintenance Mode by changing the Plugin options or delete the <i>.maintenance</i> file in Blog root folder.
60
 
61
+ = Restore a Blog Database =
62
+ Copy the <i>DBName</i>.sql in the root folder of the Blog and go to the tools tab in the Plugin.
63
+ You can use PHPMyAdmin also.
64
 
65
  = Abnormal Script aborts =
66
+ Webserver normally abort Scrips that works longer then 300s.
67
+ PHP normally abort Script that works longer then 30s but the Plugin try too switch off the abortion.
68
 
69
  = Memory usage =
70
  * The Plugin is coded to use low memory
71
+ * The Plugin will try to increase Memory automatically if needed
72
+ * PCLZIP lib need 8MB free Memory for zipping
73
  * Mail a archive need many Memory
74
 
75
+ = Mail archives =
76
  I have build in many options to Optimize the Mailing but the mailing lib uses high Memory.
77
+ Place mail only little archives
78
 
79
  == Screenshots ==
80
 
81
  1. Job Page
82
 
83
  == Changelog ==
84
+ = 1.2.0 =
85
+ * Backup file size now in log file
86
+ * Paged Logs Table
87
+ * added Backup Archives Page
88
+ * Grammar fixes
89
+ * Bug fixes
90
+
91
  = 1.1.1 =
92
  * fixed S3 lib not found bug again.
93
  * improved reschedule on activation problem.
94
 
95
  = 1.1.0 =
96
+ * added function to check/update job settings
97
+ * added no Ajax bucket list to job page
98
+ * changed error handling a bit and remove PHP errors that can't handled
99
+ * fixed problem with not compiled --enable-memory-limit in PHP
100
  * removed setting for memory limit use WP filter and default now (256M)
101
+ * now a time limit of 5 mins. is set again for job execution but it will be reseted on every message. (prevent never ending jobs.)
102
  * added a shutdown function if __destruct not called for job
103
  * added more flexible Backup file selection
104
 
106
  * fix "Undefined index: dbshortinsert"
107
 
108
  = 1.0.9 =
109
+ * change s3 class to hide warnings
110
+ * add option to make MySQL INSERTs shorter (smaller dump file size.)
111
+ * add requirements checks
112
+ * Ajaxed S3 bucket selection in job settings
113
+ * add S3 Bucket can made in job settings
114
 
115
  = 1.0.8 =
116
  * fix temp backup file not deleted if no destination folder
131
 
132
  = 1.0.4 =
133
  * fixed bugs in DB restore
134
+ * use WP functions to get Plugin dirs
135
 
136
  = 1.0.3 =
137
+ * hopefully fixed a cache problem on run now
138
 
139
  = 1.0.2 =
140
+ * fixed bug for file excludes
141
 
142
  = 1.0.1 =
143
+ * fixed bug for https
144
 
145
  = 1.0.0 =
146
+ * now WordPress Exports to XML can made
147
  * new backup files formats tar, tar.gz, tar.bz2
148
  * all job types can made in one job
149
+ * added PHP zip extension support (use pclzip only if not supported)
150
  * removed PclZip trace code
151
  * fixed time display and schedule bugs
152
  * added some security
153
+ * Maintenance Mode on MySQL Operations
154
  * new Design on some Pages
155
 
156
  = 0.8.1 =
157
+ * use global var instead of constant for log file
158
+ * PCLZip Trace included with setting for log Level
159
 
160
  = 0.8.0 =
161
+ * Fixed not working default settings on settings page
162
+ * crate .htaccsses on Apache and index.html on other Webserver
163
  * fixed global for $wp_version
164
+ * set max execution time to 0 for unlimited
165
  * use WP function to generate options tables
166
  * Backup file list and zip creation changes
167
  * Added support for Amazon S3
168
  * Only works with PHP 5 now
169
+ * Complete rewrite of job doing as PHP5 class
170
  * PHP errors now in Backup log
171
  * Log now in files
172
 
176
  * make date with date_i18n
177
 
178
  = 0.7.1 =
179
+ * FTP Connection test changes
180
  * no Errors in Log for FTP ALLO command.
181
 
182
  = 0.7.0 =
183
  * set ftp Connection timeout to 10 sec
184
  * fix bug for DB tables exclude
185
+ * DB Backup in MySQL Client encoding now
186
  * Fixed missing ; in DB Backup
187
+ * Added tool DB Restore with automatic Blog URL/Path change
188
 
189
  = 0.6.5 =
190
  * Prevent direct file loading
204
  * use ftp_row for login and other commands
205
  * Add option to send only email on errors
206
  * Internal structure changes
207
+ * Add option to disable WP-Cron and use Hosters cron
208
  * bug fixes
209
 
210
  = 0.6.2 =