InfiniteWP Client - Version 1.0.4

Version Description

  • Premium addons compatibility
  • Clearing cache and sending WP data
  • Bugs fixed
Download this release

Release Info

Developer infinitewp
Plugin Icon 128x128 InfiniteWP Client
Version 1.0.4
Comparing to
See all releases

Code changes from version 1.0.3 to 1.0.4

addons/backup_repository/backup_repository.class.php ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class IWP_MMB_Backup_Repository extends IWP_MMB_Backup
3
+ {
4
+ /*var $site_name;
5
+ var $statuses;
6
+ var $tasks;
7
+ var $s3;
8
+ var $ftp;
9
+ var $dropbox;
10
+
11
+ function __construct()
12
+ {
13
+ parent::__construct();
14
+ $this->site_name = str_replace(array(
15
+ "_",
16
+ "/"
17
+ ), array(
18
+ "",
19
+ "-"
20
+ ), rtrim($this->remove_http(get_bloginfo('url')), "/"));
21
+ $this->statuses = array(
22
+ 'db_dump' => 1,
23
+ 'db_zip' => 2,
24
+ 'files_zip' => 3,
25
+ 's3' => 4,
26
+ 'dropbox' => 5,
27
+ 'ftp' => 6,
28
+ 'email' => 7,
29
+ 'finished' => 100
30
+ );
31
+
32
+ $this->tasks = get_option('iwp_client_backup_tasks');
33
+ }*/
34
+
35
+ function backup_repository($args){
36
+
37
+
38
+ if (!empty($args))
39
+ extract($args);
40
+
41
+ $tasks = $this->tasks;
42
+ $task = $tasks['Backup Now'];
43
+
44
+ @ini_set('memory_limit', '256M');
45
+ @set_time_limit(1200);
46
+
47
+ if (!empty($task)) {
48
+ extract($task['task_args']);
49
+ }
50
+
51
+ $results = $task['task_results'];
52
+
53
+ if (is_array($results) && count($results)) {
54
+ $backup_file = $results[count($results) - 1]['server']['file_path'];
55
+ }
56
+
57
+
58
+ if ($backup_file && file_exists($backup_file)) {
59
+ //FTP, Amazon S3 or Dropbox
60
+ if (isset($account_info['iwp_ftp']) && !empty($account_info)) {
61
+ $account_info['iwp_ftp']['backup_file'] = $backup_file;
62
+ $return = $this->ftp_backup($account_info['iwp_ftp']);
63
+ }
64
+
65
+ if (isset($account_info['iwp_amazon_s3']) && !empty($account_info['iwp_amazon_s3'])) {
66
+ $account_info['iwp_amazon_s3']['backup_file'] = $backup_file;
67
+ $return = $this->amazons3_backup($account_info['iwp_amazon_s3']);
68
+ }
69
+
70
+ if (isset($account_info['iwp_dropbox']) && !empty($account_info['iwp_dropbox'])) {
71
+ $account_info['iwp_dropbox']['backup_file'] = $backup_file;
72
+ $return = $this->dropbox_backup($account_info['iwp_dropbox']);
73
+ }
74
+
75
+ if (isset($account_info['iwp_email']) && !empty($account_info['iwp_email'])) {
76
+ $account_info['iwp_email']['file_path'] = $backup_file;
77
+ $account_info['iwp_email']['task_name'] = 'Backup Now';
78
+ $return = $this->email_backup($account_info['iwp_email']);
79
+ }
80
+
81
+
82
+ if ($return == true && $del_host_file) {
83
+ @unlink($backup_file);
84
+ unset($tasks['Backup Now']['task_results'][count($results) - 1]['server']);
85
+ $this->update_tasks($tasks);
86
+ //update_option('iwp_client_backup_tasks', $tasks);
87
+ }
88
+
89
+ } else {
90
+ $return = array(
91
+ 'error' => 'Backup file not found on your server. Please try again.'
92
+ );
93
+ }
94
+
95
+ return $return;
96
+
97
+ }
98
+ /*
99
+ function ftp_backup($args)
100
+ {
101
+ extract($args);
102
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder, $ftp_site_folder
103
+ $port = $ftp_port ? $ftp_port : 21; //default port is 21
104
+ if ($ftp_ssl) {
105
+ if (function_exists('ftp_ssl_connect')) {
106
+ $conn_id = ftp_ssl_connect($ftp_hostname,$port);
107
+ } else {
108
+ return array(
109
+ 'error' => 'Your server doesn\'t support SFTP',
110
+ 'partial' => 1
111
+ );
112
+ }
113
+ } else {
114
+ if (function_exists('ftp_connect')) {
115
+ $conn_id = ftp_connect($ftp_hostname,$port);
116
+ if ($conn_id === false) {
117
+ return array(
118
+ 'error' => 'Failed to connect to ' . $ftp_hostname,
119
+ 'partial' => 1
120
+ );
121
+ }
122
+ } else {
123
+ return array(
124
+ 'error' => 'Your server doesn\'t support FTP',
125
+ 'partial' => 1
126
+ );
127
+ }
128
+ }
129
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
130
+ if ($login === false) {
131
+ return array(
132
+ 'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
133
+ 'partial' => 1
134
+ );
135
+ }
136
+
137
+ if($ftp_passive){
138
+ @ftp_pasv($conn_id,true);
139
+ }
140
+
141
+ @ftp_mkdir($conn_id, $ftp_remote_folder);
142
+ if ($ftp_site_folder) {
143
+ $ftp_remote_folder .= '/' . $this->site_name;
144
+ }
145
+ @ftp_mkdir($conn_id, $ftp_remote_folder);
146
+
147
+ $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_BINARY);
148
+
149
+ if ($upload === false) { //Try ascii
150
+ $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_ASCII);
151
+ }
152
+ ftp_close($conn_id);
153
+
154
+ if ($upload === false) {
155
+ return array(
156
+ 'error' => 'Failed to upload file to FTP. Please check your specified path.',
157
+ 'partial' => 1
158
+ );
159
+ }
160
+
161
+ return true;
162
+ }
163
+
164
+ function remove_ftp_backup($args)
165
+ {
166
+ extract($args);
167
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
168
+ $port = $ftp_port ? $ftp_port : 21; //default port is 21
169
+ if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
170
+ $conn_id = ftp_ssl_connect($ftp_hostname,$port);
171
+ } else if (function_exists('ftp_connect')) {
172
+ $conn_id = ftp_connect($ftp_hostname,$port);
173
+ }
174
+
175
+ if ($conn_id) {
176
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
177
+ if ($ftp_site_folder)
178
+ $ftp_remote_folder .= '/' . $this->site_name;
179
+
180
+ if($ftp_passive){
181
+ @ftp_pasv($conn_id,true);
182
+ }
183
+
184
+ $delete = ftp_delete($conn_id, $ftp_remote_folder . '/' . $backup_file);
185
+
186
+ ftp_close($conn_id);
187
+ }
188
+
189
+ }
190
+
191
+ function get_ftp_backup($args)
192
+ {
193
+ extract($args);
194
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
195
+ $port = $ftp_port ? $ftp_port : 21; //default port is 21
196
+ if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
197
+ $conn_id = ftp_ssl_connect($ftp_hostname,$port);
198
+
199
+ } else if (function_exists('ftp_connect')) {
200
+ $conn_id = ftp_connect($ftp_hostname,$port);
201
+ if ($conn_id === false) {
202
+ return false;
203
+ }
204
+ }
205
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
206
+ if ($login === false) {
207
+ return false;
208
+ } else {
209
+ }
210
+
211
+ if ($ftp_site_folder)
212
+ $ftp_remote_folder .= '/' . $this->site_name;
213
+
214
+ if($ftp_passive){
215
+ @ftp_pasv($conn_id,true);
216
+ }
217
+
218
+ $temp = ABSPATH . 'iwp_temp_backup.zip';
219
+ $get = ftp_get($conn_id, $temp, $ftp_remote_folder . '/' . $backup_file, FTP_BINARY);
220
+ if ($get === false) {
221
+ return false;
222
+ } else {
223
+
224
+ }
225
+ ftp_close($conn_id);
226
+
227
+ return $temp;
228
+ }
229
+
230
+ function amazons3_backup($args)
231
+ {
232
+ if ($this->iwp_mmb_function_exists('curl_init')) {
233
+ require_once($iwp_mmb_plugin_dir.'/lib/s3.php');
234
+ extract($args);
235
+
236
+ if ($as3_site_folder == true)
237
+ $as3_directory .= '/' . $this->site_name;
238
+
239
+ $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
240
+
241
+ $s3 = new S3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
242
+
243
+ $s3->putBucket($as3_bucket, S3::ACL_PUBLIC_READ);
244
+
245
+ if ($s3->putObjectFile($backup_file, $as3_bucket, $as3_directory . '/' . basename($backup_file), S3::ACL_PRIVATE)) {
246
+ return true;
247
+ } else {
248
+ return array(
249
+ 'error' => 'Failed to upload to Amazon S3. Please check your details and set upload/delete permissions on your bucket.',
250
+ 'partial' => 1
251
+ );
252
+ }
253
+ } else {
254
+ return array(
255
+ 'error' => 'You cannot use Amazon S3 on your server. Please enable curl first.',
256
+ 'partial' => 1
257
+ );
258
+ }
259
+ }
260
+
261
+ function remove_amazons3_backup($args)
262
+ {
263
+ require_once($iwp_mmb_plugin_dir.'/lib/s3.php');
264
+ extract($args);
265
+ if ($as3_site_folder == true)
266
+ $as3_directory .= '/' . $this->site_name;
267
+ $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
268
+ $s3 = new S3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
269
+ $s3->deleteObject($as3_bucket, $as3_directory . '/' . $backup_file);
270
+ }
271
+
272
+ function get_amazons3_backup($args)
273
+ {
274
+ require_once($iwp_mmb_plugin_dir.'/lib/s3.php');
275
+ extract($args);
276
+ $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
277
+ $s3 = new S3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
278
+ if ($as3_site_folder == true)
279
+ $as3_directory .= '/' . $this->site_name;
280
+
281
+ $temp = ABSPATH . 'iwp_temp_backup.zip';
282
+ $s3->getObject($as3_bucket, $as3_directory . '/' . $backup_file, $temp);
283
+
284
+ return $temp;
285
+ }
286
+
287
+ function dropbox_backup($args)
288
+ {
289
+
290
+ extract($args);
291
+
292
+ if(isset($consumer_secret) && !empty($consumer_secret)){
293
+ //New way
294
+ require_once($iwp_mmb_plugin_dir.'/lib/dropbox.oauth.php');
295
+
296
+ $dropbox = new Dropbox($consumer_key, $consumer_secret);
297
+ $dropbox->setOAuthToken($oauth_token);
298
+ $dropbox->setOAuthTokenSecret($oauth_token_secret);
299
+
300
+ if ($dropbox_site_folder == true)
301
+ $dropbox_destination .= '/' . $this->site_name;
302
+
303
+ try{
304
+
305
+ $dropbox->filesPost($dropbox_destination, $backup_file,true);
306
+
307
+ } catch(Exception $e){
308
+ return array(
309
+ 'error' => 'Dropbox upload error. '.$e->getMessage()
310
+ );
311
+ }
312
+
313
+ return true;
314
+
315
+ } else {
316
+ //old way
317
+ require_once($iwp_mmb_plugin_dir.'/lib/dropbox.php');
318
+ // extract($args);
319
+
320
+ //$email, $password, $backup_file, $destination, $dropbox_site_folder
321
+
322
+ $size = ceil(filesize($backup_file) / 1024);
323
+ if ($size > 300000) {
324
+ return array(
325
+ 'error' => 'Cannot upload file to Dropbox. Dropbox has upload limit of 300Mb per file.',
326
+ 'partial' => 1
327
+ );
328
+ }
329
+
330
+ if ($dropbox_site_folder == true)
331
+ $dropbox_destination .= '/' . $this->site_name;
332
+
333
+ try {
334
+ $uploader = new DropboxUploader($dropbox_username, $dropbox_password);
335
+ $uploader->upload($backup_file, $dropbox_destination);
336
+ }
337
+ catch (Exception $e) {
338
+ return array(
339
+ 'error' => $e->getMessage(),
340
+ 'partial' => 1
341
+ );
342
+ }
343
+
344
+ return true;
345
+ }
346
+
347
+ }
348
+
349
+ function remove_dropbox_backup($args){
350
+ extract($args);
351
+ if(isset($consumer_secret) && !empty($consumer_secret)){
352
+ //New way
353
+ require_once($iwp_mmb_plugin_dir.'/lib/dropbox.oauth.php');
354
+
355
+ $dropbox = new Dropbox($consumer_key, $consumer_secret);
356
+ $dropbox->setOAuthToken($oauth_token);
357
+ $dropbox->setOAuthTokenSecret($oauth_token_secret);
358
+
359
+ if ($dropbox_site_folder == true)
360
+ $dropbox_destination .= '/' . $this->site_name;
361
+
362
+ try{
363
+ $dropbox->fileopsDelete($dropbox_destination.'/'.$backup_file, true);
364
+ } catch(Exception $e){
365
+
366
+ }
367
+ }
368
+ }
369
+
370
+ function get_dropbox_backup($args){
371
+ extract($args);
372
+
373
+ if(isset($consumer_secret) && !empty($consumer_secret)){
374
+ //New way
375
+ require_once($iwp_mmb_plugin_dir.'/lib/dropbox.oauth.php');
376
+
377
+ $dropbox = new Dropbox($consumer_key, $consumer_secret);
378
+ $dropbox->setOAuthToken($oauth_token);
379
+ $dropbox->setOAuthTokenSecret($oauth_token_secret);
380
+
381
+ if ($dropbox_site_folder == true)
382
+ $dropbox_destination .= '/' . $this->site_name;
383
+
384
+ $temp = ABSPATH . 'iwp_temp_backup.zip';
385
+
386
+ try{
387
+ $file = $dropbox->filesGet($dropbox_destination.'/'.$backup_file, true);
388
+
389
+ if(isset($file['data']) && !empty($file['data']) )
390
+ $stream = base64_decode($file['data']);
391
+ else
392
+ return false;
393
+
394
+ $handle = @fopen($temp, 'w+');
395
+ $result = fwrite($handle,$stream);
396
+ fclose($handle);
397
+
398
+ if($result)
399
+ return $temp;
400
+ else
401
+ return false;
402
+
403
+ } catch(Exception $e){
404
+
405
+
406
+ return false;
407
+ }
408
+
409
+ } else {
410
+ return false;
411
+ }
412
+ }
413
+
414
+ function email_backup($args)
415
+ {
416
+ $email = $args['email'];
417
+
418
+ if (!is_email($email)) {
419
+ return array(
420
+ 'error' => 'Your email (' . $email . ') is not correct'
421
+ );
422
+ }
423
+ $backup_file = $args['file_path'];
424
+ $task_name = isset($args['task_name']) ? $args['task_name'] : '';
425
+ if (file_exists($backup_file) && $email) {
426
+ $attachments = array(
427
+ $backup_file
428
+ );
429
+ $headers = 'From: InfiniteWP <no-reply@infinitewp.com>' . "\r\n";
430
+ $subject = "InfiniteWP - " . $task_name . " - " . $this->site_name;
431
+ ob_start();
432
+ $result = wp_mail($email, $subject, $subject, $headers, $attachments);
433
+ ob_end_clean();
434
+
435
+ }
436
+
437
+ if (!$result) {
438
+ return array(
439
+ 'error' => 'Email not sent. Maybe your backup is too big for email or email server is not available on your website.'
440
+ );
441
+ }
442
+ return true;
443
+
444
+ }
445
+
446
+ function update_tasks($tasks)
447
+ {
448
+ $this->tasks = $tasks;
449
+ update_option('iwp_client_backup_tasks', $tasks);
450
+ }*/
451
+
452
+ }
453
+ ?>
backup.class.php CHANGED
@@ -121,8 +121,18 @@ class IWP_MMB_Backup extends IWP_MMB_Core
121
  'removed' => true
122
  );
123
  } else {
 
 
 
 
124
 
125
  $before[$task_name]['task_args'] = $args;
 
 
 
 
 
 
126
  $return = $before[$task_name];
127
  }
128
 
@@ -224,6 +234,50 @@ class IWP_MMB_Backup extends IWP_MMB_Core
224
 
225
  }
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  /*
228
  * If Task Name not set then it's manual backup
229
  * Backup args:
@@ -360,7 +414,24 @@ class IWP_MMB_Backup extends IWP_MMB_Core
360
  'file_url' => $backup_url
361
  );
362
  }
363
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  $temp = $backup_settings[$task_name]['task_results'];
365
  $temp = @array_values($temp);
366
  $paths['time'] = time();
@@ -380,8 +451,68 @@ class IWP_MMB_Backup extends IWP_MMB_Core
380
  }
381
 
382
  //Additional: Email, ftp, amazon_s3, dropbox...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
 
384
- if ($task_name != 'Backup Now') {
385
  if ($del_host_file) {
386
  @unlink($backup_file);
387
  }
@@ -749,6 +880,44 @@ class IWP_MMB_Backup extends IWP_MMB_Core
749
  $unlink_file = false; //Don't delete file if stored on server
750
  }
751
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  $what = $tasks[$task_name]['task_args']['what'];
753
  }
754
 
@@ -930,11 +1099,8 @@ class IWP_MMB_Backup extends IWP_MMB_Core
930
  }
931
 
932
  }
933
-
934
-
935
-
936
-
937
- return true;
938
  }
939
 
940
  function restore_db()
@@ -1212,6 +1378,428 @@ class IWP_MMB_Backup extends IWP_MMB_Core
1212
  return $reqs;
1213
  }
1214
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1215
  //Parse task arguments for info on IWP Admin Panel
1216
  function get_backup_stats()
1217
  {
@@ -1236,6 +1824,22 @@ class IWP_MMB_Backup extends IWP_MMB_Core
1236
  return $stats;
1237
  }
1238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1239
  function remove_old_backups($task_name)
1240
  {
1241
  //Check for previous failed backups first
@@ -1259,6 +1863,27 @@ class IWP_MMB_Backup extends IWP_MMB_Core
1259
  @unlink($backups[$task_name]['task_results'][$i]['server']['file_path']);
1260
  }
1261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1262
  //Remove database backup info
1263
  unset($backups[$task_name]['task_results'][$i]);
1264
 
@@ -1293,6 +1918,33 @@ class IWP_MMB_Backup extends IWP_MMB_Core
1293
  if (isset($backup['server'])) {
1294
  @unlink($backup['server']['file_path']);
1295
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1296
  unset($backups[$result_id]);
1297
 
1298
  if (count($backups)) {
@@ -1327,7 +1979,7 @@ class IWP_MMB_Backup extends IWP_MMB_Core
1327
 
1328
 
1329
  //clean_old folder?
1330
- if ((basename($files[0]) == 'index.php' && count($files) == 1) || (empty($files))) {
1331
  foreach ($files as $file) {
1332
  @unlink($file);
1333
  }
@@ -1335,7 +1987,7 @@ class IWP_MMB_Backup extends IWP_MMB_Core
1335
  @rmdir(WP_CONTENT_DIR . '/' . md5('iwp_mmb-client'));
1336
  }
1337
 
1338
-
1339
  foreach ($new as $b) {
1340
  $files[] = $b;
1341
  }
121
  'removed' => true
122
  );
123
  } else {
124
+
125
+ if (is_array($params['account_info'])) { //only if sends from IWP Admin Panel first time(secure data)
126
+ $args['account_info'] = $account_info;
127
+ }
128
 
129
  $before[$task_name]['task_args'] = $args;
130
+ //$before[$task_name]['task_args'] = $task_name;
131
+
132
+ if (strlen($args['schedule']))
133
+ $before[$task_name]['task_args']['next'] = $this->schedule_next($args['type'], $args['schedule']);
134
+ $before[$task_name]['task_args']['task_name'] = $task_name;
135
+
136
  $return = $before[$task_name];
137
  }
138
 
234
 
235
  }
236
 
237
+
238
+ function task_now($task_name){
239
+
240
+ $settings = $this->tasks;
241
+ if(!array_key_exists($task_name,$settings)){
242
+ return array('error' => $task_name." does not exist.");
243
+ } else {
244
+ $setting = $settings[$task_name];
245
+ }
246
+
247
+ $this->set_backup_task(array(
248
+ 'task_name' => $task_name,
249
+ 'args' => $settings[$task_name]['task_args'],
250
+ 'time' => time()
251
+ ));
252
+
253
+ //Run backup
254
+ $result = $this->backup($setting['task_args'], $task_name);
255
+
256
+ //Check for error
257
+ if (is_array($result) && array_key_exists('error', $result)) {
258
+ $this->set_backup_task(array(
259
+ 'task_name' => $task_name,
260
+ 'args' => $settings[$task_name]['task_args'],
261
+ 'error' => $result['error']
262
+ ));
263
+ return $result;
264
+ } else {
265
+ return $this->get_backup_stats();
266
+ }
267
+
268
+ }
269
+
270
+ function delete_task_now($task_name){
271
+ $tasks = $this->tasks;
272
+ unset($tasks[$task_name]);
273
+ $this->update_tasks($tasks);
274
+ $this->cleanup();
275
+
276
+ return $task_name;
277
+
278
+ }
279
+
280
+
281
  /*
282
  * If Task Name not set then it's manual backup
283
  * Backup args:
414
  'file_url' => $backup_url
415
  );
416
  }
417
+
418
+
419
+ if (isset($backup_settings[$task_name]['task_args']['account_info']['iwp_ftp'])) {
420
+ $paths['ftp'] = basename($backup_url);
421
+ }
422
+
423
+ if (isset($backup_settings[$task_name]['task_args']['account_info']['iwp_amazon_s3'])) {
424
+ $paths['amazons3'] = basename($backup_url);
425
+ }
426
+
427
+ if (isset($backup_settings[$task_name]['task_args']['account_info']['iwp_dropbox'])) {
428
+ $paths['dropbox'] = basename($backup_url);
429
+ }
430
+
431
+ if (isset($backup_settings[$task_name]['task_args']['account_info']['iwp_email'])) {
432
+ $paths['email'] = basename($backup_url);
433
+ }
434
+
435
  $temp = $backup_settings[$task_name]['task_results'];
436
  $temp = @array_values($temp);
437
  $paths['time'] = time();
451
  }
452
 
453
  //Additional: Email, ftp, amazon_s3, dropbox...
454
+ /*
455
+ //IWP Remove starts here //IWP Remove ends here
456
+ */
457
+ if ($task_name != 'Backup Now') {
458
+
459
+ if (isset($account_info['iwp_ftp']) && !empty($account_info['iwp_ftp'])) {
460
+ $this->update_status($task_name, $this->statuses['ftp']);
461
+ $account_info['iwp_ftp']['backup_file'] = $backup_file;
462
+ $ftp_result = $this->ftp_backup($account_info['iwp_ftp']);
463
+
464
+ if ($ftp_result !== true && $del_host_file) {
465
+ @unlink($backup_file);
466
+ }
467
+
468
+ if (is_array($ftp_result) && isset($ftp_result['error'])) {
469
+ return $ftp_result;
470
+ }
471
+ $this->wpdb_reconnect();
472
+ $this->update_status($task_name, $this->statuses['ftp'], true);
473
+ }
474
+
475
+ if (isset($account_info['iwp_amazon_s3']) && !empty($account_info['iwp_amazon_s3'])) {
476
+ $this->update_status($task_name, $this->statuses['s3']);
477
+ $account_info['iwp_amazon_s3']['backup_file'] = $backup_file;
478
+ $amazons3_result = $this->amazons3_backup($account_info['iwp_amazon_s3']);
479
+ if ($amazons3_result !== true && $del_host_file) {
480
+ @unlink($backup_file);
481
+ }
482
+ if (is_array($amazons3_result) && isset($amazons3_result['error'])) {
483
+ return $amazons3_result;
484
+ }
485
+ $this->wpdb_reconnect();
486
+ $this->update_status($task_name, $this->statuses['s3'], true);
487
+ }
488
+
489
+ if (isset($account_info['iwp_dropbox']) && !empty($account_info['iwp_dropbox'])) {
490
+ $this->update_status($task_name, $this->statuses['dropbox']);
491
+ $account_info['iwp_dropbox']['backup_file'] = $backup_file;
492
+ $dropbox_result = $this->dropbox_backup($account_info['iwp_dropbox']);
493
+ if ($dropbox_result !== true && $del_host_file) {
494
+ @unlink($backup_file);
495
+ }
496
+
497
+ if (is_array($dropbox_result) && isset($dropbox_result['error'])) {
498
+ return $dropbox_result;
499
+ }
500
+ $this->wpdb_reconnect();
501
+ $this->update_status($task_name, $this->statuses['dropbox'], true);
502
+ }
503
+
504
+ if (isset($account_info['iwp_email']) && !empty($account_info['iwp_email'])) {
505
+ $this->update_status($task_name, $this->statuses['email']);
506
+ $account_info['iwp_email']['task_name'] = $task_name;
507
+ $account_info['iwp_email']['file_path'] = $backup_file;
508
+
509
+ $email_result = $this->email_backup($account_info['iwp_email']);
510
+ if (is_array($email_result) && isset($email_result['error'])) {
511
+ return $email_result;
512
+ }
513
+ $this->update_status($task_name, $this->statuses['email'], true);
514
+ }
515
 
 
516
  if ($del_host_file) {
517
  @unlink($backup_file);
518
  }
880
  $unlink_file = false; //Don't delete file if stored on server
881
  }
882
 
883
+ /*
884
+ //IWP Remove starts here//IWP Remove ends here
885
+ */
886
+
887
+ elseif (isset($task['task_results'][$result_id]['ftp'])) {
888
+ $ftp_file = $task['task_results'][$result_id]['ftp'];
889
+ $args = $task['task_args']['account_info']['iwp_ftp'];
890
+ $args['backup_file'] = $ftp_file;
891
+ $backup_file = $this->get_ftp_backup($args);
892
+ if ($backup_file == false) {
893
+ return array(
894
+ 'error' => 'Failed to download file from FTP.'
895
+ );
896
+ }
897
+ } elseif (isset($task['task_results'][$result_id]['amazons3'])) {
898
+ $amazons3_file = $task['task_results'][$result_id]['amazons3'];
899
+ $args = $task['task_args']['account_info']['iwp_amazon_s3'];
900
+ $args['backup_file'] = $ftp_file;
901
+ $backup_file = $this->get_amazons3_backup($args);
902
+ if ($backup_file == false) {
903
+ return array(
904
+ 'error' => 'Failed to download file from Amazon S3.'
905
+ );
906
+ }
907
+ } elseif(isset($task['task_results'][$result_id]['dropbox'])){
908
+ $dropbox_file = $task['task_results'][$result_id]['dropbox'];
909
+ $args = $task['task_args']['account_info']['iwp_dropbox'];
910
+ $args['backup_file'] = $dropbox_file;
911
+ $backup_file = $this->get_dropbox_backup($args);
912
+
913
+ if ($backup_file == false) {
914
+ return array(
915
+ 'error' => 'Failed to download file from Dropbox.'
916
+ );
917
+ }
918
+ }
919
+
920
+
921
  $what = $tasks[$task_name]['task_args']['what'];
922
  }
923
 
1099
  }
1100
 
1101
  }
1102
+
1103
+ return !empty($new_user) ? $new_user : true ;
 
 
 
1104
  }
1105
 
1106
  function restore_db()
1378
  return $reqs;
1379
  }
1380
 
1381
+ function ftp_backup($args)
1382
+ {
1383
+ extract($args);
1384
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder, $ftp_site_folder
1385
+ $port = $ftp_port ? $ftp_port : 21; //default port is 21
1386
+ if ($ftp_ssl) {
1387
+ if (function_exists('ftp_ssl_connect')) {
1388
+ $conn_id = ftp_ssl_connect($ftp_hostname,$port);
1389
+ } else {
1390
+ return array(
1391
+ 'error' => 'Your server doesn\'t support SFTP',
1392
+ 'partial' => 1
1393
+ );
1394
+ }
1395
+ } else {
1396
+ if (function_exists('ftp_connect')) {
1397
+ $conn_id = ftp_connect($ftp_hostname,$port);
1398
+ if ($conn_id === false) {
1399
+ return array(
1400
+ 'error' => 'Failed to connect to ' . $ftp_hostname,
1401
+ 'partial' => 1
1402
+ );
1403
+ }
1404
+ } else {
1405
+ return array(
1406
+ 'error' => 'Your server doesn\'t support FTP',
1407
+ 'partial' => 1
1408
+ );
1409
+ }
1410
+ }
1411
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
1412
+ if ($login === false) {
1413
+ return array(
1414
+ 'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
1415
+ 'partial' => 1
1416
+ );
1417
+ }
1418
+
1419
+ if($ftp_passive){
1420
+ @ftp_pasv($conn_id,true);
1421
+ }
1422
+
1423
+ @ftp_mkdir($conn_id, $ftp_remote_folder);
1424
+ if ($ftp_site_folder) {
1425
+ $ftp_remote_folder .= '/' . $this->site_name;
1426
+ }
1427
+ @ftp_mkdir($conn_id, $ftp_remote_folder);
1428
+
1429
+ $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_BINARY);
1430
+
1431
+ if ($upload === false) { //Try ascii
1432
+ $upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_ASCII);
1433
+ }
1434
+ ftp_close($conn_id);
1435
+
1436
+ if ($upload === false) {
1437
+ return array(
1438
+ 'error' => 'Failed to upload file to FTP. Please check your specified path.',
1439
+ 'partial' => 1
1440
+ );
1441
+ }
1442
+
1443
+ return true;
1444
+ }
1445
+
1446
+ function remove_ftp_backup($args)
1447
+ {
1448
+ extract($args);
1449
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
1450
+ $port = $ftp_port ? $ftp_port : 21; //default port is 21
1451
+ if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
1452
+ $conn_id = ftp_ssl_connect($ftp_hostname,$port);
1453
+ } else if (function_exists('ftp_connect')) {
1454
+ $conn_id = ftp_connect($ftp_hostname,$port);
1455
+ }
1456
+
1457
+ if ($conn_id) {
1458
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
1459
+ if ($ftp_site_folder)
1460
+ $ftp_remote_folder .= '/' . $this->site_name;
1461
+
1462
+ if($ftp_passive){
1463
+ @ftp_pasv($conn_id,true);
1464
+ }
1465
+
1466
+ $delete = ftp_delete($conn_id, $ftp_remote_folder . '/' . $backup_file);
1467
+
1468
+ ftp_close($conn_id);
1469
+ }
1470
+
1471
+ }
1472
+
1473
+ function get_ftp_backup($args)
1474
+ {
1475
+ extract($args);
1476
+ //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
1477
+ $port = $ftp_port ? $ftp_port : 21; //default port is 21
1478
+ if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
1479
+ $conn_id = ftp_ssl_connect($ftp_hostname,$port);
1480
+
1481
+ } else if (function_exists('ftp_connect')) {
1482
+ $conn_id = ftp_connect($ftp_hostname,$port);
1483
+ if ($conn_id === false) {
1484
+ return false;
1485
+ }
1486
+ }
1487
+ $login = @ftp_login($conn_id, $ftp_username, $ftp_password);
1488
+ if ($login === false) {
1489
+ return false;
1490
+ } else {
1491
+ }
1492
+
1493
+ if ($ftp_site_folder)
1494
+ $ftp_remote_folder .= '/' . $this->site_name;
1495
+
1496
+ if($ftp_passive){
1497
+ @ftp_pasv($conn_id,true);
1498
+ }
1499
+
1500
+ $temp = ABSPATH . 'iwp_temp_backup.zip';
1501
+ $get = ftp_get($conn_id, $temp, $ftp_remote_folder . '/' . $backup_file, FTP_BINARY);
1502
+ if ($get === false) {
1503
+ return false;
1504
+ } else {
1505
+ }
1506
+ ftp_close($conn_id);
1507
+
1508
+ return $temp;
1509
+ }
1510
+
1511
+
1512
+ function dropbox_backup($args)
1513
+ {
1514
+
1515
+ extract($args);
1516
+
1517
+ if(isset($consumer_secret) && !empty($consumer_secret)){
1518
+ //New way
1519
+ require_once('lib/dropbox.oauth.php');
1520
+
1521
+ $dropbox = new Dropbox($consumer_key, $consumer_secret);
1522
+ $dropbox->setOAuthToken($oauth_token);
1523
+ $dropbox->setOAuthTokenSecret($oauth_token_secret);
1524
+
1525
+ if ($dropbox_site_folder == true)
1526
+ $dropbox_destination .= '/' . $this->site_name;
1527
+
1528
+ try{
1529
+
1530
+ $dropbox->filesPost($dropbox_destination, $backup_file,true);
1531
+
1532
+ } catch(Exception $e){
1533
+ return array(
1534
+ 'error' => 'Dropbox upload error. '.$e->getMessage()
1535
+ );
1536
+ }
1537
+
1538
+ return true;
1539
+
1540
+ } else {
1541
+ //old way
1542
+ require_once('lib/dropbox.php');
1543
+ // extract($args);
1544
+
1545
+ //$email, $password, $backup_file, $destination, $dropbox_site_folder
1546
+
1547
+ $size = ceil(filesize($backup_file) / 1024);
1548
+ if ($size > 300000) {
1549
+ return array(
1550
+ 'error' => 'Cannot upload file to Dropbox. Dropbox has upload limit of 300Mb per file.',
1551
+ 'partial' => 1
1552
+ );
1553
+ }
1554
+
1555
+ if ($dropbox_site_folder == true)
1556
+ $dropbox_destination .= '/' . $this->site_name;
1557
+
1558
+ try {
1559
+ $uploader = new DropboxUploader($dropbox_username, $dropbox_password);
1560
+ $uploader->upload($backup_file, $dropbox_destination);
1561
+ }
1562
+ catch (Exception $e) {
1563
+ return array(
1564
+ 'error' => $e->getMessage(),
1565
+ 'partial' => 1
1566
+ );
1567
+ }
1568
+
1569
+ return true;
1570
+ }
1571
+
1572
+ }
1573
+
1574
+ function remove_dropbox_backup($args){
1575
+ extract($args);
1576
+ if(isset($consumer_secret) && !empty($consumer_secret)){
1577
+ //New way
1578
+ require_once('lib/dropbox.oauth.php');
1579
+
1580
+ $dropbox = new Dropbox($consumer_key, $consumer_secret);
1581
+ $dropbox->setOAuthToken($oauth_token);
1582
+ $dropbox->setOAuthTokenSecret($oauth_token_secret);
1583
+
1584
+ if ($dropbox_site_folder == true)
1585
+ $dropbox_destination .= '/' . $this->site_name;
1586
+
1587
+ try{
1588
+ $dropbox->fileopsDelete($dropbox_destination.'/'.$backup_file, true);
1589
+ } catch(Exception $e){
1590
+
1591
+ }
1592
+ }
1593
+ }
1594
+
1595
+ function get_dropbox_backup($args){
1596
+ extract($args);
1597
+
1598
+ if(isset($consumer_secret) && !empty($consumer_secret)){
1599
+ //New way
1600
+ require_once('lib/dropbox.oauth.php');
1601
+
1602
+ $dropbox = new Dropbox($consumer_key, $consumer_secret);
1603
+ $dropbox->setOAuthToken($oauth_token);
1604
+ $dropbox->setOAuthTokenSecret($oauth_token_secret);
1605
+
1606
+ if ($dropbox_site_folder == true)
1607
+ $dropbox_destination .= '/' . $this->site_name;
1608
+
1609
+ $temp = ABSPATH . 'mwp_temp_backup.zip';
1610
+
1611
+ try{
1612
+ $file = $dropbox->filesGet($dropbox_destination.'/'.$backup_file, true);
1613
+
1614
+ if(isset($file['data']) && !empty($file['data']) )
1615
+ $stream = base64_decode($file['data']);
1616
+ else
1617
+ return false;
1618
+
1619
+ $handle = @fopen($temp, 'w+');
1620
+ $result = fwrite($handle,$stream);
1621
+ fclose($handle);
1622
+
1623
+ if($result)
1624
+ return $temp;
1625
+ else
1626
+ return false;
1627
+
1628
+ } catch(Exception $e){
1629
+
1630
+
1631
+ return false;
1632
+ }
1633
+
1634
+ } else {
1635
+ return false;
1636
+ }
1637
+
1638
+
1639
+ }
1640
+
1641
+ function amazons3_backup($args)
1642
+ {
1643
+ if ($this->iwp_mmb_function_exists('curl_init')) {
1644
+ require_once('lib/s3.php');
1645
+ extract($args);
1646
+
1647
+ if ($as3_site_folder == true)
1648
+ $as3_directory .= '/' . $this->site_name;
1649
+
1650
+ $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
1651
+
1652
+ $s3 = new S3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
1653
+
1654
+ $s3->putBucket($as3_bucket, S3::ACL_PUBLIC_READ);
1655
+
1656
+ if ($s3->putObjectFile($backup_file, $as3_bucket, $as3_directory . '/' . basename($backup_file), S3::ACL_PRIVATE)) {
1657
+ return true;
1658
+ } else {
1659
+ return array(
1660
+ 'error' => 'Failed to upload to Amazon S3. Please check your details and set upload/delete permissions on your bucket.',
1661
+ 'partial' => 1
1662
+ );
1663
+ }
1664
+
1665
+ }
1666
+ else {
1667
+ return array(
1668
+ 'error' => 'You cannot use Amazon S3 on your server. Please enable curl first.',
1669
+ 'partial' => 1
1670
+ );
1671
+ }
1672
+ }
1673
+
1674
+ function remove_amazons3_backup($args)
1675
+ {
1676
+ if ($this->iwp_mmb_function_exists('curl_init')) {
1677
+ require_once('lib/s3.php');
1678
+ extract($args);
1679
+ if ($as3_site_folder == true)
1680
+ $as3_directory .= '/' . $this->site_name;
1681
+ $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
1682
+ try{
1683
+ $s3 = new S3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
1684
+ $s3->deleteObject($as3_bucket, $as3_directory . '/' . $backup_file);
1685
+ } catch (Exception $e){
1686
+
1687
+ }
1688
+ }
1689
+ }
1690
+
1691
+ function get_amazons3_backup($args)
1692
+ {
1693
+ require_once('lib/s3.php');
1694
+ extract($args);
1695
+ $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
1696
+ $temp = '';
1697
+ try{
1698
+ $s3 = new S3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
1699
+ if ($as3_site_folder == true)
1700
+ $as3_directory .= '/' . $this->site_name;
1701
+
1702
+ $temp = ABSPATH . 'iwp_temp_backup.zip';
1703
+ $s3->getObject($as3_bucket, $as3_directory . '/' . $backup_file, $temp);
1704
+ } catch (Exception $e){
1705
+ return $temp;
1706
+ }
1707
+ return $temp;
1708
+ }
1709
+ //IWP Remove ends here
1710
+
1711
+
1712
+ function schedule_next($type, $schedule)
1713
+ {
1714
+ $schedule = explode("|", $schedule);
1715
+ if (empty($schedule))
1716
+ return false;
1717
+ switch ($type) {
1718
+
1719
+ case 'daily':
1720
+
1721
+ if (isset($schedule[1]) && $schedule[1]) {
1722
+ $delay_time = $schedule[1] * 60;
1723
+ }
1724
+
1725
+ $current_hour = date("H");
1726
+ $schedule_hour = $schedule[0];
1727
+ if ($current_hour >= $schedule_hour){
1728
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d") + 1, date("Y"));
1729
+ //$time ='0001#'.$current_hour.'|'.$schedule_hour;
1730
+
1731
+ }
1732
+
1733
+ else{
1734
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
1735
+ //$time ='0000#'.$current_hour.'|'.$schedule_hour;
1736
+ }
1737
+ $time = time() + 30;
1738
+
1739
+ file_put_contents("timetest.txt", var_export($time, true).'|'.var_export($schedule_hour, true).'|'.var_export($current_hour, true));
1740
+ break;
1741
+
1742
+
1743
+ case 'weekly':
1744
+ if (isset($schedule[2]) && $schedule[2]) {
1745
+ $delay_time = $schedule[2] * 60;
1746
+ }
1747
+ $current_weekday = date('w');
1748
+ $schedule_weekday = $schedule[1];
1749
+ $current_hour = date("H");
1750
+ $schedule_hour = $schedule[0];
1751
+
1752
+ if ($current_weekday > $schedule_weekday)
1753
+ $weekday_offset = 7 - ($week_day - $task_schedule[1]);
1754
+ else
1755
+ $weekday_offset = $schedule_weekday - $current_weekday;
1756
+
1757
+
1758
+ if (!$weekday_offset) { //today is scheduled weekday
1759
+ if ($current_hour >= $schedule_hour)
1760
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d") + 7, date("Y"));
1761
+ else
1762
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
1763
+ } else {
1764
+ $time = mktime($schedule_hour, 0, 0, date("m"), date("d") + $weekday_offset, date("Y"));
1765
+ }
1766
+
1767
+ break;
1768
+
1769
+ case 'monthly':
1770
+ if (isset($schedule[2]) && $schedule[2]) {
1771
+ $delay_time = $schedule[2] * 60;
1772
+ }
1773
+ $current_monthday = date('j');
1774
+ $schedule_monthday = $schedule[1];
1775
+ $current_hour = date("H");
1776
+ $schedule_hour = $schedule[0];
1777
+
1778
+ if ($current_monthday > $schedule_monthday) {
1779
+ $time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
1780
+ } else if ($current_monthday < $schedule_monthday) {
1781
+ $time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
1782
+ } else if ($current_monthday == $schedule_monthday) {
1783
+ if ($current_hour >= $schedule_hour)
1784
+ $time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
1785
+ else
1786
+ $time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
1787
+ break;
1788
+ }
1789
+
1790
+ break;
1791
+ default:
1792
+ break;
1793
+ }
1794
+
1795
+ if (isset($delay_time) && $delay_time) {
1796
+ $time += $delay_time;
1797
+ }
1798
+
1799
+ return $time;
1800
+ }
1801
+
1802
+
1803
  //Parse task arguments for info on IWP Admin Panel
1804
  function get_backup_stats()
1805
  {
1824
  return $stats;
1825
  }
1826
 
1827
+ /*
1828
+ //IWP Remove starts here//IWP Remove ends here
1829
+ */
1830
+ function get_next_schedules()
1831
+ {
1832
+ $stats = array();
1833
+ $tasks = $this->tasks;
1834
+ if (is_array($tasks) && !empty($tasks)) {
1835
+ foreach ($tasks as $task_name => $info) {
1836
+ $stats[$task_name] = isset($info['task_args']['next']) ? $info['task_args']['next'] : array();
1837
+ }
1838
+ }
1839
+ return $stats;
1840
+ }
1841
+
1842
+
1843
  function remove_old_backups($task_name)
1844
  {
1845
  //Check for previous failed backups first
1863
  @unlink($backups[$task_name]['task_results'][$i]['server']['file_path']);
1864
  }
1865
 
1866
+ if (isset($backups[$task_name]['task_results'][$i]['ftp'])) {
1867
+ $ftp_file = $backups[$task_name]['task_results'][$i]['ftp'];
1868
+ $args = $backups[$task_name]['task_args']['account_info']['iwp_ftp'];
1869
+ $args['backup_file'] = $ftp_file;
1870
+ $this->remove_ftp_backup($args);
1871
+ }
1872
+
1873
+ if (isset($backups[$task_name]['task_results'][$i]['amazons3'])) {
1874
+ $amazons3_file = $backups[$task_name]['task_results'][$i]['amazons3'];
1875
+ $args = $backups[$task_name]['task_args']['account_info']['iwp_amazon_s3'];
1876
+ $args['backup_file'] = $amazons3_file;
1877
+ $this->remove_amazons3_backup($args);
1878
+ }
1879
+
1880
+ if (isset($backups[$task_name]['task_results'][$i]['dropbox']) && isset($backups[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
1881
+ //To do: dropbox remove
1882
+ $dropbox_file = $backups[$task_name]['task_results'][$i]['dropbox'];
1883
+ $args = $backups[$task_name]['task_args']['account_info']['mwp_dropbox'];
1884
+ $args['backup_file'] = $dropbox_file;
1885
+ $this->remove_dropbox_backup($args);
1886
+ }
1887
  //Remove database backup info
1888
  unset($backups[$task_name]['task_results'][$i]);
1889
 
1918
  if (isset($backup['server'])) {
1919
  @unlink($backup['server']['file_path']);
1920
  }
1921
+
1922
+ /*
1923
+ //IWP Remove starts here//IWP Remove ends here
1924
+ */
1925
+ //Remove from ftp
1926
+ if (isset($backup['ftp'])) {
1927
+ $ftp_file = $backup['ftp'];
1928
+ $args = $tasks[$task_name]['task_args']['account_info']['iwp_ftp'];
1929
+ $args['backup_file'] = $ftp_file;
1930
+ $this->remove_ftp_backup($args);
1931
+ }
1932
+
1933
+ if (isset($backup['amazons3'])) {
1934
+ $amazons3_file = $backup['amazons3'];
1935
+ $args = $tasks[$task_name]['task_args']['account_info']['iwp_amazon_s3'];
1936
+ $args['backup_file'] = $amazons3_file;
1937
+ $this->remove_amazons3_backup($args);
1938
+ }
1939
+
1940
+ if (isset($backup['dropbox'])) {
1941
+ $dropbox_file = $backup['dropbox'];
1942
+ $args = $tasks[$task_name]['task_args']['account_info']['iwp_dropbox'];
1943
+ $args['backup_file'] = $dropbox_file;
1944
+ $this->remove_dropbox_backup($args);
1945
+ }
1946
+
1947
+
1948
  unset($backups[$result_id]);
1949
 
1950
  if (count($backups)) {
1979
 
1980
 
1981
  //clean_old folder?
1982
+ if ((basename($files[0]) == 'index.php' && count($files) == 1) || (empty($files))) { //USE (!empty($files)
1983
  foreach ($files as $file) {
1984
  @unlink($file);
1985
  }
1987
  @rmdir(WP_CONTENT_DIR . '/' . md5('iwp_mmb-client'));
1988
  }
1989
 
1990
+ // USE $new = array();
1991
  foreach ($new as $b) {
1992
  $files[] = $b;
1993
  }
core.class.php CHANGED
@@ -35,6 +35,9 @@ class IWP_MMB_Core extends IWP_MMB_Helper
35
  var $installer_instance;
36
  var $iwp_mmb_multisite;
37
  var $network_admin_install;
 
 
 
38
  private $action_call;
39
  private $action_params;
40
  private $iwp_mmb_pre_init_actions;
@@ -122,6 +125,7 @@ class IWP_MMB_Core extends IWP_MMB_Helper
122
  'check_backup_compat' => 'iwp_mmb_check_backup_compat',
123
  'scheduled_backup' => 'iwp_mmb_scheduled_backup',
124
  'run_task' => 'iwp_mmb_run_task_now',
 
125
  'execute_php_code' => 'iwp_mmb_execute_php_code',
126
  'delete_backup' => 'mmm_delete_backup',
127
  'remote_backup_now' => 'iwp_mmb_remote_backup_now',
@@ -133,7 +137,9 @@ class IWP_MMB_Core extends IWP_MMB_Helper
133
  'edit_plugins_themes' => 'iwp_mmb_edit_plugins_themes',
134
  'client_brand' => 'iwp_mmb_client_brand',
135
  'set_alerts' => 'iwp_mmb_set_alerts',
136
- 'maintenance' => 'iwp_mmb_maintenance_mode'
 
 
137
  );
138
 
139
  add_action('rightnow_end', array( &$this, 'add_right_now_info' ));
@@ -379,6 +385,15 @@ class IWP_MMB_Core extends IWP_MMB_Helper
379
  return $this->backup_instance;
380
  }
381
 
 
 
 
 
 
 
 
 
 
382
  /**
383
  * Gets an instance of links class
384
  *
35
  var $installer_instance;
36
  var $iwp_mmb_multisite;
37
  var $network_admin_install;
38
+
39
+ var $backup_repository_instance;
40
+
41
  private $action_call;
42
  private $action_params;
43
  private $iwp_mmb_pre_init_actions;
125
  'check_backup_compat' => 'iwp_mmb_check_backup_compat',
126
  'scheduled_backup' => 'iwp_mmb_scheduled_backup',
127
  'run_task' => 'iwp_mmb_run_task_now',
128
+ 'delete_schedule_task' => 'iwp_mmb_delete_task_now',
129
  'execute_php_code' => 'iwp_mmb_execute_php_code',
130
  'delete_backup' => 'mmm_delete_backup',
131
  'remote_backup_now' => 'iwp_mmb_remote_backup_now',
137
  'edit_plugins_themes' => 'iwp_mmb_edit_plugins_themes',
138
  'client_brand' => 'iwp_mmb_client_brand',
139
  'set_alerts' => 'iwp_mmb_set_alerts',
140
+ 'maintenance' => 'iwp_mmb_maintenance_mode',
141
+
142
+ 'backup_repository' => 'iwp_mmb_backup_repository'
143
  );
144
 
145
  add_action('rightnow_end', array( &$this, 'add_right_now_info' ));
385
  return $this->backup_instance;
386
  }
387
 
388
+ function get_backup_repository_instance()
389
+ {
390
+ if (!isset($this->backup_repository_instance)) {
391
+ $this->backup_repository_instance = new IWP_MMB_Backup_Repository();
392
+ }
393
+
394
+ return $this->backup_repository_instance;
395
+ }
396
+
397
  /**
398
  * Gets an instance of links class
399
  *
helper.class.php CHANGED
@@ -16,6 +16,9 @@
16
  * www.prelovac.com
17
  **************************************************************/
18
 
 
 
 
19
  class IWP_MMB_Helper
20
  {
21
  /**
@@ -357,7 +360,7 @@ class IWP_MMB_Helper
357
  );
358
  }
359
 
360
- if (function_exists('openssl_verify') && !$this->get_random_signature()) {
361
  $verify = openssl_verify($data, $signature, $pl_key);
362
  if ($verify == 1) {
363
  $message_id = $this->set_client_message_id($message_id);
@@ -497,10 +500,5 @@ class IWP_MMB_Helper
497
  die('Error downloading file ' . $url);
498
  return $file_name;
499
  }
500
-
501
-
502
-
503
-
504
-
505
  }
506
  ?>
16
  * www.prelovac.com
17
  **************************************************************/
18
 
19
+ if(!defined('MMB_WORKER_VERSION'))
20
+ define('MMB_WORKER_VERSION', '0');
21
+
22
  class IWP_MMB_Helper
23
  {
24
  /**
360
  );
361
  }
362
 
363
+ if (checkOpenSSL() && !$this->get_random_signature()) {
364
  $verify = openssl_verify($data, $signature, $pl_key);
365
  if ($verify == 1) {
366
  $message_id = $this->set_client_message_id($message_id);
500
  die('Error downloading file ' . $url);
501
  return $file_name;
502
  }
 
 
 
 
 
503
  }
504
  ?>
init.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: InfiniteWP - Client
4
  Plugin URI: http://infinitewp.com/
5
  Description: This is the client plugin of InfiniteWP that communicates with the InfiniteWP Admin panel.
6
  Author: Revmakx
7
- Version: 1.0.3
8
  Author URI: http://www.revmakx.com
9
  */
10
  /************************************************************
@@ -26,7 +26,8 @@ Author URI: http://www.revmakx.com
26
  **************************************************************/
27
 
28
  if(!defined('IWP_MMB_CLIENT_VERSION'))
29
- define('IWP_MMB_CLIENT_VERSION', '1.0.3');
 
30
 
31
  if ( !defined('IWP_MMB_XFRAME_COOKIE')){
32
  $siteurl = function_exists('get_site_option') ? get_site_option( 'siteurl' ) : get_option('siteurl');
@@ -46,6 +47,7 @@ require_once("$iwp_mmb_plugin_dir/core.class.php");
46
  require_once("$iwp_mmb_plugin_dir/stats.class.php");
47
  require_once("$iwp_mmb_plugin_dir/backup.class.php");
48
  require_once("$iwp_mmb_plugin_dir/installer.class.php");
 
49
  require_once("$iwp_mmb_plugin_dir/api.php");
50
  require_once("$iwp_mmb_plugin_dir/plugins/search/search.php");
51
  require_once("$iwp_mmb_plugin_dir/plugins/cleanup/cleanup.php");
@@ -133,12 +135,15 @@ if( !function_exists ('iwp_mmb_parse_request')) {
133
  }
134
 
135
  if(isset($params['secure'])){
 
136
  if($decrypted = $iwp_mmb_core->_secure_data($params['secure'])){
137
  $decrypted = maybe_unserialize($decrypted);
138
  if(is_array($decrypted)){
 
139
  foreach($decrypted as $key => $val){
140
  if(!is_numeric($key))
141
  $params[$key] = $val;
 
142
  }
143
  unset($params['secure']);
144
  } else $params['secure'] = $decrypted;
@@ -199,7 +204,7 @@ if( !function_exists ( 'iwp_mmb_add_site' )) {
199
  return;
200
  }
201
 
202
- if (function_exists('openssl_verify') && !$user_random_key_signing) {
203
  $verify = openssl_verify($action . $id, base64_decode($signature), $public_key);
204
  if ($verify == 1) {
205
  $iwp_mmb_core->set_admin_panel_public_key($public_key);
@@ -341,6 +346,19 @@ if( !function_exists ( 'iwp_mmb_run_task_now' )) {
341
  }
342
  }
343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  if( !function_exists ( 'iwp_mmb_check_backup_compat' )) {
345
  function iwp_mmb_check_backup_compat($params)
346
  {
@@ -420,6 +438,18 @@ if( !function_exists ( 'iwp_mmb_restore_now' )) {
420
  }
421
 
422
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
 
425
  if( !function_exists ( 'iwp_mmb_clean_orphan_backups' )) {
@@ -679,6 +709,26 @@ if( !function_exists('iwp_mmb_plugin_actions') ){
679
  }
680
  }
681
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
  $iwp_mmb_core = new IWP_MMB_Core();
683
 
684
  if(isset($_GET['auto_login']))
4
  Plugin URI: http://infinitewp.com/
5
  Description: This is the client plugin of InfiniteWP that communicates with the InfiniteWP Admin panel.
6
  Author: Revmakx
7
+ Version: 1.0.4
8
  Author URI: http://www.revmakx.com
9
  */
10
  /************************************************************
26
  **************************************************************/
27
 
28
  if(!defined('IWP_MMB_CLIENT_VERSION'))
29
+ define('IWP_MMB_CLIENT_VERSION', '1.0.4');
30
+
31
 
32
  if ( !defined('IWP_MMB_XFRAME_COOKIE')){
33
  $siteurl = function_exists('get_site_option') ? get_site_option( 'siteurl' ) : get_option('siteurl');
47
  require_once("$iwp_mmb_plugin_dir/stats.class.php");
48
  require_once("$iwp_mmb_plugin_dir/backup.class.php");
49
  require_once("$iwp_mmb_plugin_dir/installer.class.php");
50
+ require_once("$iwp_mmb_plugin_dir/addons/backup_repository/backup_repository.class.php");
51
  require_once("$iwp_mmb_plugin_dir/api.php");
52
  require_once("$iwp_mmb_plugin_dir/plugins/search/search.php");
53
  require_once("$iwp_mmb_plugin_dir/plugins/cleanup/cleanup.php");
135
  }
136
 
137
  if(isset($params['secure'])){
138
+
139
  if($decrypted = $iwp_mmb_core->_secure_data($params['secure'])){
140
  $decrypted = maybe_unserialize($decrypted);
141
  if(is_array($decrypted)){
142
+
143
  foreach($decrypted as $key => $val){
144
  if(!is_numeric($key))
145
  $params[$key] = $val;
146
+
147
  }
148
  unset($params['secure']);
149
  } else $params['secure'] = $decrypted;
204
  return;
205
  }
206
 
207
+ if (checkOpenSSL() && !$user_random_key_signing) {
208
  $verify = openssl_verify($action . $id, base64_decode($signature), $public_key);
209
  if ($verify == 1) {
210
  $iwp_mmb_core->set_admin_panel_public_key($public_key);
346
  }
347
  }
348
 
349
+ if( !function_exists ( 'iwp_mmb_delete_task_now' )) {
350
+ function iwp_mmb_delete_task_now($params)
351
+ {
352
+ global $iwp_mmb_core;
353
+ $iwp_mmb_core->get_backup_instance();
354
+ $return = $iwp_mmb_core->backup_instance->delete_task_now($params['task_name']);
355
+ if (is_array($return) && array_key_exists('error', $return))
356
+ iwp_mmb_response($return['error'], false);
357
+ else {
358
+ iwp_mmb_response($return, true);
359
+ }
360
+ }
361
+ }
362
  if( !function_exists ( 'iwp_mmb_check_backup_compat' )) {
363
  function iwp_mmb_check_backup_compat($params)
364
  {
438
  }
439
 
440
 
441
+ if( !function_exists ( 'iwp_mmb_backup_repository' )) {
442
+ function iwp_mmb_backup_repository($params)
443
+ {
444
+ global $iwp_mmb_core;
445
+ $iwp_mmb_core->get_backup_repository_instance();
446
+ $return = $iwp_mmb_core->backup_repository_instance->backup_repository($params);
447
+ if (is_array($return) && array_key_exists('error', $return))
448
+ iwp_mmb_response($return['error'], false);
449
+ else
450
+ iwp_mmb_response($return, true);
451
+ }
452
+ }
453
 
454
 
455
  if( !function_exists ( 'iwp_mmb_clean_orphan_backups' )) {
709
  }
710
  }
711
 
712
+ if(!function_exists('checkOpenSSL')){
713
+ function checkOpenSSL(){
714
+ if(!function_exists('openssl_verify')){
715
+ return false;
716
+ }
717
+ else{
718
+ $key = @openssl_pkey_new();
719
+ @openssl_pkey_export($key, $privateKey);
720
+ $privateKey = base64_encode($privateKey);
721
+ $publicKey = @openssl_pkey_get_details($key);
722
+ $publicKey = $publicKey["key"];
723
+
724
+ if(empty($publicKey) || empty($privateKey)){
725
+ return false;
726
+ }
727
+ }
728
+ return true;
729
+ }
730
+ }
731
+
732
  $iwp_mmb_core = new IWP_MMB_Core();
733
 
734
  if(isset($_GET['auto_login']))
installer.class.php CHANGED
@@ -489,43 +489,96 @@ class IWP_MMB_Installer extends IWP_MMB_Core
489
 
490
  $upgrader = false;
491
  $pr_update = array();
 
 
492
  $result = array();
493
  $premium_update = array();
494
- $premium_update = apply_filters('iwp_premium_perform_update', $premium_update);
495
-
496
  if (!empty($premium_update)) {
 
497
  foreach ($premium as $pr) {
498
- foreach ($premium_update as $update) {
499
  $update = array_change_key_case($update, CASE_LOWER);
500
-
501
  if ($update['name'] == $pr['name']) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  $update_result = false;
503
  if (isset($update['url'])) {
504
  if (defined('WP_INSTALLING') && file_exists(ABSPATH . '.maintenance'))
505
  $pr_update[$update['type'] . 's']['upgraded'][md5($update['name'])] = 'Site under maintanace.';
506
 
507
- if ($upgrader == false) {
508
  $upgrader_skin = new WP_Upgrader_Skin();
509
  $upgrader_skin->done_header = true;
510
-
511
  $upgrader = new WP_Upgrader();
512
- }
513
-
514
  @$update_result = $upgrader->run(array(
515
  'package' => $update['url'],
516
  'destination' => isset($update['type']) && $update['type'] == 'theme' ? WP_CONTENT_DIR . '/themes' : WP_PLUGIN_DIR,
517
  'clear_destination' => true,
518
  'clear_working' => true,
 
519
  'hook_extra' => array()
520
  ));
521
  $update_result = !$update_result || is_wp_error($update_result) ? $this->iwp_mmb_get_error($update_result) : 1;
522
 
523
  } else if (isset($update['callback'])) {
524
  if (is_array($update['callback'])) {
525
- $update_result = call_user_func(array(
526
- $update['callback'][0],
527
- $update['callback'][1]
528
- ));
529
  } else if (is_string($update['callback'])) {
530
  $update_result = call_user_func($update['callback']);
531
  } else {
@@ -539,7 +592,6 @@ class IWP_MMB_Installer extends IWP_MMB_Core
539
  $pr_update[$update['type'] . 's']['upgraded'][md5($update['name'])] = $update_result;
540
  }
541
  }
542
- }
543
  return $pr_update;
544
  } else {
545
  foreach ($premium as $pr) {
@@ -653,12 +705,14 @@ class IWP_MMB_Installer extends IWP_MMB_Core
653
  if (in_array($path, $activated_plugins)) {
654
  $plugins['active'][$br_a]['path'] = $path;
655
  $plugins['active'][$br_a]['name'] = strip_tags($plugin['Name']);
 
656
  $br_a++;
657
  }
658
 
659
  if (!in_array($path, $activated_plugins)) {
660
  $plugins['inactive'][$br_i]['path'] = $path;
661
  $plugins['inactive'][$br_i]['name'] = strip_tags($plugin['Name']);
 
662
  $br_i++;
663
  }
664
 
@@ -708,6 +762,7 @@ class IWP_MMB_Installer extends IWP_MMB_Core
708
  if ($current_theme == $theme_name) {
709
  $themes['active'][$br_a]['path'] = $theme['Template'];
710
  $themes['active'][$br_a]['name'] = strip_tags($theme['Name']);
 
711
  $themes['active'][$br_a]['stylesheet'] = $theme['Stylesheet'];
712
  $br_a++;
713
  }
@@ -715,6 +770,7 @@ class IWP_MMB_Installer extends IWP_MMB_Core
715
  if ($current_theme != $theme_name) {
716
  $themes['inactive'][$br_i]['path'] = $theme['Template'];
717
  $themes['inactive'][$br_i]['name'] = strip_tags($theme['Name']);
 
718
  $themes['inactive'][$br_i]['stylesheet'] = $theme['Stylesheet'];
719
  $br_i++;
720
  }
489
 
490
  $upgrader = false;
491
  $pr_update = array();
492
+ $themes = array();
493
+ $plugins = array();
494
  $result = array();
495
  $premium_update = array();
496
+ $premium_update = apply_filters('mwp_premium_perform_update', $premium_update);
 
497
  if (!empty($premium_update)) {
498
+
499
  foreach ($premium as $pr) {
500
+ foreach ($premium_update as $key => $update) {
501
  $update = array_change_key_case($update, CASE_LOWER);
 
502
  if ($update['name'] == $pr['name']) {
503
+
504
+ // prepare bulk updates for premiums that use WordPress upgrader
505
+ if(isset($update['type'])){
506
+ if($update['type'] == 'plugin'){
507
+ if(isset($update['slug']) && !empty($update['slug']))
508
+ $plugins[$update['slug']] = $update;
509
+ }
510
+
511
+ if($update['type'] == 'theme'){
512
+ if(isset($update['template']) && !empty($update['template']))
513
+ $themes[$update['template']] = $update;
514
+ }
515
+ }
516
+ } else {
517
+ unset($premium_update[$key]);
518
+ }
519
+ }
520
+ }
521
+
522
+ // try default wordpress upgrader
523
+ if(!empty($plugins)){
524
+ $updateplugins = $this->upgrade_plugins(array_keys($plugins));
525
+ if(!empty($updateplugins) && isset($updateplugins['upgraded'])){
526
+ foreach ($premium_update as $key => $update) {
527
+ $update = array_change_key_case($update, CASE_LOWER);
528
+ foreach($updateplugins['upgraded'] as $slug => $upgrade){
529
+ if( isset($update['slug']) && $update['slug'] == $slug){
530
+ if( $upgrade == 1 )
531
+ unset($premium_update[$key]);
532
+
533
+ $pr_update['plugins']['upgraded'][md5($update['name'])] = $upgrade;
534
+ }
535
+ }
536
+ }
537
+ }
538
+ }
539
+
540
+ if(!empty($themes)){
541
+ $updatethemes = $this->upgrade_themes(array_keys($themes));
542
+ if(!empty($updatethemes) && isset($updatethemes['upgraded'])){
543
+ foreach ($premium_update as $key => $update) {
544
+ $update = array_change_key_case($update, CASE_LOWER);
545
+ foreach($updatethemes['upgraded'] as $template => $upgrade){
546
+ if( isset($update['template']) && $update['template'] == $template) {
547
+ if( $upgrade == 1 )
548
+ unset($premium_update[$key]);
549
+
550
+ $pr_update['themes']['upgraded'][md5($update['name'])] = $upgrade;
551
+ }
552
+ }
553
+ }
554
+ }
555
+ }
556
+
557
+ //try direct install with overwrite
558
+ if (!empty($premium_update)) {
559
+ foreach ($premium_update as $update) {
560
+ $update = array_change_key_case($update, CASE_LOWER);
561
  $update_result = false;
562
  if (isset($update['url'])) {
563
  if (defined('WP_INSTALLING') && file_exists(ABSPATH . '.maintenance'))
564
  $pr_update[$update['type'] . 's']['upgraded'][md5($update['name'])] = 'Site under maintanace.';
565
 
 
566
  $upgrader_skin = new WP_Upgrader_Skin();
567
  $upgrader_skin->done_header = true;
 
568
  $upgrader = new WP_Upgrader();
 
 
569
  @$update_result = $upgrader->run(array(
570
  'package' => $update['url'],
571
  'destination' => isset($update['type']) && $update['type'] == 'theme' ? WP_CONTENT_DIR . '/themes' : WP_PLUGIN_DIR,
572
  'clear_destination' => true,
573
  'clear_working' => true,
574
+ 'is_multi' => true,
575
  'hook_extra' => array()
576
  ));
577
  $update_result = !$update_result || is_wp_error($update_result) ? $this->iwp_mmb_get_error($update_result) : 1;
578
 
579
  } else if (isset($update['callback'])) {
580
  if (is_array($update['callback'])) {
581
+ $update_result = call_user_func(array( $update['callback'][0], $update['callback'][1] ));
 
 
 
582
  } else if (is_string($update['callback'])) {
583
  $update_result = call_user_func($update['callback']);
584
  } else {
592
  $pr_update[$update['type'] . 's']['upgraded'][md5($update['name'])] = $update_result;
593
  }
594
  }
 
595
  return $pr_update;
596
  } else {
597
  foreach ($premium as $pr) {
705
  if (in_array($path, $activated_plugins)) {
706
  $plugins['active'][$br_a]['path'] = $path;
707
  $plugins['active'][$br_a]['name'] = strip_tags($plugin['Name']);
708
+ $plugins['active'][$br_a]['version'] = $plugin['Version'];
709
  $br_a++;
710
  }
711
 
712
  if (!in_array($path, $activated_plugins)) {
713
  $plugins['inactive'][$br_i]['path'] = $path;
714
  $plugins['inactive'][$br_i]['name'] = strip_tags($plugin['Name']);
715
+ $plugins['inactive'][$br_i]['version'] = $plugin['Version'];
716
  $br_i++;
717
  }
718
 
762
  if ($current_theme == $theme_name) {
763
  $themes['active'][$br_a]['path'] = $theme['Template'];
764
  $themes['active'][$br_a]['name'] = strip_tags($theme['Name']);
765
+ $themes['active'][$br_a]['version'] = $theme['Version'];
766
  $themes['active'][$br_a]['stylesheet'] = $theme['Stylesheet'];
767
  $br_a++;
768
  }
770
  if ($current_theme != $theme_name) {
771
  $themes['inactive'][$br_i]['path'] = $theme['Template'];
772
  $themes['inactive'][$br_i]['name'] = strip_tags($theme['Name']);
773
+ $themes['inactive'][$br_i]['version'] = $theme['Version'];
774
  $themes['inactive'][$br_i]['stylesheet'] = $theme['Stylesheet'];
775
  $br_i++;
776
  }
lib/dropbox.oauth.php ADDED
@@ -0,0 +1,1133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Dropbox class
5
+ *
6
+ * This source file can be used to communicate with Dropbox (http://dropbox.com)
7
+ *
8
+ * The class is documented in the file itself. If you find any bugs help me out and report them. Reporting can be done by sending an email to php-dropbox-bugs[at]verkoyen[dot]eu.
9
+ * If you report a bug, make sure you give me enough information (include your code).
10
+ *
11
+ * Changelog since 1.0.4
12
+ * - Fixed filesPost so it returns a boolean.
13
+ * - Some code styling
14
+ *
15
+ * Changelog since 1.0.3
16
+ * - Corrected the authorize-URL (thx to Jacob Budin).
17
+ *
18
+ * Changelog since 1.0.2
19
+ * - Added methods to enable oauth-usage.
20
+ *
21
+ * Changelog since 1.0.1
22
+ * - Bugfix: when doing multiple calles where GET and POST is mixed, the postfields should be reset (thx to Daniel Hトてスsken)
23
+ *
24
+ * Changelog since 1.0.0
25
+ * - fixed some issues with generation off the basestring
26
+ *
27
+ * License
28
+ * Copyright (c), Tijs Verkoyen. All rights reserved.
29
+ *
30
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
31
+ *
32
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
33
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
34
+ * 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
35
+ *
36
+ * This software is provided by the author "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
37
+ *
38
+ * @author Tijs Verkoyen <php-dropbox@verkoyen.eu>
39
+ * @version 1.0.5
40
+ *
41
+ * @copyright Copyright (c), Tijs Verkoyen. All rights reserved.
42
+ * @license BSD License
43
+ */
44
+ class Dropbox
45
+ {
46
+ // internal constant to enable/disable debugging
47
+ const DEBUG = false;
48
+
49
+ // url for the dropbox-api
50
+ const API_URL = 'https://api.dropbox.com';
51
+ const API_AUTH_URL = 'https://www.dropbox.com';
52
+ const API_CONTENT_URL = 'https://api-content.dropbox.com';
53
+
54
+ // port for the dropbox-api
55
+ const API_PORT = 443;
56
+
57
+ // current version
58
+ const VERSION = '1.0.5';
59
+
60
+
61
+ /**
62
+ * A cURL instance
63
+ *
64
+ * @var resource
65
+ */
66
+ private $curl;
67
+
68
+
69
+ /**
70
+ * The application key
71
+ *
72
+ * @var string
73
+ */
74
+ private $applicationKey;
75
+
76
+
77
+ /**
78
+ * The application secret
79
+ *
80
+ * @var string
81
+ */
82
+ private $applicationSecret;
83
+
84
+
85
+ /**
86
+ * The oAuth-token
87
+ *
88
+ * @var string
89
+ */
90
+ private $oAuthToken = '';
91
+
92
+
93
+ /**
94
+ * The oAuth-token-secret
95
+ *
96
+ * @var string
97
+ */
98
+ private $oAuthTokenSecret = '';
99
+
100
+
101
+ /**
102
+ * The timeout
103
+ *
104
+ * @var int
105
+ */
106
+ private $timeOut = 1200;
107
+
108
+
109
+ /**
110
+ * The user agent
111
+ *
112
+ * @var string
113
+ */
114
+ private $userAgent;
115
+
116
+
117
+ // class methods
118
+ /**
119
+ * Default constructor
120
+ *
121
+ * @return void
122
+ * @param string $applicationKey The application key to use.
123
+ * @param string $applicationSecret The application secret to use.
124
+ */
125
+ public function __construct($applicationKey, $applicationSecret)
126
+ {
127
+ $this->setApplicationKey($applicationKey);
128
+ $this->setApplicationSecret($applicationSecret);
129
+ }
130
+
131
+
132
+ /**
133
+ * Default destructor
134
+ *
135
+ * @return void
136
+ */
137
+ public function __destruct()
138
+ {
139
+ if($this->curl != null) curl_close($this->curl);
140
+ }
141
+
142
+
143
+ /**
144
+ * Format the parameters as a querystring
145
+ *
146
+ * @return string
147
+ * @param array $parameters The parameters to pass.
148
+ */
149
+ private function buildQuery(array $parameters)
150
+ {
151
+ // no parameters?
152
+ if(empty($parameters)) return '';
153
+
154
+ // encode the keys
155
+ $keys = self::urlencode_rfc3986(array_keys($parameters));
156
+
157
+ // encode the values
158
+ $values = self::urlencode_rfc3986(array_values($parameters));
159
+
160
+ // reset the parameters
161
+ $parameters = array_combine($keys, $values);
162
+
163
+ // sort parameters by key
164
+ uksort($parameters, 'strcmp');
165
+
166
+ // loop parameters
167
+ foreach($parameters as $key => $value)
168
+ {
169
+ // sort by value
170
+ if(is_array($value)) $parameters[$key] = natsort($value);
171
+ }
172
+
173
+ // process parameters
174
+ foreach($parameters as $key => $value) $chunks[] = $key . '=' . str_replace('%25', '%', $value);
175
+
176
+ // return
177
+ return implode('&', $chunks);
178
+ }
179
+
180
+
181
+ /**
182
+ * All OAuth 1.0 requests use the same basic algorithm for creating a signature base string and a signature.
183
+ * The signature base string is composed of the HTTP method being used, followed by an ampersand ("&") and then the URL-encoded base URL being accessed,
184
+ * complete with path (but not query parameters), followed by an ampersand ("&").
185
+ * Then, you take all query parameters and POST body parameters (when the POST body is of the URL-encoded type, otherwise the POST body is ignored),
186
+ * including the OAuth parameters necessary for negotiation with the request at hand, and sort them in lexicographical order by first parameter name and
187
+ * then parameter value (for duplicate parameters), all the while ensuring that both the key and the value for each parameter are URL encoded in isolation.
188
+ * Instead of using the equals ("=") sign to mark the key/value relationship, you use the URL-encoded form of "%3D". Each parameter is then joined by the
189
+ * URL-escaped ampersand sign, "%26".
190
+ *
191
+ * @return string
192
+ * @param string $url The url to use.
193
+ * @param string $method The method that will be called.
194
+ * @param array $parameters The parameters to pass.
195
+ */
196
+ private function calculateBaseString($url, $method, array $parameters)
197
+ {
198
+ // redefine
199
+ $url = (string) $url;
200
+ $parameters = (array) $parameters;
201
+
202
+ // init var
203
+ $pairs = array();
204
+ $chunks = array();
205
+
206
+ // sort parameters by key
207
+ uksort($parameters, 'strcmp');
208
+
209
+ // loop parameters
210
+ foreach($parameters as $key => $value)
211
+ {
212
+ // sort by value
213
+ if(is_array($value)) $parameters[$key] = natsort($value);
214
+ }
215
+
216
+ // process queries
217
+ foreach($parameters as $key => $value)
218
+ {
219
+ // only add if not already in the url
220
+ if(substr_count($url, $key . '=' . $value) == 0) $chunks[] = self::urlencode_rfc3986($key) . '%3D' . self::urlencode_rfc3986($value);
221
+ }
222
+
223
+ $urlChunks = explode('/', $url);
224
+ $i = 0;
225
+
226
+ foreach($urlChunks as &$chunk)
227
+ {
228
+ if($i > 4) $chunk = self::urlencode_rfc3986($chunk);
229
+ else $chunk = urlencode($chunk);
230
+
231
+ $i++;
232
+
233
+ }
234
+
235
+ // build base
236
+ $base = $method . '&';
237
+ $base .= implode('%2F', $urlChunks);
238
+ $base .= (substr_count($url, '?')) ? '%26' : '&';
239
+ $base .= implode('%26', $chunks);
240
+ $base = str_replace(array('%3F', '%20'), array('&', '%2520'), $base);
241
+
242
+ // return
243
+ return $base;
244
+ }
245
+
246
+
247
+ /**
248
+ * Build the Authorization header
249
+ * @later: fix me
250
+ *
251
+ * @return string
252
+ * @param array $parameters The parameters to pass.
253
+ * @param string $url The url to use.
254
+ */
255
+ private function calculateHeader(array $parameters, $url)
256
+ {
257
+ // redefine
258
+ $url = (string) $url;
259
+
260
+ // divide into parts
261
+ $parts = parse_url($url);
262
+
263
+ // init var
264
+ $chunks = array();
265
+
266
+ // process queries
267
+ foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', self::urlencode_rfc3986($key) . '="' . self::urlencode_rfc3986($value) . '"');
268
+ $parts['path']=str_replace("%2F", "/", rawurlencode($parts['path']));
269
+ // build return
270
+ $return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
271
+ $return .= implode(',', $chunks);
272
+ // prepend name and OAuth part
273
+ return $return;
274
+ }
275
+
276
+
277
+ /**
278
+ * Make an call to the oAuth
279
+ * @todo refactor me
280
+ *
281
+ * @return array
282
+ * @param string $url The url that has to be called.
283
+ * @param array[optional] $parameters The parameters to pass.
284
+ * @param string[optional] $method Which HTTP-method should we use? Possible values are POST, GET.
285
+ * @param bool[optional] $expectJSON Do we expect JSON?
286
+ */
287
+ private function doOAuthCall($url, array $parameters = null, $method = 'POST', $expectJSON = true)
288
+ {
289
+ // redefine
290
+ $url = (string) $url;
291
+
292
+ // append default parameters
293
+ $parameters['oauth_consumer_key'] = $this->getApplicationKey();
294
+ $parameters['oauth_nonce'] = md5(microtime() . rand());
295
+ $parameters['oauth_timestamp'] = time();
296
+ $parameters['oauth_signature_method'] = 'HMAC-SHA1';
297
+ $parameters['oauth_version'] = '1.0';
298
+
299
+ // calculate the base string
300
+ $base = $this->calculateBaseString(self::API_URL . '/' . $url, 'POST', $parameters);
301
+
302
+ // add sign into the parameters
303
+ $parameters['oauth_signature'] = $this->hmacsha1($this->getApplicationSecret() . '&' . $this->getOAuthTokenSecret(), $base);
304
+
305
+ // calculate header
306
+ $header = $this->calculateHeader($parameters, self::API_URL . '/' . $url);
307
+
308
+ if($method == 'POST')
309
+ {
310
+ $options[CURLOPT_POST] = true;
311
+ $options[CURLOPT_POSTFIELDS] = $this->buildQuery($parameters);
312
+ }
313
+
314
+ else
315
+ {
316
+ // reset post
317
+ $options[CURLOPT_POST] = 0;
318
+ unset($options[CURLOPT_POSTFIELDS]);
319
+
320
+ // add the parameters into the querystring
321
+ if(!empty($parameters)) $url .= '?' . $this->buildQuery($parameters);
322
+ }
323
+
324
+ // set options
325
+ $options[CURLOPT_URL] = self::API_URL . '/' . $url;
326
+ $options[CURLOPT_PORT] = self::API_PORT;
327
+ $options[CURLOPT_USERAGENT] = $this->getUserAgent();
328
+ if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
329
+ $options[CURLOPT_RETURNTRANSFER] = true;
330
+ $options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
331
+ $options[CURLOPT_SSL_VERIFYPEER] = false;
332
+ $options[CURLOPT_SSL_VERIFYHOST] = false;
333
+ $options[CURLOPT_HTTPHEADER] = array('Expect:');
334
+
335
+ // init
336
+ $this->curl = curl_init();
337
+
338
+ // set options
339
+ curl_setopt_array($this->curl, $options);
340
+
341
+ // execute
342
+ $response = curl_exec($this->curl);
343
+ $headers = curl_getinfo($this->curl);
344
+
345
+ // fetch errors
346
+ $errorNumber = curl_errno($this->curl);
347
+ $errorMessage = curl_error($this->curl);
348
+
349
+ // error?
350
+ if($errorNumber != '') throw new DropboxException($errorMessage, $errorNumber);
351
+
352
+ // return
353
+ if($expectJSON) return json_decode($response, true);
354
+
355
+ // fallback
356
+ return $response;
357
+ }
358
+
359
+
360
+ /**
361
+ * Make the call
362
+ *
363
+ * @return string
364
+ * @param string $url The url to call.
365
+ * @param array[optional] $parameters Optional parameters.
366
+ * @param bool[optional] $method The method to use. Possible values are GET, POST.
367
+ * @param string[optional] $filePath The path to the file to upload.
368
+ * @param bool[optional] $expectJSON Do we expect JSON?
369
+ * @param bool[optional] $isContent Is this content?
370
+ */
371
+ private function doCall($url, array $parameters = null, $method = 'GET', $filePath = null, $expectJSON = true, $isContent = false)
372
+ {
373
+ // allowed methods
374
+ $allowedMethods = array('GET', 'POST');
375
+
376
+ // redefine
377
+ $url = (string) $url;
378
+ $parameters = (array) $parameters;
379
+ $method = (string) $method;
380
+ $expectJSON = (bool) $expectJSON;
381
+
382
+ // validate method
383
+ if(!in_array($method, $allowedMethods)) throw new DropboxException('Unknown method (' . $method . '). Allowed methods are: ' . implode(', ', $allowedMethods));
384
+
385
+ // append default parameters
386
+ $oauth['oauth_consumer_key'] = $this->getApplicationKey();
387
+ $oauth['oauth_nonce'] = md5(microtime() . rand());
388
+ $oauth['oauth_timestamp'] = time();
389
+ $oauth['oauth_token'] = $this->getOAuthToken();
390
+ $oauth['oauth_signature_method'] = 'HMAC-SHA1';
391
+ $oauth['oauth_version'] = '1.0';
392
+
393
+ // set data
394
+ $data = $oauth;
395
+ if(!empty($parameters))
396
+ {
397
+ // convert to UTF-8
398
+ foreach($parameters as &$value) $value = utf8_encode($value);
399
+
400
+ // merge
401
+ $data = array_merge($data, $parameters);
402
+ }
403
+
404
+ if($filePath != null)
405
+ {
406
+ // process file
407
+ $fileInfo = pathinfo($filePath);
408
+
409
+ // add to the data
410
+ $data['file'] = $fileInfo['basename'];
411
+
412
+ }
413
+
414
+ // calculate the base string
415
+ if($isContent) $base = $this->calculateBaseString(self::API_CONTENT_URL . '/' . $url, $method, $data);
416
+ else $base = $this->calculateBaseString(self::API_URL . '/' . $url, $method, $data);
417
+
418
+ // based on the method, we should handle the parameters in a different way
419
+ if($method == 'POST')
420
+ {
421
+ // file provided?
422
+ if($filePath != null)
423
+ {
424
+ // build a boundary
425
+ $boundary = md5(time());
426
+
427
+ // init var
428
+ $content = '--' . $boundary . "\r\n";
429
+
430
+ // set file
431
+ $content .= 'Content-Disposition: form-data; name=file; filename="' . $fileInfo['basename'] . '"' . "\r\n";
432
+ $content .= 'Content-Type: application/octet-stream' . "\r\n";
433
+ $content .= "\r\n";
434
+ $content .= file_get_contents($filePath);
435
+ $content .= "\r\n";
436
+ $content .= "--" . $boundary . '--';
437
+
438
+ // build headers
439
+ $headers[] = 'Content-Type: multipart/form-data; boundary=' . $boundary;
440
+ $headers[] = 'Content-Length: ' . strlen($content);
441
+
442
+ // set content
443
+ $options[CURLOPT_POSTFIELDS] = $content;
444
+ }
445
+
446
+ // no file
447
+ else $options[CURLOPT_POSTFIELDS] = $this->buildQuery($parameters);
448
+
449
+ // enable post
450
+ $options[CURLOPT_POST] = 1;
451
+ }
452
+
453
+ else
454
+ {
455
+ // reset post
456
+ $options[CURLOPT_POST] = 0;
457
+ unset($options[CURLOPT_POSTFIELDS]);
458
+ $url=str_replace("%2F", "/", rawurlencode($url));
459
+
460
+ // add the parameters into the querystring
461
+ if(!empty($parameters)) $url .= '?' . $this->buildQuery($parameters);
462
+ }
463
+
464
+ // add sign into the parameters
465
+ $oauth['oauth_signature'] = $this->hmacsha1($this->getApplicationSecret() . '&' . $this->getOAuthTokenSecret(), $base);
466
+
467
+ if($isContent) $headers[] = $this->calculateHeader($oauth, self::API_CONTENT_URL . '/' . $url);
468
+ else $headers[] = $this->calculateHeader($oauth, self::API_URL . '/' . $url);
469
+ $headers[] = 'Expect:';
470
+
471
+ // set options
472
+ if($isContent) $options[CURLOPT_URL] = self::API_CONTENT_URL . '/' . $url;
473
+ else $options[CURLOPT_URL] = self::API_URL . '/' . $url;
474
+ $options[CURLOPT_PORT] = self::API_PORT;
475
+ $options[CURLOPT_USERAGENT] = $this->getUserAgent();
476
+ if(ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) $options[CURLOPT_FOLLOWLOCATION] = true;
477
+ $options[CURLOPT_RETURNTRANSFER] = true;
478
+ $options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
479
+ $options[CURLOPT_SSL_VERIFYPEER] = false;
480
+ $options[CURLOPT_SSL_VERIFYHOST] = false;
481
+ $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
482
+ $options[CURLOPT_HTTPHEADER] = $headers;
483
+ // init
484
+ if($this->curl == null) $this->curl = curl_init();
485
+
486
+ // set options
487
+ curl_setopt_array($this->curl, $options);
488
+
489
+ // execute
490
+ $response = curl_exec($this->curl);
491
+ $headers = curl_getinfo($this->curl);
492
+
493
+ // fetch errors
494
+ $errorNumber = curl_errno($this->curl);
495
+ $errorMessage = curl_error($this->curl);
496
+
497
+ if(!$expectJSON && $isContent)
498
+ {
499
+ // is it JSON?
500
+ $json = @json_decode($response, true);
501
+ if($json !== false && isset($json['error'])) throw new DropboxException($json['error']);
502
+
503
+ // set return
504
+ $return['content_type'] = $headers['content_type'];
505
+ $return['data'] = base64_encode($response);
506
+
507
+ // return
508
+ return $return;
509
+ }
510
+
511
+ // we don't expect JSON, return the response
512
+ if(!$expectJSON) return $response;
513
+
514
+ // replace ids with their string values, added because of some PHP-version can't handle these large values
515
+ $response = preg_replace('/id":(\d+)/', 'id":"\1"', $response);
516
+
517
+ // we expect JSON, so decode it
518
+ $json = @json_decode($response, true);
519
+
520
+ // validate JSON
521
+ if($json === null)
522
+ {
523
+ // should we provide debug information
524
+ if(self::DEBUG)
525
+ {
526
+ // make it output proper
527
+ echo '<pre>';
528
+
529
+ // dump the header-information
530
+ var_dump($headers);
531
+
532
+ // dump the error
533
+ var_dump($errorMessage);
534
+
535
+ // dump the raw response
536
+ var_dump($response);
537
+
538
+ // end proper format
539
+ echo '</pre>';
540
+ }
541
+
542
+ // throw exception
543
+ throw new DropboxException('Invalid response.');
544
+ }
545
+
546
+ // any error
547
+ if(isset($json['error']))
548
+ {
549
+ // should we provide debug information
550
+ if(self::DEBUG)
551
+ {
552
+ // make it output proper
553
+ echo '<pre>';
554
+
555
+ // dump the header-information
556
+ var_dump($headers);
557
+
558
+ // dump the raw response
559
+ var_dump($response);
560
+
561
+ // end proper format
562
+ echo '</pre>';
563
+ }
564
+
565
+ if(isset($json['error']) && is_string($json['error'])) $message = $json['error'];
566
+ elseif(isset($json['error']['hash']) && $json['error']['hash'] != '') $message = (string) $json['error']['hash'];
567
+ else $message = 'Invalid response.';
568
+
569
+ // throw exception
570
+ throw new DropboxException($message);
571
+ }
572
+
573
+ // return
574
+ return $json;
575
+ }
576
+
577
+
578
+ /**
579
+ * Get the application key
580
+ *
581
+ * @return string
582
+ */
583
+ private function getApplicationKey()
584
+ {
585
+ return $this->applicationKey;
586
+ }
587
+
588
+
589
+ /**
590
+ * Get the application secret
591
+ *
592
+ * @return string
593
+ */
594
+ private function getApplicationSecret()
595
+ {
596
+ return $this->applicationSecret;
597
+ }
598
+
599
+
600
+ /**
601
+ * Get the oAuth-token
602
+ *
603
+ * @return string
604
+ */
605
+ private function getOAuthToken()
606
+ {
607
+ return $this->oAuthToken;
608
+ }
609
+
610
+
611
+ /**
612
+ * Get the oAuth-token-secret
613
+ *
614
+ * @return string
615
+ */
616
+ private function getOAuthTokenSecret()
617
+ {
618
+ return $this->oAuthTokenSecret;
619
+ }
620
+
621
+
622
+ /**
623
+ * Get the timeout
624
+ *
625
+ * @return int
626
+ */
627
+ public function getTimeOut()
628
+ {
629
+ return (int) $this->timeOut;
630
+ }
631
+
632
+
633
+ /**
634
+ * Get the useragent that will be used. Our version will be prepended to yours.
635
+ * It will look like: "PHP Dropbox/<version> <your-user-agent>"
636
+ *
637
+ * @return string
638
+ */
639
+ public function getUserAgent()
640
+ {
641
+ return (string) 'PHP Dropbox/' . self::VERSION . ' ' . $this->userAgent;
642
+ }
643
+
644
+
645
+ /**
646
+ * Set the application key
647
+ *
648
+ * @return void
649
+ * @param string $key The application key to use.
650
+ */
651
+ private function setApplicationKey($key)
652
+ {
653
+ $this->applicationKey = (string) $key;
654
+ }
655
+
656
+
657
+ /**
658
+ * Set the application secret
659
+ *
660
+ * @return void
661
+ * @param string $secret The application secret to use.
662
+ */
663
+ private function setApplicationSecret($secret)
664
+ {
665
+ $this->applicationSecret = (string) $secret;
666
+ }
667
+
668
+
669
+ /**
670
+ * Set the oAuth-token
671
+ *
672
+ * @return void
673
+ * @param string $token The token to use.
674
+ */
675
+ public function setOAuthToken($token)
676
+ {
677
+ $this->oAuthToken = (string) $token;
678
+ }
679
+
680
+
681
+ /**
682
+ * Set the oAuth-secret
683
+ *
684
+ * @return void
685
+ * @param string $secret The secret to use.
686
+ */
687
+ public function setOAuthTokenSecret($secret)
688
+ {
689
+ $this->oAuthTokenSecret = (string) $secret;
690
+ }
691
+
692
+
693
+ /**
694
+ * Set the timeout
695
+ *
696
+ * @return void
697
+ * @param int $seconds The timeout in seconds.
698
+ */
699
+ public function setTimeOut($seconds)
700
+ {
701
+ $this->timeOut = (int) $seconds;
702
+ }
703
+
704
+
705
+ /**
706
+ * Get the useragent that will be used. Our version will be prepended to yours.
707
+ * It will look like: "PHP Dropbox/<version> <your-user-agent>"
708
+ *
709
+ * @return void
710
+ * @param string $userAgent Your user-agent, it should look like <app-name>/<app-version>.
711
+ */
712
+ public function setUserAgent($userAgent)
713
+ {
714
+ $this->userAgent = (string) $userAgent;
715
+ }
716
+
717
+
718
+ /**
719
+ * Build the signature for the data
720
+ *
721
+ * @return string
722
+ * @param string $key The key to use for signing.
723
+ * @param string $data The data that has to be signed.
724
+ */
725
+ private function hmacsha1($key, $data)
726
+ {
727
+ return base64_encode(hash_hmac('SHA1', $data, $key, true));
728
+ }
729
+
730
+
731
+ /**
732
+ * URL-encode method for internatl use
733
+ *
734
+ * @return string
735
+ * @param mixed $value The value to encode.
736
+ */
737
+ private static function urlencode_rfc3986($value)
738
+ {
739
+ if(is_array($value)) return array_map(array('Dropbox', 'urlencode_rfc3986'), $value);
740
+ else
741
+ {
742
+ $search = array('+', ' ', '%7E', '%');
743
+ $replace = array('%20', '%20', '~', '%25');
744
+
745
+ return str_replace($search, $replace, rawurlencode($value));
746
+ }
747
+ }
748
+
749
+
750
+ // oauth resources
751
+ /**
752
+ * Call for obtaining an OAuth request token.
753
+ * Returns a request token and the corresponding request token secret. This token and secret cannot be used to sign requests for the /metadata and /file content API calls.
754
+ * Their only purpose is for signing a request to oauth/access_token once the user has gone through the application authorization steps provided by oauth/authorize.
755
+ *
756
+ * @return array
757
+ */
758
+ public function oAuthRequestToken()
759
+ {
760
+ // make the call
761
+ $response = $this->doOAuthCall('1/oauth/request_token', null, 'POST', false);
762
+
763
+ // process response
764
+ $response = (array) explode('&', $response);
765
+ $return = array();
766
+
767
+ // loop chunks
768
+ foreach($response as $chunk)
769
+ {
770
+ // split again
771
+ $chunks = explode('=', $chunk, 2);
772
+
773
+ // store return
774
+ if(count($chunks) == 2) $return[$chunks[0]] = $chunks[1];
775
+ }
776
+
777
+ // return
778
+ return $return;
779
+ }
780
+
781
+
782
+ /**
783
+ * Redirect the user to the oauth/authorize location so that Dropbox can authenticate the user and ask whether or not the user wants to authorize the application to access
784
+ * file metadata and content on its behalf. oauth/authorize is not an API call per se, because it does not have a return value, but rather directs the user to a page on
785
+ * api.dropbox.com where they are provided means to log in to Dropbox and grant authority to the application requesting it.
786
+ * The page served by oauth/authorize should be presented to the user through their web browser.
787
+ * Please note, without directing the user to a Dropbox-provided page via oauth/authorize, it is impossible for your application to use the request token it received
788
+ * via oauth/request_token to obtain an access token from oauth/access_token.
789
+ *
790
+ * @return void
791
+ * @param string $oauthToken The request token of the application requesting authority from a user.
792
+ * @param string[optional] $oauthCallback After the user authorizes an application, the user is redirected to the application-served URL provided by this parameter.
793
+ */
794
+ public function oAuthAuthorize($oauthToken, $oauthCallback = null)
795
+ {
796
+ // build parameters
797
+ $parameters = array();
798
+ $parameters['oauth_token'] = (string) $oauthToken;
799
+ if($oauthCallback !== null) $parameters['oauth_callback'] = (string) $oauthCallback;
800
+
801
+ // build url
802
+ $url = self::API_AUTH_URL . '/1/oauth/authorize?' . http_build_query($parameters);
803
+
804
+ // redirect
805
+ header('Location: ' . $url);
806
+ exit;
807
+ }
808
+
809
+ public function mwp_oAuthAuthorize($oauthToken, $oauthCallback = null)
810
+ {
811
+ // build parameters
812
+ $parameters = array();
813
+ $parameters['oauth_token'] = (string) $oauthToken;
814
+ if($oauthCallback !== null) $parameters['oauth_callback'] = (string) $oauthCallback;
815
+
816
+ // build url
817
+ $url = self::API_AUTH_URL . '/1/oauth/authorize?' . http_build_query($parameters);
818
+
819
+ return $url;
820
+ }
821
+
822
+ /**
823
+ * This call returns a access token and the corresponding access token secret.
824
+ * Upon return, the authorization process is now complete and the access token and corresponding secret are used to sign requests for the metadata and file content API calls.
825
+ *
826
+ * @return array
827
+ * @param string $oauthToken The token returned after authorizing.
828
+ */
829
+ public function oAuthAccessToken($oauthToken)
830
+ {
831
+ // build parameters
832
+ $parameters = array();
833
+ $parameters['oauth_token'] = (string) $oauthToken;
834
+
835
+ // make the call
836
+ $response = $this->doOAuthCall('1/oauth/access_token', $parameters, 'POST', false);
837
+
838
+ // process response
839
+ $response = (array) explode('&', $response);
840
+ $return = array();
841
+
842
+ // loop chunks
843
+ foreach($response as $chunk)
844
+ {
845
+ // split again
846
+ $chunks = explode('=', $chunk, 2);
847
+
848
+ // store return
849
+ if(count($chunks) == 2) $return[$chunks[0]] = $chunks[1];
850
+ }
851
+
852
+ // return
853
+ return $return;
854
+ }
855
+
856
+
857
+ // token resources
858
+ /**
859
+ * The token call provides a consumer/secret key pair you can use to consistently access the user's account.
860
+ * This is the preferred method of authentication over storing the username and password.
861
+ * Use the key pair as a signature with every subsequent call.
862
+ * The request must be signed using the application's developer and secret key token. Request or access tokens are necessary.
863
+ *
864
+ * Warning: DO NOT STORE THE USER'S PASSWORD! The way this call works is you call it once with the user's email and password and then
865
+ * keep the token around for later. You do NOT (I repeat NOT) call this before everything you do or on each program startup.
866
+ * We watch for this and will shut down your application with little notice if we catch you.
867
+ * In fact, the Objective-C code does this for you so you can't get it wrong.
868
+ *
869
+ * @return array Upon successful verification of the user's credentials, returns an array representation of the access token and secret.
870
+ * @param string $email The email account of the user.
871
+ * @param string $password The password of the user.
872
+ */
873
+ public function token($email, $password)
874
+ {
875
+ // build parameters
876
+ $parameters = array();
877
+ $parameters['email'] = (string) $email;
878
+ $parameters['password'] = (string) $password;
879
+
880
+ // make the call
881
+ $response = (array) $this->doOAuthCall('1/token', $parameters);
882
+
883
+ // validate and set
884
+ if(isset($response['token'])) $this->setOAuthToken($response['token']);
885
+ if(isset($response['secret'])) $this->setOAuthTokenSecret($response['secret']);
886
+
887
+ // return
888
+ return $response;
889
+ }
890
+
891
+
892
+ // account resources
893
+ /**
894
+ * Given a set of account information, the account call allows an application to create a new Dropbox user account.
895
+ * This is useful for situations where the trusted third party application is possibly the user's first interaction with Dropbox.
896
+ *
897
+ * @return bool
898
+ * @param string $email The email account of the user.
899
+ * @param string $password The password for the user.
900
+ * @param string $firstName The user's first name.
901
+ * @param string $lastName The user's last name.
902
+ */
903
+ public function account($email, $password, $firstName, $lastName)
904
+ {
905
+ // build parameters
906
+ $parameters['email'] = (string) $email;
907
+ $parameters['first_name'] = (string) $firstName;
908
+ $parameters['last_name'] = (string) $lastName;
909
+ $parameters['password'] = (string) $password;
910
+
911
+ return (bool) ($this->doCall('1/account', $parameters, 'POST', null, false) == 'OK');
912
+ }
913
+
914
+
915
+ /**
916
+ * Get the user account information.
917
+ *
918
+ * @return array
919
+ */
920
+ public function accountInfo()
921
+ {
922
+ // make the call
923
+ return (array) $this->doCall('1/account/info');
924
+ }
925
+
926
+
927
+ // files & metadata
928
+ /**
929
+ * Retrieves file contents relative to the user's Dropbox root or the application's directory within the user's Dropbox.
930
+ *
931
+ * @return string
932
+ * @param string $path Path of the directory wherin the file is located.
933
+ * @param bool[optional] $sandbox Sandbox mode?
934
+ */
935
+ public function filesGet($path, $sandbox = false)
936
+ {
937
+ // build url
938
+ $url = '1/files/';
939
+ $url .= ($sandbox) ? 'sandbox/' : 'dropbox/';
940
+ $url .= trim((string) $path, '/');
941
+
942
+ // make the call
943
+ return $this->doCall($url, null, 'GET', null, false, true);
944
+ }
945
+
946
+
947
+ /**
948
+ * Uploads file contents relative to the user's Dropbox root or the application's directory within the user's Dropbox.
949
+ *
950
+ * @return bool
951
+ * @param string $path Path of the directory wherin the file should be uploaded.
952
+ * @param string $localFile Path to the local file.
953
+ * @param bool[optional] $sandbox Sandbox mode?
954
+ */
955
+ public function filesPost($path, $localFile, $sandbox = false)
956
+ {
957
+ // build url
958
+ $url = '1/files/';
959
+ $url .= ($sandbox) ? 'sandbox/' : 'dropbox/';
960
+ $url .= trim((string) $path, '/');
961
+
962
+ // make the call
963
+ $return = $this->doCall($url, null, 'POST', $localFile, true, true);
964
+ // return the result
965
+ return (bool) (isset($return['size']) && $return['size'] == 'winner!');
966
+ }
967
+
968
+
969
+ /**
970
+ * Returns metadata for the file or directory at the given <path> location relative to the user's Dropbox or
971
+ * the user's application sandbox. If <path> represents a directory and the list parameter is true, the metadata will
972
+ * also include a listing of metadata for the directory's contents.
973
+ *
974
+ * @return array
975
+ * @param string[optional] $path The path to the file/director to get the metadata for.
976
+ * @param int[optional] $fileLimit When listing a directory, the service will not report listings containing more than $fileLimit files.
977
+ * @param bool[optional] $hash Listing return values include a hash representing the state of the directory's contents.
978
+ * @param bool[optional] $list If true, this call returns a list of metadata representations for the contents of the directory. If false, this call returns the metadata for the directory itself.
979
+ * @param bool[optional] $sandbox Sandbox mode?
980
+ */
981
+ public function metadata($path = '', $fileLimit = 10000, $hash = false, $list = true, $sandbox = false)
982
+ {
983
+ // build url
984
+ $url = '1/metadata/';
985
+ $url .= ($sandbox) ? 'sandbox/' : 'dropbox/';
986
+ $url .= trim((string) $path, '/');
987
+
988
+ // build parameters
989
+ $parameters = null;
990
+ $parameters['file_limit'] = (int) $fileLimit;
991
+ if((bool) $hash) $parameters['hash'] = '';
992
+ $parameters['list'] = ($list) ? 'true': 'false';
993
+
994
+ // make the call
995
+ return (array) $this->doCall($url, $parameters);
996
+ }
997
+
998
+
999
+ /**
1000
+ * Get a minimized thumbnail for a photo.
1001
+ *
1002
+ * @return string Will return a base64_encode string with the JPEG-data
1003
+ * @param string $path The path to the photo.
1004
+ * @param string[optional] $size The size, possible values are: 'small' (32x32), 'medium' (64x64), 'large' (128x128).
1005
+ */
1006
+ public function thumbnails($path, $size = 'small')
1007
+ {
1008
+ // build url
1009
+ $url = '1/thumbnails/dropbox/';
1010
+ $url .= trim((string) $path, '/');
1011
+
1012
+ // build parameters
1013
+ $parameters['size'] = (string) $size;
1014
+
1015
+ // make the call
1016
+ return $this->doCall($url, $parameters, 'GET', null, false, true);
1017
+ }
1018
+
1019
+
1020
+ // file operations
1021
+ /**
1022
+ * Copy a file or folder to a new location.
1023
+ *
1024
+ * @return array
1025
+ * @param string $fromPath fromPath specifies either a file or folder to be copied to the location specified by toPath. This path is interpreted relative to the location specified by root.
1026
+ * @param string $toPath toPath specifies the destination path including the new name for file or folder. This path is interpreted relative to the location specified by root.
1027
+ * @param bool[optional] $sandbox Sandbox mode?
1028
+ */
1029
+ public function fileopsCopy($fromPath, $toPath, $sandbox = false)
1030
+ {
1031
+ // build url
1032
+ $url = '1/fileops/copy';
1033
+
1034
+ // build parameters
1035
+ $parameters['from_path'] = (string) $fromPath;
1036
+ $parameters['to_path'] = (string) $toPath;
1037
+ $parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
1038
+
1039
+ // make the call
1040
+ return $this->doCall($url, $parameters, 'POST');
1041
+ }
1042
+
1043
+
1044
+ /**
1045
+ * Create a folder relative to the user's Dropbox root or the user's application sandbox folder.
1046
+ *
1047
+ * @return array
1048
+ * @param string $path The path to the new folder to create, relative to root.
1049
+ * @param bool[optional] $sandbox Sandbox mode?
1050
+ */
1051
+ public function fileopsCreateFolder($path, $sandbox = false)
1052
+ {
1053
+ // build url
1054
+ $url = '1/fileops/create_folder';
1055
+
1056
+ // build parameters
1057
+ $parameters['path'] = trim((string) $path, '/');
1058
+ $parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
1059
+
1060
+ // make the call
1061
+ return $this->doCall($url, $parameters, 'POST');
1062
+ }
1063
+
1064
+
1065
+ /**
1066
+ * Deletes a file or folder.
1067
+ *
1068
+ * @return array
1069
+ * @param string $path path specifies either a file or folder to be deleted. This path is interpreted relative to the location specified by root.
1070
+ * @param bool[optional] $sandbox Sandbox mode?
1071
+ */
1072
+ public function fileopsDelete($path, $sandbox = false)
1073
+ {
1074
+ // build url
1075
+ $url = '1/fileops/delete';
1076
+
1077
+ // build parameters
1078
+ $parameters['path'] = trim((string) $path, '/');
1079
+ $parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
1080
+ // make the call
1081
+ return $this->doCall($url, $parameters, 'POST');
1082
+ }
1083
+
1084
+
1085
+ /**
1086
+ * Move a file or folder to a new location.
1087
+ *
1088
+ * @return array
1089
+ * @param string $fromPath fromPath specifies either a file or folder to be copied to the location specified by toPath. This path is interpreted relative to the location specified by root.
1090
+ * @param string $toPath toPath specifies the destination path including the new name for file or folder. This path is interpreted relative to the location specified by root.
1091
+ * @param bool[optional] $sandbox Sandbox mode?
1092
+ */
1093
+ public function fileopsMove($fromPath, $toPath, $sandbox = false)
1094
+ {
1095
+ // build url
1096
+ $url = '1/fileops/move';
1097
+
1098
+ // build parameters
1099
+ $parameters['from_path'] = (string) $fromPath;
1100
+ $parameters['to_path'] = (string) $toPath;
1101
+ $parameters['root'] = ($sandbox) ? 'sandbox' : 'dropbox';
1102
+
1103
+ // make the call
1104
+ return $this->doCall($url, $parameters, 'POST');
1105
+ }
1106
+
1107
+ function _log($mixed)
1108
+ {
1109
+ if (is_array($mixed)) {
1110
+ $mixed = print_r($mixed, 1);
1111
+ } else if (is_object($mixed)) {
1112
+ ob_start();
1113
+ var_dump($mixed);
1114
+ $mixed = ob_get_clean();
1115
+ }
1116
+
1117
+ $handle = fopen(dirname(__FILE__) . '/log', 'a');
1118
+ fwrite($handle, $mixed . PHP_EOL);
1119
+ fclose($handle);
1120
+ }
1121
+ }
1122
+
1123
+
1124
+ /**
1125
+ * Dropbox Exception class
1126
+ *
1127
+ * @author Tijs Verkoyen <php-dropbox@verkoyen.eu>
1128
+ */
1129
+ class DropboxException extends Exception
1130
+ {
1131
+ }
1132
+
1133
+ ?>
lib/dropbox.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Dropbox Uploader
4
+ *
5
+ * Copyright (c) 2009 Jaka Jancar
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * @author Jaka Jancar [jaka@kubje.org] [http://jaka.kubje.org/]
26
+ * @version 1.1.5
27
+ */
28
+ class DropboxUploader {
29
+ protected $email;
30
+ protected $password;
31
+ protected $caCertSourceType = self::CACERT_SOURCE_SYSTEM;
32
+ const CACERT_SOURCE_SYSTEM = 0;
33
+ const CACERT_SOURCE_FILE = 1;
34
+ const CACERT_SOURCE_DIR = 2;
35
+ protected $caCertSource;
36
+ protected $loggedIn = false;
37
+ protected $cookies = array();
38
+
39
+ /**
40
+ * Constructor
41
+ *
42
+ * @param string $email
43
+ * @param string|null $password
44
+ */
45
+ public function __construct($email, $password) {
46
+ // Check requirements
47
+ if (!extension_loaded('curl'))
48
+ throw new Exception('DropboxUploader requires the cURL extension.');
49
+
50
+ $this->email = $email;
51
+ $this->password = $password;
52
+ }
53
+
54
+ public function setCaCertificateFile($file)
55
+ {
56
+ $this->caCertSourceType = self::CACERT_SOURCE_FILE;
57
+ $this->caCertSource = $file;
58
+ }
59
+
60
+ public function setCaCertificateDir($dir)
61
+ {
62
+ $this->caCertSourceType = self::CACERT_SOURCE_DIR;
63
+ $this->caCertSource = $dir;
64
+ }
65
+
66
+ public function upload($filename, $remoteDir='/') {
67
+ if (!file_exists($filename) or !is_file($filename) or !is_readable($filename))
68
+ throw new Exception("File '$filename' does not exist or is not readable.");
69
+
70
+ if (!is_string($remoteDir))
71
+ throw new Exception("Remote directory must be a string, is ".gettype($remoteDir)." instead.");
72
+
73
+ if (!$this->loggedIn)
74
+ $this->login();
75
+
76
+ $data = $this->request('https://www.dropbox.com/home');
77
+ $token = $this->extractToken($data, 'https://dl-web.dropbox.com/upload');
78
+
79
+ $data = $this->request('https://dl-web.dropbox.com/upload', true, array('plain'=>'yes', 'file'=>'@'.$filename, 'dest'=>$remoteDir, 't'=>$token));
80
+ if (strpos($data, 'HTTP/1.1 302 FOUND') === false)
81
+ throw new Exception('Upload failed!');
82
+ }
83
+
84
+ protected function login() {
85
+ $data = $this->request('https://www.dropbox.com/login');
86
+ $token = $this->extractToken($data, '/login');
87
+
88
+ $data = $this->request('https://www.dropbox.com/login', true, array('login_email'=>$this->email, 'login_password'=>$this->password, 't'=>$token));
89
+
90
+ if (stripos($data, 'location: /home') === false)
91
+ throw new Exception('Login unsuccessful.');
92
+
93
+ $this->loggedIn = true;
94
+ }
95
+
96
+ protected function request($url, $post=false, $postData=array()) {
97
+ $ch = curl_init();
98
+ curl_setopt($ch, CURLOPT_URL, $url);
99
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
100
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
101
+ switch ($this->caCertSourceType) {
102
+ case self::CACERT_SOURCE_FILE:
103
+ curl_setopt($ch, CURLOPT_CAINFO, $this->caCertSource);
104
+ break;
105
+ case self::CACERT_SOURCE_DIR:
106
+ curl_setopt($ch, CURLOPT_CAPATH, $this->caCertSource);
107
+ break;
108
+ }
109
+ curl_setopt($ch, CURLOPT_HEADER, 1);
110
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
111
+ if ($post) {
112
+ curl_setopt($ch, CURLOPT_POST, $post);
113
+ curl_setopt($ch, CURLOPT_POSTFIELDS, array_map('stripcslashes', $postData));
114
+ }
115
+
116
+ // Send cookies
117
+ $rawCookies = array();
118
+ foreach ($this->cookies as $k=>$v)
119
+ $rawCookies[] = "$k=$v";
120
+ $rawCookies = implode(';', $rawCookies);
121
+ curl_setopt($ch, CURLOPT_COOKIE, $rawCookies);
122
+
123
+ $data = curl_exec($ch);
124
+
125
+ if ($data === false)
126
+ throw new Exception('Cannot execute request: '.curl_error($ch));
127
+
128
+ // Store received cookies
129
+ preg_match_all('/Set-Cookie: ([^=]+)=(.*?);/i', $data, $matches, PREG_SET_ORDER);
130
+ foreach ($matches as $match)
131
+ $this->cookies[$match[1]] = $match[2];
132
+
133
+ curl_close($ch);
134
+
135
+ return $data;
136
+ }
137
+
138
+ protected function extractToken($html, $formAction) {
139
+ if (!preg_match('/<form [^>]*'.preg_quote($formAction, '/').'[^>]*>.*?(<input [^>]*name="t" [^>]*value="(.*?)"[^>]*>).*?<\/form>/is', $html, $matches) || !isset($matches[2]))
140
+ throw new Exception("Cannot extract token! (form action=$formAction)");
141
+ return $matches[2];
142
+ }
143
+
144
+ }
lib/s3.php ADDED
@@ -0,0 +1,1966 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * $Id$
4
+ *
5
+ * Copyright (c) 2011, 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.5.0-dev
36
+ */
37
+ class S3
38
+ {
39
+ // ACL flags
40
+ const ACL_PRIVATE = 'private';
41
+ const ACL_PUBLIC_READ = 'public-read';
42
+ const ACL_PUBLIC_READ_WRITE = 'public-read-write';
43
+ const ACL_AUTHENTICATED_READ = 'authenticated-read';
44
+
45
+ const STORAGE_CLASS_STANDARD = 'STANDARD';
46
+ const STORAGE_CLASS_RRS = 'REDUCED_REDUNDANCY';
47
+
48
+ private static $__accessKey = null; // AWS Access key
49
+ private static $__secretKey = null; // AWS Secret key
50
+ private static $__sslKey = null;
51
+
52
+ public static $endpoint = 's3.amazonaws.com';
53
+ public static $proxy = null;
54
+
55
+ public static $useSSL = false;
56
+ public static $useSSLValidation = true;
57
+ public static $useExceptions = false;
58
+
59
+ // SSL CURL SSL options - only needed if you are experiencing problems with your OpenSSL configuration
60
+ public static $sslKey = null;
61
+ public static $sslCert = null;
62
+ public static $sslCACert = null;
63
+
64
+ private static $__signingKeyPairId = null; // AWS Key Pair ID
65
+ private static $__signingKeyResource = false; // Key resource, freeSigningKey() must be called to clear it from memory
66
+
67
+
68
+ /**
69
+ * Constructor - if you're not using the class statically
70
+ *
71
+ * @param string $accessKey Access key
72
+ * @param string $secretKey Secret key
73
+ * @param boolean $useSSL Enable SSL
74
+ * @return void
75
+ */
76
+ public function __construct($accessKey = null, $secretKey = null, $useSSL = false, $endpoint = 's3.amazonaws.com')
77
+ {
78
+ if ($accessKey !== null && $secretKey !== null)
79
+ self::setAuth($accessKey, $secretKey);
80
+ self::$useSSL = $useSSL;
81
+ self::$endpoint = $endpoint;
82
+ }
83
+
84
+
85
+ /**
86
+ * Set the sertvice endpoint
87
+ *
88
+ * @param string $host Hostname
89
+ * @return void
90
+ */
91
+ public function setEndpoint($host)
92
+ {
93
+ self::$endpoint = $host;
94
+ }
95
+
96
+ /**
97
+ * Set AWS access key and secret key
98
+ *
99
+ * @param string $accessKey Access key
100
+ * @param string $secretKey Secret key
101
+ * @return void
102
+ */
103
+ public static function setAuth($accessKey, $secretKey)
104
+ {
105
+ self::$__accessKey = $accessKey;
106
+ self::$__secretKey = $secretKey;
107
+ }
108
+
109
+
110
+ /**
111
+ * Check if AWS keys have been set
112
+ *
113
+ * @return boolean
114
+ */
115
+ public static function hasAuth() {
116
+ return (self::$__accessKey !== null && self::$__secretKey !== null);
117
+ }
118
+
119
+
120
+ /**
121
+ * Set SSL on or off
122
+ *
123
+ * @param boolean $enabled SSL enabled
124
+ * @param boolean $validate SSL certificate validation
125
+ * @return void
126
+ */
127
+ public static function setSSL($enabled, $validate = true)
128
+ {
129
+ self::$useSSL = $enabled;
130
+ self::$useSSLValidation = $validate;
131
+ }
132
+
133
+
134
+ /**
135
+ * Set SSL client certificates (experimental)
136
+ *
137
+ * @param string $sslCert SSL client certificate
138
+ * @param string $sslKey SSL client key
139
+ * @param string $sslCACert SSL CA cert (only required if you are having problems with your system CA cert)
140
+ * @return void
141
+ */
142
+ public static function setSSLAuth($sslCert = null, $sslKey = null, $sslCACert = null)
143
+ {
144
+ self::$sslCert = $sslCert;
145
+ self::$sslKey = $sslKey;
146
+ self::$sslCACert = $sslCACert;
147
+ }
148
+
149
+
150
+ /**
151
+ * Set proxy information
152
+ *
153
+ * @param string $host Proxy hostname and port (localhost:1234)
154
+ * @param string $user Proxy username
155
+ * @param string $pass Proxy password
156
+ * @param constant $type CURL proxy type
157
+ * @return void
158
+ */
159
+ public static function setProxy($host, $user = null, $pass = null, $type = CURLPROXY_SOCKS5)
160
+ {
161
+ self::$proxy = array('host' => $host, 'type' => $type, 'user' => null, 'pass' => 'null');
162
+ }
163
+
164
+
165
+ /**
166
+ * Set the error mode to exceptions
167
+ *
168
+ * @param boolean $enabled Enable exceptions
169
+ * @return void
170
+ */
171
+ public static function setExceptions($enabled = true)
172
+ {
173
+ self::$useExceptions = $enabled;
174
+ }
175
+
176
+
177
+ /**
178
+ * Set signing key
179
+ *
180
+ * @param string $keyPairId AWS Key Pair ID
181
+ * @param string $signingKey Private Key
182
+ * @param boolean $isFile Load private key from file, set to false to load string
183
+ * @return boolean
184
+ */
185
+ public static function setSigningKey($keyPairId, $signingKey, $isFile = true)
186
+ {
187
+ self::$__signingKeyPairId = $keyPairId;
188
+ if ((self::$__signingKeyResource = openssl_pkey_get_private($isFile ?
189
+ file_get_contents($signingKey) : $signingKey)) !== false) return true;
190
+ self::__triggerError('S3::setSigningKey(): Unable to open load private key: '.$signingKey, __FILE__, __LINE__);
191
+ return false;
192
+ }
193
+
194
+
195
+ /**
196
+ * Free signing key from memory, MUST be called if you are using setSigningKey()
197
+ *
198
+ * @return void
199
+ */
200
+ public static function freeSigningKey()
201
+ {
202
+ if (self::$__signingKeyResource !== false)
203
+ openssl_free_key(self::$__signingKeyResource);
204
+ }
205
+
206
+
207
+ /**
208
+ * Internal error handler
209
+ *
210
+ * @internal Internal error handler
211
+ * @param string $message Error message
212
+ * @param string $file Filename
213
+ * @param integer $line Line number
214
+ * @param integer $code Error code
215
+ * @return void
216
+ */
217
+ private static function __triggerError($message, $file, $line, $code = 0)
218
+ {
219
+
220
+ //if (self::$useExceptions)
221
+ throw new mwpS3Exception($message, $file, $line, $code);
222
+ //else
223
+ //trigger_error($message, E_USER_WARNING);
224
+ }
225
+
226
+
227
+ /**
228
+ * Get a list of buckets
229
+ *
230
+ * @param boolean $detailed Returns detailed bucket list when true
231
+ * @return array | false
232
+ */
233
+ public static function listBuckets($detailed = false)
234
+ {
235
+ $rest = new iwpS3Request('GET', '', '', self::$endpoint);
236
+ $rest = $rest->getResponse();
237
+ if ($rest->error === false && $rest->code !== 200)
238
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
239
+ if ($rest->error !== false)
240
+ {
241
+ self::__triggerError(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'],
242
+ $rest->error['message']), __FILE__, __LINE__);
243
+ return false;
244
+ }
245
+ $results = array();
246
+ if (!isset($rest->body->Buckets)) return $results;
247
+
248
+ if ($detailed)
249
+ {
250
+ if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
251
+ $results['owner'] = array(
252
+ 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID
253
+ );
254
+ $results['buckets'] = array();
255
+ foreach ($rest->body->Buckets->Bucket as $b)
256
+ $results['buckets'][] = array(
257
+ 'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate)
258
+ );
259
+ } else
260
+ foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name;
261
+
262
+ return $results;
263
+ }
264
+
265
+
266
+ /*
267
+ * Get contents for a bucket
268
+ *
269
+ * If maxKeys is null this method will loop through truncated result sets
270
+ *
271
+ * @param string $bucket Bucket name
272
+ * @param string $prefix Prefix
273
+ * @param string $marker Marker (last file listed)
274
+ * @param string $maxKeys Max keys (maximum number of keys to return)
275
+ * @param string $delimiter Delimiter
276
+ * @param boolean $returnCommonPrefixes Set to true to return CommonPrefixes
277
+ * @return array | false
278
+ */
279
+ public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false)
280
+ {
281
+ $rest = new iwpS3Request('GET', $bucket, '', self::$endpoint);
282
+ if ($maxKeys == 0) $maxKeys = null;
283
+ if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
284
+ if ($marker !== null && $marker !== '') $rest->setParameter('marker', $marker);
285
+ if ($maxKeys !== null && $maxKeys !== '') $rest->setParameter('max-keys', $maxKeys);
286
+ if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
287
+ $response = $rest->getResponse();
288
+ if ($response->error === false && $response->code !== 200)
289
+ $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
290
+ if ($response->error !== false)
291
+ {
292
+ self::__triggerError(sprintf("S3::getBucket(): [%s] %s",
293
+ $response->error['code'], $response->error['message']), __FILE__, __LINE__);
294
+ return false;
295
+ }
296
+
297
+ $results = array();
298
+
299
+ $nextMarker = null;
300
+ if (isset($response->body, $response->body->Contents))
301
+ foreach ($response->body->Contents as $c)
302
+ {
303
+ $results[(string)$c->Key] = array(
304
+ 'name' => (string)$c->Key,
305
+ 'time' => strtotime((string)$c->LastModified),
306
+ 'size' => (int)$c->Size,
307
+ 'hash' => substr((string)$c->ETag, 1, -1)
308
+ );
309
+ $nextMarker = (string)$c->Key;
310
+ }
311
+
312
+ if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
313
+ foreach ($response->body->CommonPrefixes as $c)
314
+ $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
315
+
316
+ if (isset($response->body, $response->body->IsTruncated) &&
317
+ (string)$response->body->IsTruncated == 'false') return $results;
318
+
319
+ if (isset($response->body, $response->body->NextMarker))
320
+ $nextMarker = (string)$response->body->NextMarker;
321
+
322
+ // Loop through truncated results if maxKeys isn't specified
323
+ if ($maxKeys == null && $nextMarker !== null && (string)$response->body->IsTruncated == 'true')
324
+ do
325
+ {
326
+ $rest = new iwpS3Request('GET', $bucket, '', self::$endpoint);
327
+ if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
328
+ $rest->setParameter('marker', $nextMarker);
329
+ if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
330
+
331
+ if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break;
332
+
333
+ if (isset($response->body, $response->body->Contents))
334
+ foreach ($response->body->Contents as $c)
335
+ {
336
+ $results[(string)$c->Key] = array(
337
+ 'name' => (string)$c->Key,
338
+ 'time' => strtotime((string)$c->LastModified),
339
+ 'size' => (int)$c->Size,
340
+ 'hash' => substr((string)$c->ETag, 1, -1)
341
+ );
342
+ $nextMarker = (string)$c->Key;
343
+ }
344
+
345
+ if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
346
+ foreach ($response->body->CommonPrefixes as $c)
347
+ $results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
348
+
349
+ if (isset($response->body, $response->body->NextMarker))
350
+ $nextMarker = (string)$response->body->NextMarker;
351
+
352
+ } while ($response !== false && (string)$response->body->IsTruncated == 'true');
353
+
354
+ return $results;
355
+ }
356
+
357
+
358
+ /**
359
+ * Put a bucket
360
+ *
361
+ * @param string $bucket Bucket name
362
+ * @param constant $acl ACL flag
363
+ * @param string $location Set as "EU" to create buckets hosted in Europe
364
+ * @return boolean
365
+ */
366
+ public static function putBucket($bucket, $acl = self::ACL_PRIVATE, $location = false)
367
+ {
368
+ $rest = new iwpS3Request('PUT', $bucket, '', self::$endpoint);
369
+ $rest->setAmzHeader('x-amz-acl', $acl);
370
+
371
+ if ($location !== false)
372
+ {
373
+ $dom = new DOMDocument;
374
+ $createBucketConfiguration = $dom->createElement('CreateBucketConfiguration');
375
+ $locationConstraint = $dom->createElement('LocationConstraint', $location);
376
+ $createBucketConfiguration->appendChild($locationConstraint);
377
+ $dom->appendChild($createBucketConfiguration);
378
+ $rest->data = $dom->saveXML();
379
+ $rest->size = strlen($rest->data);
380
+ $rest->setHeader('Content-Type', 'application/xml');
381
+ }
382
+ $rest = $rest->getResponse();
383
+
384
+ if ($rest->error === false && $rest->code !== 200)
385
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
386
+ if ($rest->error !== false)
387
+ {
388
+ self::__triggerError(sprintf("S3::putBucket({$bucket}, {$acl}, {$location}): [%s] %s",
389
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
390
+ return false;
391
+ }
392
+ return true;
393
+ }
394
+
395
+
396
+ /**
397
+ * Delete an empty bucket
398
+ *
399
+ * @param string $bucket Bucket name
400
+ * @return boolean
401
+ */
402
+ public static function deleteBucket($bucket)
403
+ {
404
+ $rest = new iwpS3Request('DELETE', $bucket, '', self::$endpoint);
405
+ $rest = $rest->getResponse();
406
+ if ($rest->error === false && $rest->code !== 204)
407
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
408
+ if ($rest->error !== false)
409
+ {
410
+ self::__triggerError(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
411
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
412
+ return false;
413
+ }
414
+ return true;
415
+ }
416
+
417
+
418
+ /**
419
+ * Create input info array for putObject()
420
+ *
421
+ * @param string $file Input file
422
+ * @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own)
423
+ * @return array | false
424
+ */
425
+ public static function inputFile($file, $md5sum = true)
426
+ {
427
+ if (!file_exists($file) || !is_file($file) || !is_readable($file))
428
+ {
429
+ self::__triggerError('S3::inputFile(): Unable to open input file: '.$file, __FILE__, __LINE__);
430
+ return false;
431
+ }
432
+ return array('file' => $file, 'size' => filesize($file), 'md5sum' => $md5sum !== false ?
433
+ (is_string($md5sum) ? $md5sum : base64_encode(md5_file($file, true))) : '');
434
+ }
435
+
436
+
437
+ /**
438
+ * Create input array info for putObject() with a resource
439
+ *
440
+ * @param string $resource Input resource to read from
441
+ * @param integer $bufferSize Input byte size
442
+ * @param string $md5sum MD5 hash to send (optional)
443
+ * @return array | false
444
+ */
445
+ public static function inputResource(&$resource, $bufferSize, $md5sum = '')
446
+ {
447
+ if (!is_resource($resource) || $bufferSize < 0)
448
+ {
449
+ self::__triggerError('S3::inputResource(): Invalid resource or buffer size', __FILE__, __LINE__);
450
+ return false;
451
+ }
452
+ $input = array('size' => $bufferSize, 'md5sum' => $md5sum);
453
+ $input['fp'] =& $resource;
454
+ return $input;
455
+ }
456
+
457
+
458
+ /**
459
+ * Put an object
460
+ *
461
+ * @param mixed $input Input data
462
+ * @param string $bucket Bucket name
463
+ * @param string $uri Object URI
464
+ * @param constant $acl ACL constant
465
+ * @param array $metaHeaders Array of x-amz-meta-* headers
466
+ * @param array $requestHeaders Array of request headers or content type as a string
467
+ * @param constant $storageClass Storage class constant
468
+ * @return boolean
469
+ */
470
+ public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array(), $storageClass = self::STORAGE_CLASS_STANDARD)
471
+ {
472
+ if ($input === false) return false;
473
+ $rest = new iwpS3Request('PUT', $bucket, $uri, self::$endpoint);
474
+
475
+ if (is_string($input)) $input = array(
476
+ 'data' => $input, 'size' => strlen($input),
477
+ 'md5sum' => base64_encode(md5($input, true))
478
+ );
479
+
480
+ // Data
481
+ if (isset($input['fp']))
482
+ $rest->fp =& $input['fp'];
483
+ elseif (isset($input['file']))
484
+ $rest->fp = @fopen($input['file'], 'rb');
485
+ elseif (isset($input['data']))
486
+ $rest->data = $input['data'];
487
+
488
+ // Content-Length (required)
489
+ if (isset($input['size']) && $input['size'] >= 0)
490
+ $rest->size = $input['size'];
491
+ else {
492
+ if (isset($input['file']))
493
+ $rest->size = filesize($input['file']);
494
+ elseif (isset($input['data']))
495
+ $rest->size = strlen($input['data']);
496
+ }
497
+
498
+ // Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
499
+ if (is_array($requestHeaders))
500
+ foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
501
+ elseif (is_string($requestHeaders)) // Support for legacy contentType parameter
502
+ $input['type'] = $requestHeaders;
503
+
504
+ // Content-Type
505
+ if (!isset($input['type']))
506
+ {
507
+ if (isset($requestHeaders['Content-Type']))
508
+ $input['type'] =& $requestHeaders['Content-Type'];
509
+ elseif (isset($input['file']))
510
+ $input['type'] = self::__getMimeType($input['file']);
511
+ else
512
+ $input['type'] = 'application/octet-stream';
513
+ }
514
+
515
+ if ($storageClass !== self::STORAGE_CLASS_STANDARD) // Storage class
516
+ $rest->setAmzHeader('x-amz-storage-class', $storageClass);
517
+
518
+ // We need to post with Content-Length and Content-Type, MD5 is optional
519
+ if ($rest->size >= 0 && ($rest->fp !== false || $rest->data !== false))
520
+ {
521
+ $rest->setHeader('Content-Type', $input['type']);
522
+ if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']);
523
+
524
+ $rest->setAmzHeader('x-amz-acl', $acl);
525
+ foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
526
+ $rest->getResponse();
527
+ } else
528
+ $rest->response->error = array('code' => 0, 'message' => 'Missing input parameters');
529
+
530
+ if ($rest->response->error === false && $rest->response->code !== 200)
531
+ $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
532
+ if ($rest->response->error !== false)
533
+ {
534
+ self::__triggerError(sprintf("S3::putObject(): [%s] %s",
535
+ $rest->response->error['code'], $rest->response->error['message']), __FILE__, __LINE__);
536
+ return false;
537
+ }
538
+ return true;
539
+ }
540
+
541
+
542
+ /**
543
+ * Put an object from a file (legacy function)
544
+ *
545
+ * @param string $file Input file path
546
+ * @param string $bucket Bucket name
547
+ * @param string $uri Object URI
548
+ * @param constant $acl ACL constant
549
+ * @param array $metaHeaders Array of x-amz-meta-* headers
550
+ * @param string $contentType Content type
551
+ * @return boolean
552
+ */
553
+ public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null)
554
+ {
555
+ return self::putObject(self::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType);
556
+ }
557
+
558
+
559
+ /**
560
+ * Put an object from a string (legacy function)
561
+ *
562
+ * @param string $string Input data
563
+ * @param string $bucket Bucket name
564
+ * @param string $uri Object URI
565
+ * @param constant $acl ACL constant
566
+ * @param array $metaHeaders Array of x-amz-meta-* headers
567
+ * @param string $contentType Content type
568
+ * @return boolean
569
+ */
570
+ public static function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain')
571
+ {
572
+ return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType);
573
+ }
574
+
575
+
576
+ /**
577
+ * Get an object
578
+ *
579
+ * @param string $bucket Bucket name
580
+ * @param string $uri Object URI
581
+ * @param mixed $saveTo Filename or resource to write to
582
+ * @return mixed
583
+ */
584
+ public static function getObject($bucket, $uri, $saveTo = false)
585
+ {
586
+ $rest = new iwpS3Request('GET', $bucket, $uri, self::$endpoint);
587
+ if ($saveTo !== false)
588
+ {
589
+ if (is_resource($saveTo))
590
+ $rest->fp =& $saveTo;
591
+ else
592
+ if (($rest->fp = @fopen($saveTo, 'wb')) !== false)
593
+ $rest->file = realpath($saveTo);
594
+ else
595
+ $rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
596
+ }
597
+ if ($rest->response->error === false) $rest->getResponse();
598
+
599
+ if ($rest->response->error === false && $rest->response->code !== 200)
600
+ $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
601
+ if ($rest->response->error !== false)
602
+ {
603
+ self::__triggerError(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
604
+ $rest->response->error['code'], $rest->response->error['message']), __FILE__, __LINE__);
605
+ return false;
606
+ }
607
+ return $rest->response;
608
+ }
609
+
610
+
611
+ /**
612
+ * Get object information
613
+ *
614
+ * @param string $bucket Bucket name
615
+ * @param string $uri Object URI
616
+ * @param boolean $returnInfo Return response information
617
+ * @return mixed | false
618
+ */
619
+ public static function getObjectInfo($bucket, $uri, $returnInfo = true)
620
+ {
621
+ $rest = new iwpS3Request('HEAD', $bucket, $uri, self::$endpoint);
622
+ $rest = $rest->getResponse();
623
+ if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404))
624
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
625
+ if ($rest->error !== false)
626
+ {
627
+ self::__triggerError(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
628
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
629
+ return false;
630
+ }
631
+ return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false;
632
+ }
633
+
634
+
635
+ /**
636
+ * Copy an object
637
+ *
638
+ * @param string $bucket Source bucket name
639
+ * @param string $uri Source object URI
640
+ * @param string $bucket Destination bucket name
641
+ * @param string $uri Destination object URI
642
+ * @param constant $acl ACL constant
643
+ * @param array $metaHeaders Optional array of x-amz-meta-* headers
644
+ * @param array $requestHeaders Optional array of request headers (content type, disposition, etc.)
645
+ * @param constant $storageClass Storage class constant
646
+ * @return mixed | false
647
+ */
648
+ public static function copyObject($srcBucket, $srcUri, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array(), $storageClass = self::STORAGE_CLASS_STANDARD)
649
+ {
650
+ $rest = new iwpS3Request('PUT', $bucket, $uri, self::$endpoint);
651
+ $rest->setHeader('Content-Length', 0);
652
+ foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
653
+ foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
654
+ if ($storageClass !== self::STORAGE_CLASS_STANDARD) // Storage class
655
+ $rest->setAmzHeader('x-amz-storage-class', $storageClass);
656
+ $rest->setAmzHeader('x-amz-acl', $acl); // Added rawurlencode() for $srcUri (thanks a.yamanoi)
657
+ $rest->setAmzHeader('x-amz-copy-source', sprintf('/%s/%s', $srcBucket, rawurlencode($srcUri)));
658
+ if (sizeof($requestHeaders) > 0 || sizeof($metaHeaders) > 0)
659
+ $rest->setAmzHeader('x-amz-metadata-directive', 'REPLACE');
660
+
661
+ $rest = $rest->getResponse();
662
+ if ($rest->error === false && $rest->code !== 200)
663
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
664
+ if ($rest->error !== false)
665
+ {
666
+ self::__triggerError(sprintf("S3::copyObject({$srcBucket}, {$srcUri}, {$bucket}, {$uri}): [%s] %s",
667
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
668
+ return false;
669
+ }
670
+ return isset($rest->body->LastModified, $rest->body->ETag) ? array(
671
+ 'time' => strtotime((string)$rest->body->LastModified),
672
+ 'hash' => substr((string)$rest->body->ETag, 1, -1)
673
+ ) : false;
674
+ }
675
+
676
+
677
+ /**
678
+ * Set logging for a bucket
679
+ *
680
+ * @param string $bucket Bucket name
681
+ * @param string $targetBucket Target bucket (where logs are stored)
682
+ * @param string $targetPrefix Log prefix (e,g; domain.com-)
683
+ * @return boolean
684
+ */
685
+ public static function setBucketLogging($bucket, $targetBucket, $targetPrefix = null)
686
+ {
687
+ // The S3 log delivery group has to be added to the target bucket's ACP
688
+ if ($targetBucket !== null && ($acp = self::getAccessControlPolicy($targetBucket, '')) !== false)
689
+ {
690
+ // Only add permissions to the target bucket when they do not exist
691
+ $aclWriteSet = false;
692
+ $aclReadSet = false;
693
+ foreach ($acp['acl'] as $acl)
694
+ if ($acl['type'] == 'Group' && $acl['uri'] == 'http://acs.amazonaws.com/groups/s3/LogDelivery')
695
+ {
696
+ if ($acl['permission'] == 'WRITE') $aclWriteSet = true;
697
+ elseif ($acl['permission'] == 'READ_ACP') $aclReadSet = true;
698
+ }
699
+ if (!$aclWriteSet) $acp['acl'][] = array(
700
+ 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'WRITE'
701
+ );
702
+ if (!$aclReadSet) $acp['acl'][] = array(
703
+ 'type' => 'Group', 'uri' => 'http://acs.amazonaws.com/groups/s3/LogDelivery', 'permission' => 'READ_ACP'
704
+ );
705
+ if (!$aclReadSet || !$aclWriteSet) self::setAccessControlPolicy($targetBucket, '', $acp);
706
+ }
707
+
708
+ $dom = new DOMDocument;
709
+ $bucketLoggingStatus = $dom->createElement('BucketLoggingStatus');
710
+ $bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
711
+ if ($targetBucket !== null)
712
+ {
713
+ if ($targetPrefix == null) $targetPrefix = $bucket . '-';
714
+ $loggingEnabled = $dom->createElement('LoggingEnabled');
715
+ $loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket));
716
+ $loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix));
717
+ // TODO: Add TargetGrants?
718
+ $bucketLoggingStatus->appendChild($loggingEnabled);
719
+ }
720
+ $dom->appendChild($bucketLoggingStatus);
721
+
722
+ $rest = new iwpS3Request('PUT', $bucket, '', self::$endpoint);
723
+ $rest->setParameter('logging', null);
724
+ $rest->data = $dom->saveXML();
725
+ $rest->size = strlen($rest->data);
726
+ $rest->setHeader('Content-Type', 'application/xml');
727
+ $rest = $rest->getResponse();
728
+ if ($rest->error === false && $rest->code !== 200)
729
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
730
+ if ($rest->error !== false)
731
+ {
732
+ self::__triggerError(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s",
733
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
734
+ return false;
735
+ }
736
+ return true;
737
+ }
738
+
739
+
740
+ /**
741
+ * Get logging status for a bucket
742
+ *
743
+ * This will return false if logging is not enabled.
744
+ * Note: To enable logging, you also need to grant write access to the log group
745
+ *
746
+ * @param string $bucket Bucket name
747
+ * @return array | false
748
+ */
749
+ public static function getBucketLogging($bucket)
750
+ {
751
+ $rest = new iwpS3Request('GET', $bucket, '', self::$endpoint);
752
+ $rest->setParameter('logging', null);
753
+ $rest = $rest->getResponse();
754
+ if ($rest->error === false && $rest->code !== 200)
755
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
756
+ if ($rest->error !== false)
757
+ {
758
+ self::__triggerError(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
759
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
760
+ return false;
761
+ }
762
+ if (!isset($rest->body->LoggingEnabled)) return false; // No logging
763
+ return array(
764
+ 'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket,
765
+ 'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix,
766
+ );
767
+ }
768
+
769
+
770
+ /**
771
+ * Disable bucket logging
772
+ *
773
+ * @param string $bucket Bucket name
774
+ * @return boolean
775
+ */
776
+ public static function disableBucketLogging($bucket)
777
+ {
778
+ return self::setBucketLogging($bucket, null);
779
+ }
780
+
781
+
782
+ /**
783
+ * Get a bucket's location
784
+ *
785
+ * @param string $bucket Bucket name
786
+ * @return string | false
787
+ */
788
+ public static function getBucketLocation($bucket)
789
+ {
790
+ $rest = new iwpS3Request('GET', $bucket, '', self::$endpoint);
791
+ $rest->setParameter('location', null);
792
+ $rest = $rest->getResponse();
793
+ if ($rest->error === false && $rest->code !== 200)
794
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
795
+ if ($rest->error !== false)
796
+ {
797
+ self::__triggerError(sprintf("S3::getBucketLocation({$bucket}): [%s] %s",
798
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
799
+ return false;
800
+ }
801
+ return (isset($rest->body[0]) && (string)$rest->body[0] !== '') ? (string)$rest->body[0] : 'US';
802
+ }
803
+
804
+
805
+ /**
806
+ * Set object or bucket Access Control Policy
807
+ *
808
+ * @param string $bucket Bucket name
809
+ * @param string $uri Object URI
810
+ * @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy)
811
+ * @return boolean
812
+ */
813
+ public static function setAccessControlPolicy($bucket, $uri = '', $acp = array())
814
+ {
815
+ $dom = new DOMDocument;
816
+ $dom->formatOutput = true;
817
+ $accessControlPolicy = $dom->createElement('AccessControlPolicy');
818
+ $accessControlList = $dom->createElement('AccessControlList');
819
+
820
+ // It seems the owner has to be passed along too
821
+ $owner = $dom->createElement('Owner');
822
+ $owner->appendChild($dom->createElement('ID', $acp['owner']['id']));
823
+ $owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name']));
824
+ $accessControlPolicy->appendChild($owner);
825
+
826
+ foreach ($acp['acl'] as $g)
827
+ {
828
+ $grant = $dom->createElement('Grant');
829
+ $grantee = $dom->createElement('Grantee');
830
+ $grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
831
+ if (isset($g['id']))
832
+ { // CanonicalUser (DisplayName is omitted)
833
+ $grantee->setAttribute('xsi:type', 'CanonicalUser');
834
+ $grantee->appendChild($dom->createElement('ID', $g['id']));
835
+ }
836
+ elseif (isset($g['email']))
837
+ { // AmazonCustomerByEmail
838
+ $grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail');
839
+ $grantee->appendChild($dom->createElement('EmailAddress', $g['email']));
840
+ }
841
+ elseif ($g['type'] == 'Group')
842
+ { // Group
843
+ $grantee->setAttribute('xsi:type', 'Group');
844
+ $grantee->appendChild($dom->createElement('URI', $g['uri']));
845
+ }
846
+ $grant->appendChild($grantee);
847
+ $grant->appendChild($dom->createElement('Permission', $g['permission']));
848
+ $accessControlList->appendChild($grant);
849
+ }
850
+
851
+ $accessControlPolicy->appendChild($accessControlList);
852
+ $dom->appendChild($accessControlPolicy);
853
+
854
+ $rest = new iwpS3Request('PUT', $bucket, $uri, self::$endpoint);
855
+ $rest->setParameter('acl', null);
856
+ $rest->data = $dom->saveXML();
857
+ $rest->size = strlen($rest->data);
858
+ $rest->setHeader('Content-Type', 'application/xml');
859
+ $rest = $rest->getResponse();
860
+ if ($rest->error === false && $rest->code !== 200)
861
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
862
+ if ($rest->error !== false)
863
+ {
864
+ self::__triggerError(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
865
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
866
+ return false;
867
+ }
868
+ return true;
869
+ }
870
+
871
+
872
+ /**
873
+ * Get object or bucket Access Control Policy
874
+ *
875
+ * @param string $bucket Bucket name
876
+ * @param string $uri Object URI
877
+ * @return mixed | false
878
+ */
879
+ public static function getAccessControlPolicy($bucket, $uri = '')
880
+ {
881
+ $rest = new iwpS3Request('GET', $bucket, $uri, self::$endpoint);
882
+ $rest->setParameter('acl', null);
883
+ $rest = $rest->getResponse();
884
+ if ($rest->error === false && $rest->code !== 200)
885
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
886
+ if ($rest->error !== false)
887
+ {
888
+ self::__triggerError(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
889
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
890
+ return false;
891
+ }
892
+
893
+ $acp = array();
894
+ if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
895
+ $acp['owner'] = array(
896
+ 'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName
897
+ );
898
+
899
+ if (isset($rest->body->AccessControlList))
900
+ {
901
+ $acp['acl'] = array();
902
+ foreach ($rest->body->AccessControlList->Grant as $grant)
903
+ {
904
+ foreach ($grant->Grantee as $grantee)
905
+ {
906
+ if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser
907
+ $acp['acl'][] = array(
908
+ 'type' => 'CanonicalUser',
909
+ 'id' => (string)$grantee->ID,
910
+ 'name' => (string)$grantee->DisplayName,
911
+ 'permission' => (string)$grant->Permission
912
+ );
913
+ elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail
914
+ $acp['acl'][] = array(
915
+ 'type' => 'AmazonCustomerByEmail',
916
+ 'email' => (string)$grantee->EmailAddress,
917
+ 'permission' => (string)$grant->Permission
918
+ );
919
+ elseif (isset($grantee->URI)) // Group
920
+ $acp['acl'][] = array(
921
+ 'type' => 'Group',
922
+ 'uri' => (string)$grantee->URI,
923
+ 'permission' => (string)$grant->Permission
924
+ );
925
+ else continue;
926
+ }
927
+ }
928
+ }
929
+ return $acp;
930
+ }
931
+
932
+
933
+ /**
934
+ * Delete an object
935
+ *
936
+ * @param string $bucket Bucket name
937
+ * @param string $uri Object URI
938
+ * @return boolean
939
+ */
940
+ public static function deleteObject($bucket, $uri)
941
+ {
942
+ $rest = new iwpS3Request('DELETE', $bucket, $uri, self::$endpoint);
943
+ $rest = $rest->getResponse();
944
+ if ($rest->error === false && $rest->code !== 204)
945
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
946
+ if ($rest->error !== false)
947
+ {
948
+ self::__triggerError(sprintf("S3::deleteObject(): [%s] %s",
949
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
950
+ return false;
951
+ }
952
+ return true;
953
+ }
954
+
955
+
956
+ /**
957
+ * Get a query string authenticated URL
958
+ *
959
+ * @param string $bucket Bucket name
960
+ * @param string $uri Object URI
961
+ * @param integer $lifetime Lifetime in seconds
962
+ * @param boolean $hostBucket Use the bucket name as the hostname
963
+ * @param boolean $https Use HTTPS ($hostBucket should be false for SSL verification)
964
+ * @return string
965
+ */
966
+ public static function getAuthenticatedURL($bucket, $uri, $lifetime, $hostBucket = false, $https = false)
967
+ {
968
+ $expires = time() + $lifetime;
969
+ $uri = str_replace('%2F', '/', rawurlencode($uri)); // URI should be encoded (thanks Sean O'Dea)
970
+ return sprintf(($https ? 'https' : 'http').'://%s/%s?AWSAccessKeyId=%s&Expires=%u&Signature=%s',
971
+ // $hostBucket ? $bucket : $bucket.'.s3.amazonaws.com', $uri, self::$__accessKey, $expires,
972
+ $hostBucket ? $bucket : 's3.amazonaws.com/'.$bucket, $uri, self::$__accessKey, $expires,
973
+ urlencode(self::__getHash("GET\n\n\n{$expires}\n/{$bucket}/{$uri}")));
974
+ }
975
+
976
+
977
+ /**
978
+ * Get a CloudFront signed policy URL
979
+ *
980
+ * @param array $policy Policy
981
+ * @return string
982
+ */
983
+ public static function getSignedPolicyURL($policy)
984
+ {
985
+ $data = json_encode($policy);
986
+ $signature = '';
987
+ if (!openssl_sign($data, $signature, self::$__signingKeyResource)) return false;
988
+
989
+ $encoded = str_replace(array('+', '='), array('-', '_', '~'), base64_encode($data));
990
+ $signature = str_replace(array('+', '='), array('-', '_', '~'), base64_encode($signature));
991
+
992
+ $url = $policy['Statement'][0]['Resource'] . '?';
993
+ foreach (array('Policy' => $encoded, 'Signature' => $signature, 'Key-Pair-Id' => self::$__signingKeyPairId) as $k => $v)
994
+ $url .= $k.'='.str_replace('%2F', '/', rawurlencode($v)).'&';
995
+ return substr($url, 0, -1);
996
+ }
997
+
998
+
999
+ /**
1000
+ * Get a CloudFront canned policy URL
1001
+ *
1002
+ * @param string $string URL to sign
1003
+ * @param integer $lifetime URL lifetime
1004
+ * @return string
1005
+ */
1006
+ public static function getSignedCannedURL($url, $lifetime)
1007
+ {
1008
+ return self::getSignedPolicyURL(array(
1009
+ 'Statement' => array(
1010
+ array('Resource' => $url, 'Condition' => array(
1011
+ 'DateLessThan' => array('AWS:EpochTime' => time() + $lifetime)
1012
+ ))
1013
+ )
1014
+ ));
1015
+ }
1016
+
1017
+
1018
+ /**
1019
+ * Get upload POST parameters for form uploads
1020
+ *
1021
+ * @param string $bucket Bucket name
1022
+ * @param string $uriPrefix Object URI prefix
1023
+ * @param constant $acl ACL constant
1024
+ * @param integer $lifetime Lifetime in seconds
1025
+ * @param integer $maxFileSize Maximum filesize in bytes (default 5MB)
1026
+ * @param string $successRedirect Redirect URL or 200 / 201 status code
1027
+ * @param array $amzHeaders Array of x-amz-meta-* headers
1028
+ * @param array $headers Array of request headers or content type as a string
1029
+ * @param boolean $flashVars Includes additional "Filename" variable posted by Flash
1030
+ * @return object
1031
+ */
1032
+ public static function getHttpUploadPostParams($bucket, $uriPrefix = '', $acl = self::ACL_PRIVATE, $lifetime = 3600,
1033
+ $maxFileSize = 5242880, $successRedirect = "201", $amzHeaders = array(), $headers = array(), $flashVars = false)
1034
+ {
1035
+ // Create policy object
1036
+ $policy = new stdClass;
1037
+ $policy->expiration = gmdate('Y-m-d\TH:i:s\Z', (time() + $lifetime));
1038
+ $policy->conditions = array();
1039
+ $obj = new stdClass; $obj->bucket = $bucket; array_push($policy->conditions, $obj);
1040
+ $obj = new stdClass; $obj->acl = $acl; array_push($policy->conditions, $obj);
1041
+
1042
+ $obj = new stdClass; // 200 for non-redirect uploads
1043
+ if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
1044
+ $obj->success_action_status = (string)$successRedirect;
1045
+ else // URL
1046
+ $obj->success_action_redirect = $successRedirect;
1047
+ array_push($policy->conditions, $obj);
1048
+
1049
+ if ($acl !== self::ACL_PUBLIC_READ)
1050
+ array_push($policy->conditions, array('eq', '$acl', $acl));
1051
+
1052
+ array_push($policy->conditions, array('starts-with', '$key', $uriPrefix));
1053
+ if ($flashVars) array_push($policy->conditions, array('starts-with', '$Filename', ''));
1054
+ foreach (array_keys($headers) as $headerKey)
1055
+ array_push($policy->conditions, array('starts-with', '$'.$headerKey, ''));
1056
+ foreach ($amzHeaders as $headerKey => $headerVal)
1057
+ {
1058
+ $obj = new stdClass;
1059
+ $obj->{$headerKey} = (string)$headerVal;
1060
+ array_push($policy->conditions, $obj);
1061
+ }
1062
+ array_push($policy->conditions, array('content-length-range', 0, $maxFileSize));
1063
+ $policy = base64_encode(str_replace('\/', '/', json_encode($policy)));
1064
+
1065
+ // Create parameters
1066
+ $params = new stdClass;
1067
+ $params->AWSAccessKeyId = self::$__accessKey;
1068
+ $params->key = $uriPrefix.'${filename}';
1069
+ $params->acl = $acl;
1070
+ $params->policy = $policy; unset($policy);
1071
+ $params->signature = self::__getHash($params->policy);
1072
+ if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
1073
+ $params->success_action_status = (string)$successRedirect;
1074
+ else
1075
+ $params->success_action_redirect = $successRedirect;
1076
+ foreach ($headers as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
1077
+ foreach ($amzHeaders as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
1078
+ return $params;
1079
+ }
1080
+
1081
+
1082
+ /**
1083
+ * Create a CloudFront distribution
1084
+ *
1085
+ * @param string $bucket Bucket name
1086
+ * @param boolean $enabled Enabled (true/false)
1087
+ * @param array $cnames Array containing CNAME aliases
1088
+ * @param string $comment Use the bucket name as the hostname
1089
+ * @param string $defaultRootObject Default root object
1090
+ * @param string $originAccessIdentity Origin access identity
1091
+ * @param array $trustedSigners Array of trusted signers
1092
+ * @return array | false
1093
+ */
1094
+ public static function createDistribution($bucket, $enabled = true, $cnames = array(), $comment = null, $defaultRootObject = null, $originAccessIdentity = null, $trustedSigners = array())
1095
+ {
1096
+ if (!extension_loaded('openssl'))
1097
+ {
1098
+ self::__triggerError(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", [], '$comment'): %s",
1099
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1100
+ return false;
1101
+ }
1102
+ $useSSL = self::$useSSL;
1103
+
1104
+ self::$useSSL = true; // CloudFront requires SSL
1105
+ $rest = new iwpS3Request('POST', '', '2010-11-01/distribution', 'cloudfront.amazonaws.com');
1106
+ $rest->data = self::__getCloudFrontDistributionConfigXML(
1107
+ $bucket.'.s3.amazonaws.com',
1108
+ $enabled,
1109
+ (string)$comment,
1110
+ (string)microtime(true),
1111
+ $cnames,
1112
+ $defaultRootObject,
1113
+ $originAccessIdentity,
1114
+ $trustedSigners
1115
+ );
1116
+
1117
+ $rest->size = strlen($rest->data);
1118
+ $rest->setHeader('Content-Type', 'application/xml');
1119
+ $rest = self::__getCloudFrontResponse($rest);
1120
+
1121
+ self::$useSSL = $useSSL;
1122
+
1123
+ if ($rest->error === false && $rest->code !== 201)
1124
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1125
+ if ($rest->error !== false)
1126
+ {
1127
+ self::__triggerError(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", [], '$comment'): [%s] %s",
1128
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
1129
+ return false;
1130
+ } elseif ($rest->body instanceof SimpleXMLElement)
1131
+ return self::__parseCloudFrontDistributionConfig($rest->body);
1132
+ return false;
1133
+ }
1134
+
1135
+
1136
+ /**
1137
+ * Get CloudFront distribution info
1138
+ *
1139
+ * @param string $distributionId Distribution ID from listDistributions()
1140
+ * @return array | false
1141
+ */
1142
+ public static function getDistribution($distributionId)
1143
+ {
1144
+ if (!extension_loaded('openssl'))
1145
+ {
1146
+ self::__triggerError(sprintf("S3::getDistribution($distributionId): %s",
1147
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1148
+ return false;
1149
+ }
1150
+ $useSSL = self::$useSSL;
1151
+
1152
+ self::$useSSL = true; // CloudFront requires SSL
1153
+ $rest = new iwpS3Request('GET', '', '2010-11-01/distribution/'.$distributionId, 'cloudfront.amazonaws.com');
1154
+ $rest = self::__getCloudFrontResponse($rest);
1155
+
1156
+ self::$useSSL = $useSSL;
1157
+
1158
+ if ($rest->error === false && $rest->code !== 200)
1159
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1160
+ if ($rest->error !== false)
1161
+ {
1162
+ self::__triggerError(sprintf("S3::getDistribution($distributionId): [%s] %s",
1163
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
1164
+ return false;
1165
+ }
1166
+ elseif ($rest->body instanceof SimpleXMLElement)
1167
+ {
1168
+ $dist = self::__parseCloudFrontDistributionConfig($rest->body);
1169
+ $dist['hash'] = $rest->headers['hash'];
1170
+ $dist['id'] = $distributionId;
1171
+ return $dist;
1172
+ }
1173
+ return false;
1174
+ }
1175
+
1176
+
1177
+ /**
1178
+ * Update a CloudFront distribution
1179
+ *
1180
+ * @param array $dist Distribution array info identical to output of getDistribution()
1181
+ * @return array | false
1182
+ */
1183
+ public static function updateDistribution($dist)
1184
+ {
1185
+ if (!extension_loaded('openssl'))
1186
+ {
1187
+ self::__triggerError(sprintf("S3::updateDistribution({$dist['id']}): %s",
1188
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1189
+ return false;
1190
+ }
1191
+
1192
+ $useSSL = self::$useSSL;
1193
+
1194
+ self::$useSSL = true; // CloudFront requires SSL
1195
+ $rest = new iwpS3Request('PUT', '', '2010-11-01/distribution/'.$dist['id'].'/config', 'cloudfront.amazonaws.com');
1196
+ $rest->data = self::__getCloudFrontDistributionConfigXML(
1197
+ $dist['origin'],
1198
+ $dist['enabled'],
1199
+ $dist['comment'],
1200
+ $dist['callerReference'],
1201
+ $dist['cnames'],
1202
+ $dist['defaultRootObject'],
1203
+ $dist['originAccessIdentity'],
1204
+ $dist['trustedSigners']
1205
+ );
1206
+
1207
+ $rest->size = strlen($rest->data);
1208
+ $rest->setHeader('If-Match', $dist['hash']);
1209
+ $rest = self::__getCloudFrontResponse($rest);
1210
+
1211
+ self::$useSSL = $useSSL;
1212
+
1213
+ if ($rest->error === false && $rest->code !== 200)
1214
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1215
+ if ($rest->error !== false)
1216
+ {
1217
+ self::__triggerError(sprintf("S3::updateDistribution({$dist['id']}): [%s] %s",
1218
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
1219
+ return false;
1220
+ } else {
1221
+ $dist = self::__parseCloudFrontDistributionConfig($rest->body);
1222
+ $dist['hash'] = $rest->headers['hash'];
1223
+ return $dist;
1224
+ }
1225
+ return false;
1226
+ }
1227
+
1228
+
1229
+ /**
1230
+ * Delete a CloudFront distribution
1231
+ *
1232
+ * @param array $dist Distribution array info identical to output of getDistribution()
1233
+ * @return boolean
1234
+ */
1235
+ public static function deleteDistribution($dist)
1236
+ {
1237
+ if (!extension_loaded('openssl'))
1238
+ {
1239
+ self::__triggerError(sprintf("S3::deleteDistribution({$dist['id']}): %s",
1240
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1241
+ return false;
1242
+ }
1243
+
1244
+ $useSSL = self::$useSSL;
1245
+
1246
+ self::$useSSL = true; // CloudFront requires SSL
1247
+ $rest = new iwpS3Request('DELETE', '', '2008-06-30/distribution/'.$dist['id'], 'cloudfront.amazonaws.com');
1248
+ $rest->setHeader('If-Match', $dist['hash']);
1249
+ $rest = self::__getCloudFrontResponse($rest);
1250
+
1251
+ self::$useSSL = $useSSL;
1252
+
1253
+ if ($rest->error === false && $rest->code !== 204)
1254
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1255
+ if ($rest->error !== false)
1256
+ {
1257
+ self::__triggerError(sprintf("S3::deleteDistribution({$dist['id']}): [%s] %s",
1258
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
1259
+ return false;
1260
+ }
1261
+ return true;
1262
+ }
1263
+
1264
+
1265
+ /**
1266
+ * Get a list of CloudFront distributions
1267
+ *
1268
+ * @return array
1269
+ */
1270
+ public static function listDistributions()
1271
+ {
1272
+ if (!extension_loaded('openssl'))
1273
+ {
1274
+ self::__triggerError(sprintf("S3::listDistributions(): [%s] %s",
1275
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1276
+ return false;
1277
+ }
1278
+
1279
+ $useSSL = self::$useSSL;
1280
+ self::$useSSL = true; // CloudFront requires SSL
1281
+ $rest = new iwpS3Request('GET', '', '2010-11-01/distribution', 'cloudfront.amazonaws.com');
1282
+ $rest = self::__getCloudFrontResponse($rest);
1283
+ self::$useSSL = $useSSL;
1284
+
1285
+ if ($rest->error === false && $rest->code !== 200)
1286
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1287
+ if ($rest->error !== false)
1288
+ {
1289
+ self::__triggerError(sprintf("S3::listDistributions(): [%s] %s",
1290
+ $rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
1291
+ return false;
1292
+ }
1293
+ elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary))
1294
+ {
1295
+ $list = array();
1296
+ if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated))
1297
+ {
1298
+ //$info['marker'] = (string)$rest->body->Marker;
1299
+ //$info['maxItems'] = (int)$rest->body->MaxItems;
1300
+ //$info['isTruncated'] = (string)$rest->body->IsTruncated == 'true' ? true : false;
1301
+ }
1302
+ foreach ($rest->body->DistributionSummary as $summary)
1303
+ $list[(string)$summary->Id] = self::__parseCloudFrontDistributionConfig($summary);
1304
+
1305
+ return $list;
1306
+ }
1307
+ return array();
1308
+ }
1309
+
1310
+ /**
1311
+ * List CloudFront Origin Access Identities
1312
+ *
1313
+ * @return array
1314
+ */
1315
+ public static function listOriginAccessIdentities()
1316
+ {
1317
+ if (!extension_loaded('openssl'))
1318
+ {
1319
+ self::__triggerError(sprintf("S3::listOriginAccessIdentities(): [%s] %s",
1320
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1321
+ return false;
1322
+ }
1323
+
1324
+ self::$useSSL = true; // CloudFront requires SSL
1325
+ $rest = new iwpS3Request('GET', '', '2010-11-01/origin-access-identity/cloudfront', 'cloudfront.amazonaws.com');
1326
+ $rest = self::__getCloudFrontResponse($rest);
1327
+ $useSSL = self::$useSSL;
1328
+
1329
+ if ($rest->error === false && $rest->code !== 200)
1330
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1331
+ if ($rest->error !== false)
1332
+ {
1333
+ trigger_error(sprintf("S3::listOriginAccessIdentities(): [%s] %s",
1334
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
1335
+ return false;
1336
+ }
1337
+
1338
+ if (isset($rest->body->CloudFrontOriginAccessIdentitySummary))
1339
+ {
1340
+ $identities = array();
1341
+ foreach ($rest->body->CloudFrontOriginAccessIdentitySummary as $identity)
1342
+ if (isset($identity->S3CanonicalUserId))
1343
+ $identities[(string)$identity->Id] = array('id' => (string)$identity->Id, 's3CanonicalUserId' => (string)$identity->S3CanonicalUserId);
1344
+ return $identities;
1345
+ }
1346
+ return false;
1347
+ }
1348
+
1349
+
1350
+ /**
1351
+ * Invalidate objects in a CloudFront distribution
1352
+ *
1353
+ * Thanks to Martin Lindkvist for S3::invalidateDistribution()
1354
+ *
1355
+ * @param string $distributionId Distribution ID from listDistributions()
1356
+ * @param array $paths Array of object paths to invalidate
1357
+ * @return boolean
1358
+ */
1359
+ public static function invalidateDistribution($distributionId, $paths)
1360
+ {
1361
+ if (!extension_loaded('openssl'))
1362
+ {
1363
+ self::__triggerError(sprintf("S3::invalidateDistribution(): [%s] %s",
1364
+ "CloudFront functionality requires SSL"), __FILE__, __LINE__);
1365
+ return false;
1366
+ }
1367
+
1368
+ $useSSL = self::$useSSL;
1369
+ self::$useSSL = true; // CloudFront requires SSL
1370
+ $rest = new iwpS3Request('POST', '', '2010-08-01/distribution/'.$distributionId.'/invalidation', 'cloudfront.amazonaws.com');
1371
+ $rest->data = self::__getCloudFrontInvalidationBatchXML($paths, (string)microtime(true));
1372
+ $rest->size = strlen($rest->data);
1373
+ $rest = self::__getCloudFrontResponse($rest);
1374
+ self::$useSSL = $useSSL;
1375
+
1376
+ if ($rest->error === false && $rest->code !== 201)
1377
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
1378
+ if ($rest->error !== false)
1379
+ {
1380
+ trigger_error(sprintf("S3::invalidate('{$distributionId}',{$paths}): [%s] %s",
1381
+ $rest->error['code'], $rest->error['message']), E_USER_WARNING);
1382
+ return false;
1383
+ }
1384
+ return true;
1385
+ }
1386
+
1387
+
1388
+ /**
1389
+ * Get a InvalidationBatch DOMDocument
1390
+ *
1391
+ * @internal Used to create XML in invalidateDistribution()
1392
+ * @param array $paths Paths to objects to invalidateDistribution
1393
+ * @return string
1394
+ */
1395
+ private static function __getCloudFrontInvalidationBatchXML($paths, $callerReference = '0') {
1396
+ $dom = new DOMDocument('1.0', 'UTF-8');
1397
+ $dom->formatOutput = true;
1398
+ $invalidationBatch = $dom->createElement('InvalidationBatch');
1399
+ foreach ($paths as $path)
1400
+ $invalidationBatch->appendChild($dom->createElement('Path', $path));
1401
+
1402
+ $invalidationBatch->appendChild($dom->createElement('CallerReference', $callerReference));
1403
+ $dom->appendChild($invalidationBatch);
1404
+ return $dom->saveXML();
1405
+ }
1406
+
1407
+
1408
+ /**
1409
+ * Get a DistributionConfig DOMDocument
1410
+ *
1411
+ * http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/index.html?PutConfig.html
1412
+ *
1413
+ * @internal Used to create XML in createDistribution() and updateDistribution()
1414
+ * @param string $bucket S3 Origin bucket
1415
+ * @param boolean $enabled Enabled (true/false)
1416
+ * @param string $comment Comment to append
1417
+ * @param string $callerReference Caller reference
1418
+ * @param array $cnames Array of CNAME aliases
1419
+ * @param string $defaultRootObject Default root object
1420
+ * @param string $originAccessIdentity Origin access identity
1421
+ * @param array $trustedSigners Array of trusted signers
1422
+ * @return string
1423
+ */
1424
+ private static function __getCloudFrontDistributionConfigXML($bucket, $enabled, $comment, $callerReference = '0', $cnames = array(), $defaultRootObject = null, $originAccessIdentity = null, $trustedSigners = array())
1425
+ {
1426
+ $dom = new DOMDocument('1.0', 'UTF-8');
1427
+ $dom->formatOutput = true;
1428
+ $distributionConfig = $dom->createElement('DistributionConfig');
1429
+ $distributionConfig->setAttribute('xmlns', 'http://cloudfront.amazonaws.com/doc/2010-11-01/');
1430
+
1431
+ $origin = $dom->createElement('S3Origin');
1432
+ $origin->appendChild($dom->createElement('DNSName', $bucket));
1433
+ if ($originAccessIdentity !== null) $origin->appendChild($dom->createElement('OriginAccessIdentity', $originAccessIdentity));
1434
+ $distributionConfig->appendChild($origin);
1435
+
1436
+ if ($defaultRootObject !== null) $distributionConfig->appendChild($dom->createElement('DefaultRootObject', $defaultRootObject));
1437
+
1438
+ $distributionConfig->appendChild($dom->createElement('CallerReference', $callerReference));
1439
+ foreach ($cnames as $cname)
1440
+ $distributionConfig->appendChild($dom->createElement('CNAME', $cname));
1441
+ if ($comment !== '') $distributionConfig->appendChild($dom->createElement('Comment', $comment));
1442
+ $distributionConfig->appendChild($dom->createElement('Enabled', $enabled ? 'true' : 'false'));
1443
+
1444
+ $trusted = $dom->createElement('TrustedSigners');
1445
+ foreach ($trustedSigners as $id => $type)
1446
+ $trusted->appendChild($id !== '' ? $dom->createElement($type, $id) : $dom->createElement($type));
1447
+ $distributionConfig->appendChild($trusted);
1448
+
1449
+ $dom->appendChild($distributionConfig);
1450
+ //var_dump($dom->saveXML());
1451
+ return $dom->saveXML();
1452
+ }
1453
+
1454
+
1455
+ /**
1456
+ * Parse a CloudFront distribution config
1457
+ *
1458
+ * See http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/index.html?GetDistribution.html
1459
+ *
1460
+ * @internal Used to parse the CloudFront DistributionConfig node to an array
1461
+ * @param object &$node DOMNode
1462
+ * @return array
1463
+ */
1464
+ private static function __parseCloudFrontDistributionConfig(&$node)
1465
+ {
1466
+ if (isset($node->DistributionConfig))
1467
+ return self::__parseCloudFrontDistributionConfig($node->DistributionConfig);
1468
+
1469
+ $dist = array();
1470
+ if (isset($node->Id, $node->Status, $node->LastModifiedTime, $node->DomainName))
1471
+ {
1472
+ $dist['id'] = (string)$node->Id;
1473
+ $dist['status'] = (string)$node->Status;
1474
+ $dist['time'] = strtotime((string)$node->LastModifiedTime);
1475
+ $dist['domain'] = (string)$node->DomainName;
1476
+ }
1477
+
1478
+ if (isset($node->CallerReference))
1479
+ $dist['callerReference'] = (string)$node->CallerReference;
1480
+
1481
+ if (isset($node->Enabled))
1482
+ $dist['enabled'] = (string)$node->Enabled == 'true' ? true : false;
1483
+
1484
+ if (isset($node->S3Origin))
1485
+ {
1486
+ if (isset($node->S3Origin->DNSName))
1487
+ $dist['origin'] = (string)$node->S3Origin->DNSName;
1488
+
1489
+ $dist['originAccessIdentity'] = isset($node->S3Origin->OriginAccessIdentity) ?
1490
+ (string)$node->S3Origin->OriginAccessIdentity : null;
1491
+ }
1492
+
1493
+ $dist['defaultRootObject'] = isset($node->DefaultRootObject) ? (string)$node->DefaultRootObject : null;
1494
+
1495
+ $dist['cnames'] = array();
1496
+ if (isset($node->CNAME))
1497
+ foreach ($node->CNAME as $cname)
1498
+ $dist['cnames'][(string)$cname] = (string)$cname;
1499
+
1500
+ $dist['trustedSigners'] = array();
1501
+ if (isset($node->TrustedSigners))
1502
+ foreach ($node->TrustedSigners as $signer)
1503
+ {
1504
+ if (isset($signer->Self))
1505
+ $dist['trustedSigners'][''] = 'Self';
1506
+ elseif (isset($signer->KeyPairId))
1507
+ $dist['trustedSigners'][(string)$signer->KeyPairId] = 'KeyPairId';
1508
+ elseif (isset($signer->AwsAccountNumber))
1509
+ $dist['trustedSigners'][(string)$signer->AwsAccountNumber] = 'AwsAccountNumber';
1510
+ }
1511
+
1512
+ $dist['comment'] = isset($node->Comment) ? (string)$node->Comment : null;
1513
+ return $dist;
1514
+ }
1515
+
1516
+
1517
+ /**
1518
+ * Grab CloudFront response
1519
+ *
1520
+ * @internal Used to parse the CloudFront S3Request::getResponse() output
1521
+ * @param object &$rest S3Request instance
1522
+ * @return object
1523
+ */
1524
+ private static function __getCloudFrontResponse(&$rest)
1525
+ {
1526
+ $rest->getResponse();
1527
+ if ($rest->response->error === false && isset($rest->response->body) &&
1528
+ is_string($rest->response->body) && substr($rest->response->body, 0, 5) == '<?xml')
1529
+ {
1530
+ $rest->response->body = simplexml_load_string($rest->response->body);
1531
+ // Grab CloudFront errors
1532
+ if (isset($rest->response->body->Error, $rest->response->body->Error->Code,
1533
+ $rest->response->body->Error->Message))
1534
+ {
1535
+ $rest->response->error = array(
1536
+ 'code' => (string)$rest->response->body->Error->Code,
1537
+ 'message' => (string)$rest->response->body->Error->Message
1538
+ );
1539
+ unset($rest->response->body);
1540
+ }
1541
+ }
1542
+ return $rest->response;
1543
+ }
1544
+
1545
+
1546
+ /**
1547
+ * Get MIME type for file
1548
+ *
1549
+ * @internal Used to get mime types
1550
+ * @param string &$file File path
1551
+ * @return string
1552
+ */
1553
+ public static function __getMimeType(&$file)
1554
+ {
1555
+ $type = false;
1556
+ // Fileinfo documentation says fileinfo_open() will use the
1557
+ // MAGIC env var for the magic file
1558
+ if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
1559
+ ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false)
1560
+ {
1561
+ if (($type = finfo_file($finfo, $file)) !== false)
1562
+ {
1563
+ // Remove the charset and grab the last content-type
1564
+ $type = explode(' ', str_replace('; charset=', ';charset=', $type));
1565
+ $type = array_pop($type);
1566
+ $type = explode(';', $type);
1567
+ $type = trim(array_shift($type));
1568
+ }
1569
+ finfo_close($finfo);
1570
+
1571
+ // If anyone is still using mime_content_type()
1572
+ } elseif (function_exists('mime_content_type'))
1573
+ $type = trim(mime_content_type($file));
1574
+
1575
+ if ($type !== false && strlen($type) > 0) return $type;
1576
+
1577
+ // Otherwise do it the old fashioned way
1578
+ static $exts = array(
1579
+ 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
1580
+ 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
1581
+ 'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
1582
+ 'zip' => 'application/zip', 'gz' => 'application/x-gzip',
1583
+ 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
1584
+ 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
1585
+ 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
1586
+ 'css' => 'text/css', 'js' => 'text/javascript',
1587
+ 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
1588
+ 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
1589
+ 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
1590
+ 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
1591
+ );
1592
+ $ext = strtolower(pathInfo($file, PATHINFO_EXTENSION));
1593
+ return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
1594
+ }
1595
+
1596
+
1597
+ /**
1598
+ * Generate the auth string: "AWS AccessKey:Signature"
1599
+ *
1600
+ * @internal Used by S3Request::getResponse()
1601
+ * @param string $string String to sign
1602
+ * @return string
1603
+ */
1604
+ public static function __getSignature($string)
1605
+ {
1606
+ return 'AWS '.self::$__accessKey.':'.self::__getHash($string);
1607
+ }
1608
+
1609
+
1610
+ /**
1611
+ * Creates a HMAC-SHA1 hash
1612
+ *
1613
+ * This uses the hash extension if loaded
1614
+ *
1615
+ * @internal Used by __getSignature()
1616
+ * @param string $string String to sign
1617
+ * @return string
1618
+ */
1619
+ private static function __getHash($string)
1620
+ {
1621
+ return base64_encode(extension_loaded('hash') ?
1622
+ hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
1623
+ (str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
1624
+ pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0x00)) ^
1625
+ (str_repeat(chr(0x36), 64))) . $string)))));
1626
+ }
1627
+
1628
+ }
1629
+
1630
+ final class iwpS3Request
1631
+ {
1632
+ private $endpoint, $verb, $bucket, $uri, $resource = '', $parameters = array(),
1633
+ $amzHeaders = array(), $headers = array(
1634
+ 'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => ''
1635
+ );
1636
+ public $fp = false, $size = 0, $data = false, $response;
1637
+
1638
+
1639
+ /**
1640
+ * Constructor
1641
+ *
1642
+ * @param string $verb Verb
1643
+ * @param string $bucket Bucket name
1644
+ * @param string $uri Object URI
1645
+ * @return mixed
1646
+ */
1647
+ function __construct($verb, $bucket = '', $uri = '', $endpoint = 's3.amazonaws.com')
1648
+ {
1649
+ $this->endpoint = $endpoint;
1650
+ $this->verb = $verb;
1651
+ $this->bucket = $bucket;
1652
+ $this->uri = $uri !== '' ? '/'.str_replace('%2F', '/', rawurlencode($uri)) : '/';
1653
+
1654
+ //if ($this->bucket !== '')
1655
+ // $this->resource = '/'.$this->bucket.$this->uri;
1656
+ //else
1657
+ // $this->resource = $this->uri;
1658
+
1659
+ if ($this->bucket !== '')
1660
+ {
1661
+ if ($this->__dnsBucketName($this->bucket))
1662
+ {
1663
+ $this->headers['Host'] = $this->bucket.'.'.$this->endpoint;
1664
+ $this->resource = '/'.$this->bucket.$this->uri;
1665
+ }
1666
+ else
1667
+ {
1668
+ $this->headers['Host'] = $this->endpoint;
1669
+ $this->uri = $this->uri;
1670
+ if ($this->bucket !== '') $this->uri = '/'.$this->bucket.$this->uri;
1671
+ $this->bucket = '';
1672
+ $this->resource = $this->uri;
1673
+ }
1674
+ }
1675
+ else
1676
+ {
1677
+ $this->headers['Host'] = $this->endpoint;
1678
+ $this->resource = $this->uri;
1679
+ }
1680
+
1681
+
1682
+ $this->headers['Date'] = gmdate('D, d M Y H:i:s T');
1683
+ $this->response = new STDClass;
1684
+ $this->response->error = false;
1685
+ }
1686
+
1687
+
1688
+ /**
1689
+ * Set request parameter
1690
+ *
1691
+ * @param string $key Key
1692
+ * @param string $value Value
1693
+ * @return void
1694
+ */
1695
+ public function setParameter($key, $value)
1696
+ {
1697
+ $this->parameters[$key] = $value;
1698
+ }
1699
+
1700
+
1701
+ /**
1702
+ * Set request header
1703
+ *
1704
+ * @param string $key Key
1705
+ * @param string $value Value
1706
+ * @return void
1707
+ */
1708
+ public function setHeader($key, $value)
1709
+ {
1710
+ $this->headers[$key] = $value;
1711
+ }
1712
+
1713
+
1714
+ /**
1715
+ * Set x-amz-meta-* header
1716
+ *
1717
+ * @param string $key Key
1718
+ * @param string $value Value
1719
+ * @return void
1720
+ */
1721
+ public function setAmzHeader($key, $value)
1722
+ {
1723
+ $this->amzHeaders[$key] = $value;
1724
+ }
1725
+
1726
+
1727
+ /**
1728
+ * Get the S3 response
1729
+ *
1730
+ * @return object | false
1731
+ */
1732
+ public function getResponse()
1733
+ {
1734
+ $query = '';
1735
+ if (sizeof($this->parameters) > 0)
1736
+ {
1737
+ $query = substr($this->uri, -1) !== '?' ? '?' : '&';
1738
+ foreach ($this->parameters as $var => $value)
1739
+ if ($value == null || $value == '') $query .= $var.'&';
1740
+ // Parameters should be encoded (thanks Sean O'Dea)
1741
+ else $query .= $var.'='.rawurlencode($value).'&';
1742
+ $query = substr($query, 0, -1);
1743
+ $this->uri .= $query;
1744
+
1745
+ if (array_key_exists('acl', $this->parameters) ||
1746
+ array_key_exists('location', $this->parameters) ||
1747
+ array_key_exists('torrent', $this->parameters) ||
1748
+ array_key_exists('website', $this->parameters) ||
1749
+ array_key_exists('logging', $this->parameters))
1750
+ $this->resource .= $query;
1751
+ }
1752
+ $url = (S3::$useSSL ? 'https://' : 'http://') . ($this->headers['Host'] !== '' ? $this->headers['Host'] : $this->endpoint) . $this->uri;
1753
+
1754
+ //var_dump('bucket: ' . $this->bucket, 'uri: ' . $this->uri, 'resource: ' . $this->resource, 'url: ' . $url);
1755
+
1756
+ // Basic setup
1757
+ $curl = curl_init();
1758
+ curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php');
1759
+ curl_setopt($curl,CURLOPT_TIMEOUT,600);
1760
+ if (S3::$useSSL)
1761
+ {
1762
+ // SSL Validation can now be optional for those with broken OpenSSL installations
1763
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, S3::$useSSLValidation ? 1 : 0);
1764
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, S3::$useSSLValidation ? 1 : 0);
1765
+
1766
+ if (S3::$sslKey !== null) curl_setopt($curl, CURLOPT_SSLKEY, S3::$sslKey);
1767
+ if (S3::$sslCert !== null) curl_setopt($curl, CURLOPT_SSLCERT, S3::$sslCert);
1768
+ if (S3::$sslCACert !== null) curl_setopt($curl, CURLOPT_CAINFO, S3::$sslCACert);
1769
+ }
1770
+
1771
+ curl_setopt($curl, CURLOPT_URL, $url);
1772
+
1773
+ if (S3::$proxy != null && isset(S3::$proxy['host']))
1774
+ {
1775
+ curl_setopt($curl, CURLOPT_PROXY, S3::$proxy['host']);
1776
+ curl_setopt($curl, CURLOPT_PROXYTYPE, S3::$proxy['type']);
1777
+ if (isset(S3::$proxy['user'], S3::$proxy['pass']) && $proxy['user'] != null && $proxy['pass'] != null)
1778
+ curl_setopt($curl, CURLOPT_PROXYUSERPWD, sprintf('%s:%s', S3::$proxy['user'], S3::$proxy['pass']));
1779
+ }
1780
+
1781
+ // Headers
1782
+ $headers = array(); $amz = array();
1783
+ foreach ($this->amzHeaders as $header => $value)
1784
+ if (strlen($value) > 0) $headers[] = $header.': '.$value;
1785
+ foreach ($this->headers as $header => $value)
1786
+ if (strlen($value) > 0) $headers[] = $header.': '.$value;
1787
+
1788
+ // Collect AMZ headers for signature
1789
+ foreach ($this->amzHeaders as $header => $value)
1790
+ if (strlen($value) > 0) $amz[] = strtolower($header).':'.$value;
1791
+
1792
+ // AMZ headers must be sorted
1793
+ if (sizeof($amz) > 0)
1794
+ {
1795
+ sort($amz);
1796
+ $amz = "\n".implode("\n", $amz);
1797
+ } else $amz = '';
1798
+
1799
+ if (S3::hasAuth())
1800
+ {
1801
+ // Authorization string (CloudFront stringToSign should only contain a date)
1802
+ if ($this->headers['Host'] == 'cloudfront.amazonaws.com')
1803
+ $headers[] = 'Authorization: ' . S3::__getSignature($this->headers['Date']);
1804
+ else
1805
+ {
1806
+ $headers[] = 'Authorization: ' . S3::__getSignature(
1807
+ $this->verb."\n".
1808
+ $this->headers['Content-MD5']."\n".
1809
+ $this->headers['Content-Type']."\n".
1810
+ $this->headers['Date'].$amz."\n".
1811
+ $this->resource
1812
+ );
1813
+ }
1814
+ }
1815
+
1816
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
1817
+ curl_setopt($curl, CURLOPT_HEADER, false);
1818
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
1819
+ curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
1820
+ curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback'));
1821
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
1822
+
1823
+ // Request types
1824
+ switch ($this->verb)
1825
+ {
1826
+ case 'GET': break;
1827
+ case 'PUT': case 'POST': // POST only used for CloudFront
1828
+ if ($this->fp !== false)
1829
+ {
1830
+ curl_setopt($curl, CURLOPT_PUT, true);
1831
+ curl_setopt($curl, CURLOPT_INFILE, $this->fp);
1832
+ if ($this->size >= 0)
1833
+ curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
1834
+ }
1835
+ elseif ($this->data !== false)
1836
+ {
1837
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
1838
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
1839
+ }
1840
+ else
1841
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
1842
+ break;
1843
+ case 'HEAD':
1844
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
1845
+ curl_setopt($curl, CURLOPT_NOBODY, true);
1846
+ break;
1847
+ case 'DELETE':
1848
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
1849
+ break;
1850
+ default: break;
1851
+ }
1852
+
1853
+ // Execute, grab errors
1854
+ if (curl_exec($curl))
1855
+ $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
1856
+ else
1857
+ $this->response->error = array(
1858
+ 'code' => curl_errno($curl),
1859
+ 'message' => curl_error($curl),
1860
+ 'resource' => $this->resource
1861
+ );
1862
+
1863
+ @curl_close($curl);
1864
+
1865
+ // Parse body into XML
1866
+ if ($this->response->error === false && isset($this->response->headers['type']) &&
1867
+ $this->response->headers['type'] == 'application/xml' && isset($this->response->body))
1868
+ {
1869
+ $this->response->body = simplexml_load_string($this->response->body);
1870
+
1871
+ // Grab S3 errors
1872
+ if (!in_array($this->response->code, array(200, 204, 206)) &&
1873
+ isset($this->response->body->Code, $this->response->body->Message))
1874
+ {
1875
+ $this->response->error = array(
1876
+ 'code' => (string)$this->response->body->Code,
1877
+ 'message' => (string)$this->response->body->Message
1878
+ );
1879
+ if (isset($this->response->body->Resource))
1880
+ $this->response->error['resource'] = (string)$this->response->body->Resource;
1881
+ unset($this->response->body);
1882
+ }
1883
+ }
1884
+
1885
+ // Clean up file resources
1886
+ if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp);
1887
+
1888
+ return $this->response;
1889
+ }
1890
+
1891
+
1892
+ /**
1893
+ * CURL write callback
1894
+ *
1895
+ * @param resource &$curl CURL resource
1896
+ * @param string &$data Data
1897
+ * @return integer
1898
+ */
1899
+ private function __responseWriteCallback(&$curl, &$data)
1900
+ {
1901
+ if (in_array($this->response->code, array(200, 206)) && $this->fp !== false)
1902
+ return fwrite($this->fp, $data);
1903
+ else
1904
+ $this->response->body .= $data;
1905
+ return strlen($data);
1906
+ }
1907
+
1908
+
1909
+ /**
1910
+ * Check DNS conformity
1911
+ *
1912
+ * @param string $bucket Bucket name
1913
+ * @return boolean
1914
+ */
1915
+ private function __dnsBucketName($bucket)
1916
+ {
1917
+ if (strlen($bucket) > 63 || !preg_match("/[^a-z0-9\.-]/", $bucket)) return false;
1918
+ if (strstr($bucket, '-.') !== false) return false;
1919
+ if (strstr($bucket, '..') !== false) return false;
1920
+ if (!preg_match("/^[0-9a-z]/", $bucket)) return false;
1921
+ if (!preg_match("/[0-9a-z]$/", $bucket)) return false;
1922
+ return true;
1923
+ }
1924
+
1925
+
1926
+ /**
1927
+ * CURL header callback
1928
+ *
1929
+ * @param resource &$curl CURL resource
1930
+ * @param string &$data Data
1931
+ * @return integer
1932
+ */
1933
+ private function __responseHeaderCallback(&$curl, &$data)
1934
+ {
1935
+ if (($strlen = strlen($data)) <= 2) return $strlen;
1936
+ if (substr($data, 0, 4) == 'HTTP')
1937
+ $this->response->code = (int)substr($data, 9, 3);
1938
+ else
1939
+ {
1940
+ $data = trim($data);
1941
+ if (strpos($data, ': ') === false) return $strlen;
1942
+ list($header, $value) = explode(': ', $data, 2);
1943
+ if ($header == 'Last-Modified')
1944
+ $this->response->headers['time'] = strtotime($value);
1945
+ elseif ($header == 'Content-Length')
1946
+ $this->response->headers['size'] = (int)$value;
1947
+ elseif ($header == 'Content-Type')
1948
+ $this->response->headers['type'] = $value;
1949
+ elseif ($header == 'ETag')
1950
+ $this->response->headers['hash'] = $value{0} == '"' ? substr($value, 1, -1) : $value;
1951
+ elseif (preg_match('/^x-amz-meta-.*$/', $header))
1952
+ $this->response->headers[$header] = is_numeric($value) ? (int)$value : $value;
1953
+ }
1954
+ return $strlen;
1955
+ }
1956
+
1957
+ }
1958
+
1959
+ class mwpS3Exception extends Exception {
1960
+ function __construct($message, $file, $line, $code = 0)
1961
+ {
1962
+ parent::__construct($message, $code);
1963
+ $this->file = $file;
1964
+ $this->line = $line;
1965
+ }
1966
+ }
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: infinitewp
3
  Tags: admin, administration, amazon, api, authentication, automatic, dashboard, dropbox, events, integration, manage, multisite, multiple, notification, performance, s3, security, seo, stats, tracking, infinitewp, updates, backup, restore, iwp, infinite
4
  Requires at least: 3.0
5
- Tested up to: 3.3.2
6
  Stable tag: trunk
7
 
8
  Install this plugin on unlimited sites and manage them all from a central dashboard.
@@ -22,11 +22,14 @@ Main features:
22
  * Bulk Install plugins & themes in multiple sites at once
23
  * and more..
24
 
 
 
25
  Check out the [InfiniteWP Overview Video](http://www.youtube.com/watch?v=IOu7LdyPOSs) below.
26
 
27
  http://www.youtube.com/watch?v=IOu7LdyPOSs
28
 
29
- Check out [InfiniteWP.com](http://infinitewp.com/ "Manage Multiple WordPress").
 
30
 
31
  == Installation ==
32
 
@@ -45,6 +48,11 @@ Check out [InfiniteWP.com](http://infinitewp.com/ "Manage Multiple WordPress").
45
 
46
  == Changelog ==
47
 
 
 
 
 
 
48
  = 1.0.3 =
49
  * WordPress Multisite Backup issue fixed
50
  * Bugs fixed
2
  Contributors: infinitewp
3
  Tags: admin, administration, amazon, api, authentication, automatic, dashboard, dropbox, events, integration, manage, multisite, multiple, notification, performance, s3, security, seo, stats, tracking, infinitewp, updates, backup, restore, iwp, infinite
4
  Requires at least: 3.0
5
+ Tested up to: 3.4.1
6
  Stable tag: trunk
7
 
8
  Install this plugin on unlimited sites and manage them all from a central dashboard.
22
  * Bulk Install plugins & themes in multiple sites at once
23
  * and more..
24
 
25
+ Visit us at [InfiniteWP.com](http://infinitewp.com/ "Manage Multiple WordPress").
26
+
27
  Check out the [InfiniteWP Overview Video](http://www.youtube.com/watch?v=IOu7LdyPOSs) below.
28
 
29
  http://www.youtube.com/watch?v=IOu7LdyPOSs
30
 
31
+ Credits: [Vladimir Prelovac](http://prelovac.com/vladimir) for his worker plugin on which the client plugin is being developed.
32
+
33
 
34
  == Installation ==
35
 
48
 
49
  == Changelog ==
50
 
51
+ = 1.0.4 =
52
+ * Premium addons compatibility
53
+ * Clearing cache and sending WP data
54
+ * Bugs fixed
55
+
56
  = 1.0.3 =
57
  * WordPress Multisite Backup issue fixed
58
  * Bugs fixed
stats.class.php CHANGED
@@ -256,18 +256,22 @@ class IWP_MMB_Stats extends IWP_MMB_Core
256
  function get_updates($stats, $options = array())
257
  {
258
  $upgrades = false;
259
-
260
  if (isset($options['premium']) && $options['premium']) {
261
  $premium_updates = array();
262
- $upgrades = apply_filters('iwp_premium_update_notification', $premium_updates);
263
  if (!empty($upgrades)) {
 
 
 
 
264
  $stats['premium_updates'] = $upgrades;
265
  $upgrades = false;
266
  }
267
  }
268
  if (isset($options['themes']) && $options['themes']) {
269
  $this->get_installer_instance();
270
- $upgrades = $this->installer_instance->get_upgradable_themes();
271
  if (!empty($upgrades)) {
272
  $stats['upgradable_themes'] = $upgrades;
273
  $upgrades = false;
@@ -276,7 +280,7 @@ class IWP_MMB_Stats extends IWP_MMB_Core
276
 
277
  if (isset($options['plugins']) && $options['plugins']) {
278
  $this->get_installer_instance();
279
- $upgrades = $this->installer_instance->get_upgradable_plugins();
280
  if (!empty($upgrades)) {
281
  $stats['upgradable_plugins'] = $upgrades;
282
  $upgrades = false;
@@ -349,8 +353,16 @@ class IWP_MMB_Stats extends IWP_MMB_Core
349
 
350
  $stats = $this->iwp_mmb_parse_action_params('pre_init_stats', $params, $this);
351
  $num = extract($params);
352
-
353
- if ($refresh == 'transient') {
 
 
 
 
 
 
 
 
354
  $current = $this->iwp_mmb_get_transient('update_core');
355
  if (isset($current->last_checked) || get_option('iwp_client_forcerefresh')) {
356
  update_option('iwp_client_forcerefresh', false);
@@ -400,7 +412,7 @@ class IWP_MMB_Stats extends IWP_MMB_Core
400
  $update_check = array();
401
  $num = extract($params);
402
  if ($refresh == 'transient') {
403
- $update_check = apply_filters('iwp_premium_update_check', $update_check);
404
  if (!empty($update_check)) {
405
  foreach ($update_check as $update) {
406
  if (is_array($update['callback'])) {
256
  function get_updates($stats, $options = array())
257
  {
258
  $upgrades = false;
259
+ $premium = array();
260
  if (isset($options['premium']) && $options['premium']) {
261
  $premium_updates = array();
262
+ $upgrades = apply_filters('mwp_premium_update_notification', $premium_updates);
263
  if (!empty($upgrades)) {
264
+ foreach( $upgrades as $data ){
265
+ if( isset($data['Name']) )
266
+ $premium[] = $data['Name'];
267
+ }
268
  $stats['premium_updates'] = $upgrades;
269
  $upgrades = false;
270
  }
271
  }
272
  if (isset($options['themes']) && $options['themes']) {
273
  $this->get_installer_instance();
274
+ $upgrades = $this->installer_instance->get_upgradable_themes( $premium );
275
  if (!empty($upgrades)) {
276
  $stats['upgradable_themes'] = $upgrades;
277
  $upgrades = false;
280
 
281
  if (isset($options['plugins']) && $options['plugins']) {
282
  $this->get_installer_instance();
283
+ $upgrades = $this->installer_instance->get_upgradable_plugins( $premium );
284
  if (!empty($upgrades)) {
285
  $stats['upgradable_plugins'] = $upgrades;
286
  $upgrades = false;
353
 
354
  $stats = $this->iwp_mmb_parse_action_params('pre_init_stats', $params, $this);
355
  $num = extract($params);
356
+
357
+ if (function_exists( 'w3tc_pgcache_flush' ) || function_exists( 'wp_cache_clear_cache' ) || !empty($force_refresh)) {
358
+ $this->iwp_mmb_delete_transient('update_plugins');
359
+ @wp_update_plugins();
360
+ $this->iwp_mmb_delete_transient('update_themes');
361
+ @wp_update_themes();
362
+ $this->iwp_mmb_delete_transient('update_core');
363
+ @wp_version_check();
364
+ }
365
+ elseif ($refresh == 'transient') {
366
  $current = $this->iwp_mmb_get_transient('update_core');
367
  if (isset($current->last_checked) || get_option('iwp_client_forcerefresh')) {
368
  update_option('iwp_client_forcerefresh', false);
412
  $update_check = array();
413
  $num = extract($params);
414
  if ($refresh == 'transient') {
415
+ $update_check = apply_filters('mwp_premium_update_check', $update_check);
416
  if (!empty($update_check)) {
417
  foreach ($update_check as $update) {
418
  if (is_array($update['callback'])) {