Version Description
Download this release
Release Info
Developer | cocreation |
Plugin | BackWPup – WordPress Backup Plugin |
Version | 3.4.0 |
Comparing to | |
See all releases |
Code changes from version 3.3.7 to 3.4.0
- .htaccess +9 -9
- assets/css/backwpup.css +0 -1
- assets/templates/{php52notice → phpnotice}/de/notice.php +0 -0
- assets/templates/{php52notice → phpnotice}/de/question.php +0 -0
- assets/templates/{php52notice → phpnotice}/de_DE_formal/notice.php +0 -0
- assets/templates/{php52notice → phpnotice}/de_DE_formal/question.php +0 -0
- assets/templates/{php52notice → phpnotice}/en/notice.php +0 -0
- assets/templates/{php52notice → phpnotice}/en/question.php +0 -0
- assets/templates/{php52notice → phpnotice}/it/notice.php +0 -0
- assets/templates/{php52notice → phpnotice}/it/question.php +0 -0
- backwpup.php +542 -562
- inc/class-become-inpsyder-widget.php +1 -8
- inc/class-betatester-admin-notice.php +1 -8
- inc/class-cron.php +20 -10
- inc/class-destination-dropbox.php +711 -290
- inc/class-destination-email.php +25 -4
- inc/class-destination-folder.php +31 -19
- inc/class-destination-ftp.php +2 -1
- inc/class-destination-msazure.php +463 -462
- inc/class-destination-rsc.php +2 -1
- inc/class-destination-s3.php +3 -4
- inc/class-destination-sugarsync.php +2 -1
- inc/class-directory.php +21 -0
- inc/class-file.php +17 -26
- inc/class-job.php +2580 -2552
- inc/class-jobtype-file.php +147 -244
- inc/class-jobtype-wpexp.php +3 -3
- inc/class-mysqldump.php +3 -0
- inc/class-option.php +76 -2
- inc/class-page-about.php +2 -2
- inc/class-page-backups.php +0 -1
- inc/class-page-backwpup.php +26 -18
- inc/class-page-editjob.php +4 -5
- inc/class-page-logs.php +6 -6
- inc/class-page-settings.php +16 -1
- inc/class-path-fixer.php +33 -0
- inc/class-recursive-directory.php +24 -0
- languages/backwpup.pot +1033 -998
- readme.txt +17 -4
- vendor/PEAR/HTTP/Request2.php +1030 -1030
- vendor/PEAR/HTTP/Request2/Adapter.php +137 -137
- vendor/PEAR/HTTP/Request2/Adapter/Curl.php +567 -567
- vendor/PEAR/HTTP/Request2/Adapter/Mock.php +165 -165
- vendor/PEAR/HTTP/Request2/Adapter/Socket.php +1120 -1120
- vendor/PEAR/HTTP/Request2/CookieJar.php +493 -493
- vendor/PEAR/HTTP/Request2/Exception.php +159 -159
- vendor/PEAR/HTTP/Request2/MultipartBody.php +268 -268
- vendor/PEAR/HTTP/Request2/Observer/Log.php +191 -191
- vendor/PEAR/HTTP/Request2/Response.php +630 -630
- vendor/PEAR/HTTP/Request2/SOCKS5.php +134 -134
- vendor/PEAR/HTTP/Request2/SocketWrapper.php +297 -297
.htaccess
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
<Files *.php>
|
2 |
-
<IfModule mod_authz_core.c>
|
3 |
-
Require all denied
|
4 |
-
</IfModule>
|
5 |
-
<IfModule !mod_authz_core.c>
|
6 |
-
Order allow,deny
|
7 |
-
Deny from all
|
8 |
-
</IfModule>
|
9 |
-
</Files>
|
1 |
+
<Files *.php>
|
2 |
+
<IfModule mod_authz_core.c>
|
3 |
+
Require all denied
|
4 |
+
</IfModule>
|
5 |
+
<IfModule !mod_authz_core.c>
|
6 |
+
Order allow,deny
|
7 |
+
Deny from all
|
8 |
+
</IfModule>
|
9 |
+
</Files>
|
assets/css/backwpup.css
CHANGED
@@ -159,7 +159,6 @@
|
|
159 |
#backwpup-page .backwpup-warning {
|
160 |
border-left: 4px solid #ffba00; /* UI color .update-nag */
|
161 |
}
|
162 |
-
|
163 |
@media screen and (min-width: 720px) {
|
164 |
#backwpup-page .backwpup-floated-postbox {
|
165 |
float: left;
|
159 |
#backwpup-page .backwpup-warning {
|
160 |
border-left: 4px solid #ffba00; /* UI color .update-nag */
|
161 |
}
|
|
|
162 |
@media screen and (min-width: 720px) {
|
163 |
#backwpup-page .backwpup-floated-postbox {
|
164 |
float: left;
|
assets/templates/{php52notice → phpnotice}/de/notice.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/de/question.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/de_DE_formal/notice.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/de_DE_formal/question.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/en/notice.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/en/question.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/it/notice.php
RENAMED
File without changes
|
assets/templates/{php52notice → phpnotice}/it/question.php
RENAMED
File without changes
|
backwpup.php
CHANGED
@@ -1,563 +1,543 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Plugin Name: BackWPup
|
4 |
-
* Plugin URI: http://backwpup.com
|
5 |
-
* Description: WordPress Backup Plugin
|
6 |
-
* Author: Inpsyde GmbH
|
7 |
-
* Author URI: http://inpsyde.com
|
8 |
-
* Version: 3.
|
9 |
-
* Text Domain: backwpup
|
10 |
-
* Domain Path: /languages/
|
11 |
-
* Network: true
|
12 |
-
* License: GPLv3
|
13 |
-
* License URI: http://www.gnu.org/licenses/gpl-3.0
|
14 |
-
*/
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Copyright (C) 2012-2016 Inpsyde GmbH (email: info@inpsyde.com)
|
18 |
-
*
|
19 |
-
* This program is free software; you can redistribute it and/or
|
20 |
-
* modify it under the terms of the GNU General Public License
|
21 |
-
* as published by the Free Software Foundation; either version 2
|
22 |
-
* of the License, or (at your option) any later version.
|
23 |
-
*
|
24 |
-
* This program is distributed in the hope that it will be useful,
|
25 |
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26 |
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27 |
-
* GNU General Public License for more details.
|
28 |
-
*
|
29 |
-
* You should have received a copy of the GNU General Public License
|
30 |
-
* along with this program; if not, write to the Free Software
|
31 |
-
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
32 |
-
*/
|
33 |
-
|
34 |
-
if ( ! class_exists( 'BackWPup' ) ) {
|
35 |
-
|
36 |
-
// Don't activate on anything less than PHP 5.
|
37 |
-
if ( version_compare( PHP_VERSION, '5.
|
38 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
39 |
-
deactivate_plugins( __FILE__ );
|
40 |
-
die( 'BackWPup requires PHP version 5.
|
41 |
-
}
|
42 |
-
|
43 |
-
//Start Plugin
|
44 |
-
if ( function_exists( 'add_filter' ) ) {
|
45 |
-
add_action( 'plugins_loaded', array( 'BackWPup', 'get_instance' ), 11 );
|
46 |
-
}
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Main BackWPup Plugin Class
|
50 |
-
*/
|
51 |
-
final class BackWPup {
|
52 |
-
|
53 |
-
private static $instance = NULL;
|
54 |
-
private static $plugin_data = array();
|
55 |
-
private static $autoload = array();
|
56 |
-
private static $destinations = array();
|
57 |
-
private static $registered_destinations = array();
|
58 |
-
private static $job_types = array();
|
59 |
-
private static $wizards = array();
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Set needed filters and actions and load
|
63 |
-
*/
|
64 |
-
private function __construct() {
|
65 |
-
|
66 |
-
// Nothing else matters if we're not on the main site
|
67 |
-
if ( ! is_main_site() ) {
|
68 |
-
return;
|
69 |
-
}
|
70 |
-
//auto loader
|
71 |
-
spl_autoload_register( array( $this, 'autoloader' ) );
|
72 |
-
|
73 |
-
//start upgrade if needed
|
74 |
-
if ( get_site_option( 'backwpup_version' ) !== self::get_plugin_data( 'Version' ) || ! wp_next_scheduled( 'backwpup_check_cleanup' ) ) {
|
75 |
-
BackWPup_Install::activate();
|
76 |
-
}
|
77 |
-
//load pro features
|
78 |
-
if ( class_exists( 'BackWPup_Pro' ) ) {
|
79 |
-
BackWPup_Pro::get_instance();
|
80 |
-
}
|
81 |
-
//WP-Cron
|
82 |
-
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
83 |
-
if ( ! empty( $_GET[ 'backwpup_run' ] ) && class_exists( 'BackWPup_Job' ) ) {
|
84 |
-
//early disable caches
|
85 |
-
BackWPup_Job::disable_caches();
|
86 |
-
//add action for running jobs in wp-cron.php
|
87 |
-
add_action( 'wp_loaded', array( 'BackWPup_Cron', 'cron_active' ), PHP_INT_MAX );
|
88 |
-
} else {
|
89 |
-
//add cron actions
|
90 |
-
add_action( 'backwpup_cron', array( 'BackWPup_Cron', 'run' ) );
|
91 |
-
add_action( 'backwpup_check_cleanup', array( 'BackWPup_Cron', 'check_cleanup' ) );
|
92 |
-
}
|
93 |
-
//if in cron the rest is not needed
|
94 |
-
return;
|
95 |
-
}
|
96 |
-
//deactivation hook
|
97 |
-
register_deactivation_hook( __FILE__, array( 'BackWPup_Install', 'deactivate' ) );
|
98 |
-
//Admin bar
|
99 |
-
if ( get_site_option( 'backwpup_cfg_showadminbar' ) ) {
|
100 |
-
add_action( 'init', array( 'BackWPup_Adminbar', 'get_instance' ) );
|
101 |
-
}
|
102 |
-
//only in backend
|
103 |
-
if ( is_admin() && class_exists( 'BackWPup_Admin' ) ) {
|
104 |
-
BackWPup_Admin::get_instance();
|
105 |
-
}
|
106 |
-
//work with wp-cli
|
107 |
-
if ( defined( 'WP_CLI' ) && WP_CLI && method_exists( 'WP_CLI', 'add_command' ) ) {
|
108 |
-
WP_CLI::add_command( 'backwpup', 'BackWPup_WP_CLI' );
|
109 |
-
}
|
110 |
-
|
111 |
-
// Notices and messages in admin
|
112 |
-
if ( is_admin() && current_user_can( 'backwpup' ) ) {
|
113 |
-
|
114 |
-
|
115 |
-
$
|
116 |
-
add_action( '
|
117 |
-
add_action( 'backwpup_admin_messages', array( $
|
118 |
-
|
119 |
-
//
|
120 |
-
$
|
121 |
-
add_action( '
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
'backwpup'
|
148 |
-
)
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
if (
|
181 |
-
self::$
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
self::$plugin_data =
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
self::$plugin_data[ '
|
208 |
-
|
209 |
-
self::$plugin_data[ '
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
self::$plugin_data[ 'user-agent' ] = self::$plugin_data[ 'name' ].'/' . self::$plugin_data[ 'version' ] . '; WordPress/' . self::$plugin_data[ 'wp_version' ] . '; ' . home_url();
|
230 |
-
}
|
231 |
-
|
232 |
-
if ( ! empty( $name ) )
|
233 |
-
return self::$plugin_data[ $name ];
|
234 |
-
else
|
235 |
-
return self::$plugin_data;
|
236 |
-
}
|
237 |
-
|
238 |
-
|
239 |
-
/**
|
240 |
-
* include not existing classes automatically
|
241 |
-
*
|
242 |
-
* @param string $class Class to load from file
|
243 |
-
*/
|
244 |
-
private function autoloader( $class ) {
|
245 |
-
|
246 |
-
//BackWPup classes auto load
|
247 |
-
if ( strstr( strtolower( $class ), 'backwpup_' ) ) {
|
248 |
-
$dir = dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR;
|
249 |
$class_file_name = 'class-' . str_replace( array( 'backwpup_', '_' ), array( '', '-' ), strtolower( $class ) ) . '.php';
|
250 |
-
if ( strstr( strtolower( $class ), 'backwpup_pro' ) ) {
|
251 |
-
$dir .= 'pro' . DIRECTORY_SEPARATOR;
|
252 |
-
$class_file_name = str_replace( 'pro-','', $class_file_name );
|
253 |
-
}
|
254 |
-
if ( file_exists( $dir . $class_file_name ) )
|
255 |
-
require $dir . $class_file_name;
|
256 |
-
}
|
257 |
-
|
258 |
-
// namespaced PSR-0
|
259 |
-
if ( ! empty( self::$autoload ) ) {
|
260 |
-
$pos = strrpos( $class, '\\' );
|
261 |
-
if ( $pos !== FALSE ) {
|
262 |
-
$class_path = str_replace( '\\', DIRECTORY_SEPARATOR, substr( $class, 0, $pos ) ) . DIRECTORY_SEPARATOR . str_replace( '_', DIRECTORY_SEPARATOR, substr( $class, $pos + 1 ) ) . '.php';
|
263 |
-
foreach ( self::$autoload as $prefix => $dir ) {
|
264 |
-
if ( $class === strstr( $class, $prefix ) ) {
|
265 |
-
if ( file_exists( $dir . DIRECTORY_SEPARATOR . $class_path ) )
|
266 |
-
require $dir . DIRECTORY_SEPARATOR . $class_path;
|
267 |
-
}
|
268 |
-
}
|
269 |
-
} // Single class file
|
270 |
-
elseif ( ! empty( self::$autoload[ $class ] ) && is_file( self::$autoload[ $class ] ) ) {
|
271 |
-
require self::$autoload[ $class ];
|
272 |
-
}
|
273 |
-
}
|
274 |
-
|
275 |
-
//Google SDK Auto loading
|
276 |
-
$classPath = explode( '_', $class );
|
277 |
-
if ( $classPath[0] == 'Google' ) {
|
278 |
-
if ( count( $classPath ) > 3 ) {
|
279 |
-
$classPath = array_slice( $classPath, 0, 3 );
|
280 |
-
}
|
281 |
-
$filePath = self::get_plugin_data( 'plugindir' ) . '/vendor/' . implode( '/', $classPath ) . '.php';
|
282 |
-
if ( file_exists( $filePath ) ) {
|
283 |
-
require $filePath;
|
284 |
-
}
|
285 |
-
}
|
286 |
-
|
287 |
-
}
|
288 |
-
|
289 |
-
/**
|
290 |
-
* Load Plugin Translation
|
291 |
-
*
|
292 |
-
* @return bool Text domain loaded
|
293 |
-
*/
|
294 |
-
public static function load_text_domain() {
|
295 |
-
|
296 |
-
if ( is_textdomain_loaded( 'backwpup' ) ) {
|
297 |
-
return TRUE;
|
298 |
-
}
|
299 |
-
|
300 |
-
return load_plugin_textdomain( 'backwpup', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
|
301 |
-
}
|
302 |
-
|
303 |
-
/**
|
304 |
-
* Get a array of instances for Backup Destination's
|
305 |
-
*
|
306 |
-
* @param $key string Key of Destination where get class instance from
|
307 |
-
* @return array BackWPup_Destinations
|
308 |
-
*/
|
309 |
-
public static function get_destination( $key ) {
|
310 |
-
|
311 |
-
$key = strtoupper( $key );
|
312 |
-
|
313 |
-
if ( isset( self::$destinations[ $key ] ) && is_object( self::$destinations[ $key ] ) )
|
314 |
-
return self::$destinations[ $key ];
|
315 |
-
|
316 |
-
$reg_dests = self::get_registered_destinations();
|
317 |
-
if ( ! empty( $reg_dests[ $key ][ 'class' ] ) ) {
|
318 |
-
self::$destinations[ $key ] = new $reg_dests[ $key ][ 'class' ];
|
319 |
-
} else {
|
320 |
-
return NULL;
|
321 |
-
}
|
322 |
-
|
323 |
-
return self::$destinations[ $key ];
|
324 |
-
}
|
325 |
-
|
326 |
-
/**
|
327 |
-
* Get a array of registered Destination's for Backups
|
328 |
-
*
|
329 |
-
* @return array BackWPup_Destinations
|
330 |
-
*/
|
331 |
-
public static function get_registered_destinations() {
|
332 |
-
|
333 |
-
//only run it one time
|
334 |
-
if ( ! empty( self::$registered_destinations ) )
|
335 |
-
return self::$registered_destinations;
|
336 |
-
|
337 |
-
//add BackWPup Destinations
|
338 |
-
// to folder
|
339 |
-
self::$registered_destinations[ 'FOLDER' ] = array(
|
340 |
-
'class' => 'BackWPup_Destination_Folder',
|
341 |
-
'info' => array(
|
342 |
-
'ID' => 'FOLDER',
|
343 |
-
'name' => __( 'Folder', 'backwpup' ),
|
344 |
-
'description' => __( 'Backup to Folder', 'backwpup' ),
|
345 |
-
),
|
346 |
-
'can_sync' => FALSE,
|
347 |
-
'needed' => array(
|
348 |
-
'php_version' => '',
|
349 |
-
'functions' => array(),
|
350 |
-
'classes' => array()
|
351 |
-
),
|
352 |
-
'autoload' => array()
|
353 |
-
);
|
354 |
-
// backup with mail
|
355 |
-
self::$registered_destinations[ 'EMAIL' ] = array(
|
356 |
-
'class' => 'BackWPup_Destination_Email',
|
357 |
-
'info' => array(
|
358 |
-
'ID' => 'EMAIL',
|
359 |
-
'name' => __( 'Email', 'backwpup' ),
|
360 |
-
'description' => __( 'Backup sent via email', 'backwpup' ),
|
361 |
-
),
|
362 |
-
'can_sync' => FALSE,
|
363 |
-
'needed' => array(
|
364 |
-
'php_version' => '5.2.4',
|
365 |
-
'functions' => array(),
|
366 |
-
'classes' => array()
|
367 |
-
),
|
368 |
-
'autoload' => array()
|
369 |
-
);
|
370 |
-
// backup to ftp
|
371 |
-
self::$registered_destinations[ 'FTP' ] = array(
|
372 |
-
'class' => 'BackWPup_Destination_Ftp',
|
373 |
-
'info' => array(
|
374 |
-
'ID' => 'FTP',
|
375 |
-
'name' => __( 'FTP', 'backwpup' ),
|
376 |
-
'description' => __( 'Backup to FTP', 'backwpup' ),
|
377 |
-
),
|
378 |
-
'can_sync' => FALSE,
|
379 |
-
'needed' => array(
|
380 |
-
'mphp_version' => '',
|
381 |
-
'functions' => array( 'ftp_nb_fput' ),
|
382 |
-
'classes' => array()
|
383 |
-
),
|
384 |
-
'autoload' => array()
|
385 |
-
);
|
386 |
-
// backup to dropbox
|
387 |
-
self::$registered_destinations[ 'DROPBOX' ] = array(
|
388 |
-
'class' => 'BackWPup_Destination_Dropbox',
|
389 |
-
'info' => array(
|
390 |
-
'ID' => 'DROPBOX',
|
391 |
-
'name' => __( 'Dropbox', 'backwpup' ),
|
392 |
-
'description' => __( 'Backup to Dropbox', 'backwpup' ),
|
393 |
-
),
|
394 |
-
'can_sync' => FALSE,
|
395 |
-
'needed' => array(
|
396 |
-
'php_version' => '',
|
397 |
-
'functions' => array( 'curl_exec' ),
|
398 |
-
'classes' => array()
|
399 |
-
),
|
400 |
-
'autoload' => array()
|
401 |
-
);
|
402 |
-
// Backup to S3
|
403 |
-
self::$registered_destinations[ 'S3' ] = array(
|
404 |
-
'class' => 'BackWPup_Destination_S3',
|
405 |
-
'info' => array(
|
406 |
-
'ID' => 'S3',
|
407 |
-
'name' => __( 'S3 Service', 'backwpup' ),
|
408 |
-
'description' => __( 'Backup to an S3 Service', 'backwpup' ),
|
409 |
-
),
|
410 |
-
'can_sync' => FALSE,
|
411 |
-
'needed' => array(
|
412 |
-
'php_version' => '5.3.3',
|
413 |
-
'functions' => array( 'curl_exec' ),
|
414 |
-
'classes' => array( 'XMLWriter' )
|
415 |
-
),
|
416 |
-
'autoload' => array( 'Aws\\Common' => dirname( __FILE__ ) .'/vendor',
|
417 |
-
'Aws\\S3' => dirname( __FILE__ ) .'/vendor',
|
418 |
-
'Symfony\\Component\\EventDispatcher' => dirname( __FILE__ ) . '/vendor',
|
419 |
-
'Guzzle' => dirname( __FILE__ ) . '/vendor' )
|
420 |
-
);
|
421 |
-
// backup to MS Azure
|
422 |
-
self::$registered_destinations[ 'MSAZURE' ] = array(
|
423 |
-
'class' => 'BackWPup_Destination_MSAzure',
|
424 |
-
'info' => array(
|
425 |
-
'ID' => 'MSAZURE',
|
426 |
-
'name' => __( 'MS Azure', 'backwpup' ),
|
427 |
-
'description' => __( 'Backup to Microsoft Azure (Blob)', 'backwpup' ),
|
428 |
-
),
|
429 |
-
'can_sync' => FALSE,
|
430 |
-
'needed' => array(
|
431 |
-
'php_version' => '5.3.2',
|
432 |
-
'functions' => array(),
|
433 |
-
'classes' => array()
|
434 |
-
),
|
435 |
-
'autoload' => array( 'WindowsAzure' => dirname( __FILE__ ) . '/vendor' )
|
436 |
-
);
|
437 |
-
// backup to Rackspace Cloud
|
438 |
-
self::$registered_destinations[ 'RSC' ] = array(
|
439 |
-
'class' => 'BackWPup_Destination_RSC',
|
440 |
-
'info' => array(
|
441 |
-
'ID' => 'RSC',
|
442 |
-
'name' => __( 'RSC', 'backwpup' ),
|
443 |
-
'description' => __( 'Backup to Rackspace Cloud Files', 'backwpup' ),
|
444 |
-
),
|
445 |
-
'can_sync' => FALSE,
|
446 |
-
'needed' => array(
|
447 |
-
'php_version' => '5.3.3',
|
448 |
-
'functions' => array( 'curl_exec' ),
|
449 |
-
'classes' => array()
|
450 |
-
),
|
451 |
-
'autoload' => array( 'OpenCloud' => dirname( __FILE__ ) . '/vendor',
|
452 |
-
'Guzzle' => dirname( __FILE__ ) . '/vendor',
|
453 |
-
'Psr' => dirname( __FILE__ ) . '/vendor' )
|
454 |
-
);
|
455 |
-
// backup to Sugarsync
|
456 |
-
self::$registered_destinations[ 'SUGARSYNC' ] = array(
|
457 |
-
'class' => 'BackWPup_Destination_SugarSync',
|
458 |
-
'info' => array(
|
459 |
-
'ID' => 'SUGARSYNC',
|
460 |
-
'name' => __( 'SugarSync', 'backwpup' ),
|
461 |
-
'description' => __( 'Backup to SugarSync', 'backwpup' ),
|
462 |
-
),
|
463 |
-
'can_sync' => FALSE,
|
464 |
-
'needed' => array(
|
465 |
-
'php_version' => '',
|
466 |
-
'functions' => array( 'curl_exec' ),
|
467 |
-
'classes' => array()
|
468 |
-
),
|
469 |
-
'autoload' => array()
|
470 |
-
);
|
471 |
-
|
472 |
-
//Hook for adding Destinations like above
|
473 |
-
self::$registered_destinations = apply_filters( 'backwpup_register_destination', self::$registered_destinations );
|
474 |
-
|
475 |
-
//check BackWPup Destinations
|
476 |
-
foreach ( self::$registered_destinations as $dest_key => $dest ) {
|
477 |
-
self::$registered_destinations[ $dest_key ][ 'error'] = '';
|
478 |
-
// check PHP Version
|
479 |
-
if ( ! empty( $dest[ 'needed' ][ 'php_version' ] ) && version_compare( PHP_VERSION, $dest[ 'needed' ][ 'php_version' ], '<' ) ) {
|
480 |
-
self::$registered_destinations[ $dest_key ][ 'error' ] .= sprintf( __( 'PHP Version %1$s is to low, you need Version %2$s or above.', 'backwpup' ), PHP_VERSION, $dest[ 'needed' ][ 'php_version' ] ) . ' ';
|
481 |
-
self::$registered_destinations[ $dest_key ][ 'class' ] = NULL;
|
482 |
-
}
|
483 |
-
//check functions exists
|
484 |
-
if ( ! empty( $dest[ 'needed' ][ 'functions' ] ) ) {
|
485 |
-
foreach ( $dest[ 'needed' ][ 'functions' ] as $function_need ) {
|
486 |
-
if ( ! function_exists( $function_need ) ) {
|
487 |
-
self::$registered_destinations[ $dest_key ][ 'error' ] .= sprintf( __( 'Missing function "%s".', 'backwpup' ), $function_need ) . ' ';
|
488 |
-
self::$registered_destinations[ $dest_key ][ 'class' ] = NULL;
|
489 |
-
}
|
490 |
-
}
|
491 |
-
}
|
492 |
-
//check classes exists
|
493 |
-
if ( ! empty( $dest[ 'needed' ][ 'classes' ] ) ) {
|
494 |
-
foreach ( $dest[ 'needed' ][ 'classes' ] as $class_need ) {
|
495 |
-
if ( ! class_exists( $class_need ) ) {
|
496 |
-
self::$registered_destinations[ $dest_key ][ 'error' ] .= sprintf( __( 'Missing class "%s".', 'backwpup' ), $class_need ) . ' ';
|
497 |
-
self::$registered_destinations[ $dest_key ][ 'class' ] = NULL;
|
498 |
-
}
|
499 |
-
}
|
500 |
-
}
|
501 |
-
//add class/namespace to auto load
|
502 |
-
if ( ! empty( self::$registered_destinations[ $dest_key ][ 'class' ] ) && ! empty( self::$registered_destinations[ $dest_key ][ 'autoload' ] ) )
|
503 |
-
self::$autoload = array_merge( self::$autoload, self::$registered_destinations[ $dest_key ][ 'autoload' ] );
|
504 |
-
|
505 |
-
}
|
506 |
-
|
507 |
-
return self::$registered_destinations;
|
508 |
-
}
|
509 |
-
|
510 |
-
|
511 |
-
/**
|
512 |
-
* Gets a array of instances from Job types
|
513 |
-
*
|
514 |
-
* @return array BackWPup_JobTypes
|
515 |
-
*/
|
516 |
-
public static function get_job_types() {
|
517 |
-
|
518 |
-
if ( !empty( self::$job_types ) )
|
519 |
-
return self::$job_types;
|
520 |
-
|
521 |
-
self::$job_types[ 'DBDUMP' ] = new BackWPup_JobType_DBDump;
|
522 |
-
self::$job_types[ 'FILE' ] = new BackWPup_JobType_File;
|
523 |
-
self::$job_types[ 'WPEXP' ] = new BackWPup_JobType_WPEXP;
|
524 |
-
self::$job_types[ 'WPPLUGIN' ] = new BackWPup_JobType_WPPlugin;
|
525 |
-
self::$job_types[ 'DBCHECK' ] = new BackWPup_JobType_DBCheck;
|
526 |
-
|
527 |
-
self::$job_types = apply_filters( 'backwpup_job_types', self::$job_types );
|
528 |
-
|
529 |
-
//remove types can't load
|
530 |
-
foreach ( self::$job_types as $key => $job_type ) {
|
531 |
-
if ( empty( $job_type ) || ! is_object( $job_type ) )
|
532 |
-
unset( self::$job_types[ $key ] );
|
533 |
-
}
|
534 |
-
|
535 |
-
return self::$job_types;
|
536 |
-
}
|
537 |
-
|
538 |
-
|
539 |
-
/**
|
540 |
-
* Gets a array of instances from Wizards
|
541 |
-
*
|
542 |
-
* @return array BackWPup_Pro_Wizards
|
543 |
-
*/
|
544 |
-
public static function get_wizards() {
|
545 |
-
|
546 |
-
if ( !empty( self::$wizards ) )
|
547 |
-
return self::$wizards;
|
548 |
-
|
549 |
-
self::$wizards = apply_filters( 'backwpup_pro_wizards', self::$wizards );
|
550 |
-
|
551 |
-
//remove wizards can't load
|
552 |
-
foreach ( self::$wizards as $key => $wizard ) {
|
553 |
-
if ( empty( $wizard ) || ! is_object( $wizard ) )
|
554 |
-
unset( self::$wizards[ $key ] );
|
555 |
-
}
|
556 |
-
|
557 |
-
return self::$wizards;
|
558 |
-
|
559 |
-
}
|
560 |
-
|
561 |
-
}
|
562 |
-
|
563 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: BackWPup
|
4 |
+
* Plugin URI: http://backwpup.com
|
5 |
+
* Description: WordPress Backup Plugin
|
6 |
+
* Author: Inpsyde GmbH
|
7 |
+
* Author URI: http://inpsyde.com
|
8 |
+
* Version: 3.4.0
|
9 |
+
* Text Domain: backwpup
|
10 |
+
* Domain Path: /languages/
|
11 |
+
* Network: true
|
12 |
+
* License: GPLv3
|
13 |
+
* License URI: http://www.gnu.org/licenses/gpl-3.0
|
14 |
+
*/
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Copyright (C) 2012-2016 Inpsyde GmbH (email: info@inpsyde.com)
|
18 |
+
*
|
19 |
+
* This program is free software; you can redistribute it and/or
|
20 |
+
* modify it under the terms of the GNU General Public License
|
21 |
+
* as published by the Free Software Foundation; either version 2
|
22 |
+
* of the License, or (at your option) any later version.
|
23 |
+
*
|
24 |
+
* This program is distributed in the hope that it will be useful,
|
25 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27 |
+
* GNU General Public License for more details.
|
28 |
+
*
|
29 |
+
* You should have received a copy of the GNU General Public License
|
30 |
+
* along with this program; if not, write to the Free Software
|
31 |
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
32 |
+
*/
|
33 |
+
|
34 |
+
if ( ! class_exists( 'BackWPup' ) ) {
|
35 |
+
|
36 |
+
// Don't activate on anything less than PHP 5.3 or WordPress 3.9
|
37 |
+
if ( version_compare( PHP_VERSION, '5.3.0', '<' ) || version_compare( get_bloginfo( 'version' ), '3.9', '<' ) || ! function_exists( 'spl_autoload_register' ) ) {
|
38 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
39 |
+
deactivate_plugins( __FILE__ );
|
40 |
+
die( 'BackWPup requires PHP version 5.3 with spl extension or greater and WordPress 3.9 or greater.' );
|
41 |
+
}
|
42 |
+
|
43 |
+
//Start Plugin
|
44 |
+
if ( function_exists( 'add_filter' ) ) {
|
45 |
+
add_action( 'plugins_loaded', array( 'BackWPup', 'get_instance' ), 11 );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Main BackWPup Plugin Class
|
50 |
+
*/
|
51 |
+
final class BackWPup {
|
52 |
+
|
53 |
+
private static $instance = NULL;
|
54 |
+
private static $plugin_data = array();
|
55 |
+
private static $autoload = array();
|
56 |
+
private static $destinations = array();
|
57 |
+
private static $registered_destinations = array();
|
58 |
+
private static $job_types = array();
|
59 |
+
private static $wizards = array();
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Set needed filters and actions and load
|
63 |
+
*/
|
64 |
+
private function __construct() {
|
65 |
+
|
66 |
+
// Nothing else matters if we're not on the main site
|
67 |
+
if ( ! is_main_site() ) {
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
//auto loader
|
71 |
+
spl_autoload_register( array( $this, 'autoloader' ) );
|
72 |
+
|
73 |
+
//start upgrade if needed
|
74 |
+
if ( get_site_option( 'backwpup_version' ) !== self::get_plugin_data( 'Version' ) || ! wp_next_scheduled( 'backwpup_check_cleanup' ) ) {
|
75 |
+
BackWPup_Install::activate();
|
76 |
+
}
|
77 |
+
//load pro features
|
78 |
+
if ( class_exists( 'BackWPup_Pro' ) ) {
|
79 |
+
BackWPup_Pro::get_instance();
|
80 |
+
}
|
81 |
+
//WP-Cron
|
82 |
+
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
83 |
+
if ( ! empty( $_GET[ 'backwpup_run' ] ) && class_exists( 'BackWPup_Job' ) ) {
|
84 |
+
//early disable caches
|
85 |
+
BackWPup_Job::disable_caches();
|
86 |
+
//add action for running jobs in wp-cron.php
|
87 |
+
add_action( 'wp_loaded', array( 'BackWPup_Cron', 'cron_active' ), PHP_INT_MAX );
|
88 |
+
} else {
|
89 |
+
//add cron actions
|
90 |
+
add_action( 'backwpup_cron', array( 'BackWPup_Cron', 'run' ) );
|
91 |
+
add_action( 'backwpup_check_cleanup', array( 'BackWPup_Cron', 'check_cleanup' ) );
|
92 |
+
}
|
93 |
+
//if in cron the rest is not needed
|
94 |
+
return;
|
95 |
+
}
|
96 |
+
//deactivation hook
|
97 |
+
register_deactivation_hook( __FILE__, array( 'BackWPup_Install', 'deactivate' ) );
|
98 |
+
//Admin bar
|
99 |
+
if ( get_site_option( 'backwpup_cfg_showadminbar' ) ) {
|
100 |
+
add_action( 'init', array( 'BackWPup_Adminbar', 'get_instance' ) );
|
101 |
+
}
|
102 |
+
//only in backend
|
103 |
+
if ( is_admin() && class_exists( 'BackWPup_Admin' ) ) {
|
104 |
+
BackWPup_Admin::get_instance();
|
105 |
+
}
|
106 |
+
//work with wp-cli
|
107 |
+
if ( defined( 'WP_CLI' ) && WP_CLI && method_exists( 'WP_CLI', 'add_command' ) ) {
|
108 |
+
WP_CLI::add_command( 'backwpup', 'BackWPup_WP_CLI' );
|
109 |
+
}
|
110 |
+
|
111 |
+
// Notices and messages in admin
|
112 |
+
if ( is_admin() && current_user_can( 'backwpup' ) ) {
|
113 |
+
|
114 |
+
// Work for Inpsyde widget
|
115 |
+
$inpsyder_widget = new BackWPup_Become_Inpsyder_Widget();
|
116 |
+
add_action( 'wp_dashboard_setup', array( $inpsyder_widget, 'setup_widget' ) );
|
117 |
+
add_action( 'backwpup_admin_messages', array( $inpsyder_widget, 'print_plugin_widget_markup' ), 0 );
|
118 |
+
|
119 |
+
// Beta Tester notice
|
120 |
+
$beta_tester_notice = new BackWPup_BetaTester_Admin_Notice();
|
121 |
+
add_action( 'backwpup_admin_messages', array( $beta_tester_notice, 'dashboard_message' ), 20 );
|
122 |
+
|
123 |
+
// Setup "dismissible" option actions for notices
|
124 |
+
BackWPup_Dismissible_Notice_Option::setup_actions(
|
125 |
+
false,
|
126 |
+
BackWPup_Become_Inpsyder_Widget::NOTICE_ID,
|
127 |
+
'backwpup'
|
128 |
+
);
|
129 |
+
BackWPup_Dismissible_Notice_Option::setup_actions(
|
130 |
+
false,
|
131 |
+
BackWPup_BetaTester_Admin_Notice::NOTICE_ID,
|
132 |
+
'backwpup'
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
// Phone Home
|
137 |
+
require_once dirname( __FILE__ ) . '/vendor/inpsyde/phone-home-client/inc/autoload.php';
|
138 |
+
Inpsyde_PhoneHome_FrontController::initialize_for_network(
|
139 |
+
'BackWPup',
|
140 |
+
dirname( __FILE__ ) . '/assets/templates/phpnotice',
|
141 |
+
'backwpup',
|
142 |
+
array(
|
143 |
+
Inpsyde_PhoneHome_Configuration::ANONYMIZE => true,
|
144 |
+
Inpsyde_PhoneHome_Configuration::MINIMUM_CAPABILITY => 'manage_options',
|
145 |
+
Inpsyde_PhoneHome_Configuration::COLLECT_PHP => true,
|
146 |
+
Inpsyde_PhoneHome_Configuration::COLLECT_WP => true,
|
147 |
+
Inpsyde_PhoneHome_Configuration::SERVER_ADDRESS => 'https://backwpup.com/wp-json',
|
148 |
+
)
|
149 |
+
);
|
150 |
+
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* @static
|
155 |
+
*
|
156 |
+
* @return self
|
157 |
+
*/
|
158 |
+
public static function get_instance() {
|
159 |
+
|
160 |
+
if (NULL === self::$instance) {
|
161 |
+
self::$instance = new self;
|
162 |
+
}
|
163 |
+
return self::$instance;
|
164 |
+
}
|
165 |
+
|
166 |
+
|
167 |
+
private function __clone() {}
|
168 |
+
|
169 |
+
/**
|
170 |
+
* get information about the Plugin
|
171 |
+
*
|
172 |
+
* @param string $name Name of info to get or NULL to get all
|
173 |
+
* @return string|array
|
174 |
+
*/
|
175 |
+
public static function get_plugin_data( $name = NULL ) {
|
176 |
+
|
177 |
+
if ( $name )
|
178 |
+
$name = strtolower( trim( $name ) );
|
179 |
+
|
180 |
+
if ( empty( self::$plugin_data ) ) {
|
181 |
+
self::$plugin_data = get_file_data( __FILE__, array(
|
182 |
+
'name' => 'Plugin Name',
|
183 |
+
'version' => 'Version'
|
184 |
+
), 'plugin' );
|
185 |
+
self::$plugin_data[ 'name' ] = trim( self::$plugin_data[ 'name' ] );
|
186 |
+
//set some extra vars
|
187 |
+
self::$plugin_data[ 'basename' ] = plugin_basename( dirname( __FILE__ ) );
|
188 |
+
self::$plugin_data[ 'mainfile' ] = __FILE__ ;
|
189 |
+
self::$plugin_data[ 'plugindir' ] = untrailingslashit( dirname( __FILE__ ) ) ;
|
190 |
+
self::$plugin_data[ 'hash' ] = get_site_option( 'backwpup_cfg_hash' );
|
191 |
+
if ( empty( self::$plugin_data[ 'hash' ] ) || strlen( self::$plugin_data[ 'hash' ] ) < 6 || strlen( self::$plugin_data[ 'hash' ] ) > 12 ) {
|
192 |
+
self::$plugin_data[ 'hash' ] = substr( md5( md5( __FILE__ ) ), 14, 6 );
|
193 |
+
update_site_option( 'backwpup_cfg_hash', self::$plugin_data[ 'hash' ] );
|
194 |
+
}
|
195 |
+
if ( defined( 'WP_TEMP_DIR' ) && is_dir( WP_TEMP_DIR ) ) {
|
196 |
+
self::$plugin_data['temp'] = str_replace( '\\', '/', get_temp_dir() ) . 'backwpup-' . self::$plugin_data['hash'] . '/';
|
197 |
+
} else {
|
198 |
+
$upload_dir = wp_upload_dir();
|
199 |
+
self::$plugin_data['temp'] = str_replace( '\\', '/', $upload_dir['basedir'] ) . '/backwpup-' . self::$plugin_data['hash'] . '-temp/';
|
200 |
+
}
|
201 |
+
self::$plugin_data[ 'running_file' ] = self::$plugin_data[ 'temp' ] . 'backwpup-working.php';
|
202 |
+
self::$plugin_data[ 'url' ] = plugins_url( '', __FILE__ );
|
203 |
+
self::$plugin_data[ 'cacert' ] = apply_filters( 'backwpup_cacert_bundle', ABSPATH . WPINC . '/certificates/ca-bundle.crt' );
|
204 |
+
//get unmodified WP Versions
|
205 |
+
include ABSPATH . WPINC . '/version.php';
|
206 |
+
/** @var $wp_version string */
|
207 |
+
self::$plugin_data[ 'wp_version' ] = $wp_version;
|
208 |
+
//Build User Agent
|
209 |
+
self::$plugin_data[ 'user-agent' ] = self::$plugin_data[ 'name' ].'/' . self::$plugin_data[ 'version' ] . '; WordPress/' . self::$plugin_data[ 'wp_version' ] . '; ' . home_url();
|
210 |
+
}
|
211 |
+
|
212 |
+
if ( ! empty( $name ) )
|
213 |
+
return self::$plugin_data[ $name ];
|
214 |
+
else
|
215 |
+
return self::$plugin_data;
|
216 |
+
}
|
217 |
+
|
218 |
+
|
219 |
+
/**
|
220 |
+
* include not existing classes automatically
|
221 |
+
*
|
222 |
+
* @param string $class Class to load from file
|
223 |
+
*/
|
224 |
+
private function autoloader( $class ) {
|
225 |
+
|
226 |
+
//BackWPup classes auto load
|
227 |
+
if ( strstr( strtolower( $class ), 'backwpup_' ) ) {
|
228 |
+
$dir = dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 |
$class_file_name = 'class-' . str_replace( array( 'backwpup_', '_' ), array( '', '-' ), strtolower( $class ) ) . '.php';
|
230 |
+
if ( strstr( strtolower( $class ), 'backwpup_pro' ) ) {
|
231 |
+
$dir .= 'pro' . DIRECTORY_SEPARATOR;
|
232 |
+
$class_file_name = str_replace( 'pro-','', $class_file_name );
|
233 |
+
}
|
234 |
+
if ( file_exists( $dir . $class_file_name ) )
|
235 |
+
require $dir . $class_file_name;
|
236 |
+
}
|
237 |
+
|
238 |
+
// namespaced PSR-0
|
239 |
+
if ( ! empty( self::$autoload ) ) {
|
240 |
+
$pos = strrpos( $class, '\\' );
|
241 |
+
if ( $pos !== FALSE ) {
|
242 |
+
$class_path = str_replace( '\\', DIRECTORY_SEPARATOR, substr( $class, 0, $pos ) ) . DIRECTORY_SEPARATOR . str_replace( '_', DIRECTORY_SEPARATOR, substr( $class, $pos + 1 ) ) . '.php';
|
243 |
+
foreach ( self::$autoload as $prefix => $dir ) {
|
244 |
+
if ( $class === strstr( $class, $prefix ) ) {
|
245 |
+
if ( file_exists( $dir . DIRECTORY_SEPARATOR . $class_path ) )
|
246 |
+
require $dir . DIRECTORY_SEPARATOR . $class_path;
|
247 |
+
}
|
248 |
+
}
|
249 |
+
} // Single class file
|
250 |
+
elseif ( ! empty( self::$autoload[ $class ] ) && is_file( self::$autoload[ $class ] ) ) {
|
251 |
+
require self::$autoload[ $class ];
|
252 |
+
}
|
253 |
+
}
|
254 |
+
|
255 |
+
//Google SDK Auto loading
|
256 |
+
$classPath = explode( '_', $class );
|
257 |
+
if ( $classPath[0] == 'Google' ) {
|
258 |
+
if ( count( $classPath ) > 3 ) {
|
259 |
+
$classPath = array_slice( $classPath, 0, 3 );
|
260 |
+
}
|
261 |
+
$filePath = self::get_plugin_data( 'plugindir' ) . '/vendor/' . implode( '/', $classPath ) . '.php';
|
262 |
+
if ( file_exists( $filePath ) ) {
|
263 |
+
require $filePath;
|
264 |
+
}
|
265 |
+
}
|
266 |
+
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Load Plugin Translation
|
271 |
+
*
|
272 |
+
* @return bool Text domain loaded
|
273 |
+
*/
|
274 |
+
public static function load_text_domain() {
|
275 |
+
|
276 |
+
if ( is_textdomain_loaded( 'backwpup' ) ) {
|
277 |
+
return TRUE;
|
278 |
+
}
|
279 |
+
|
280 |
+
return load_plugin_textdomain( 'backwpup', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
|
281 |
+
}
|
282 |
+
|
283 |
+
/**
|
284 |
+
* Get a array of instances for Backup Destination's
|
285 |
+
*
|
286 |
+
* @param $key string Key of Destination where get class instance from
|
287 |
+
* @return array BackWPup_Destinations
|
288 |
+
*/
|
289 |
+
public static function get_destination( $key ) {
|
290 |
+
|
291 |
+
$key = strtoupper( $key );
|
292 |
+
|
293 |
+
if ( isset( self::$destinations[ $key ] ) && is_object( self::$destinations[ $key ] ) )
|
294 |
+
return self::$destinations[ $key ];
|
295 |
+
|
296 |
+
$reg_dests = self::get_registered_destinations();
|
297 |
+
if ( ! empty( $reg_dests[ $key ][ 'class' ] ) ) {
|
298 |
+
self::$destinations[ $key ] = new $reg_dests[ $key ][ 'class' ];
|
299 |
+
} else {
|
300 |
+
return NULL;
|
301 |
+
}
|
302 |
+
|
303 |
+
return self::$destinations[ $key ];
|
304 |
+
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Get a array of registered Destination's for Backups
|
308 |
+
*
|
309 |
+
* @return array BackWPup_Destinations
|
310 |
+
*/
|
311 |
+
public static function get_registered_destinations() {
|
312 |
+
|
313 |
+
//only run it one time
|
314 |
+
if ( ! empty( self::$registered_destinations ) )
|
315 |
+
return self::$registered_destinations;
|
316 |
+
|
317 |
+
//add BackWPup Destinations
|
318 |
+
// to folder
|
319 |
+
self::$registered_destinations[ 'FOLDER' ] = array(
|
320 |
+
'class' => 'BackWPup_Destination_Folder',
|
321 |
+
'info' => array(
|
322 |
+
'ID' => 'FOLDER',
|
323 |
+
'name' => __( 'Folder', 'backwpup' ),
|
324 |
+
'description' => __( 'Backup to Folder', 'backwpup' ),
|
325 |
+
),
|
326 |
+
'can_sync' => FALSE,
|
327 |
+
'needed' => array(
|
328 |
+
'php_version' => '',
|
329 |
+
'functions' => array(),
|
330 |
+
'classes' => array()
|
331 |
+
),
|
332 |
+
'autoload' => array()
|
333 |
+
);
|
334 |
+
// backup with mail
|
335 |
+
self::$registered_destinations[ 'EMAIL' ] = array(
|
336 |
+
'class' => 'BackWPup_Destination_Email',
|
337 |
+
'info' => array(
|
338 |
+
'ID' => 'EMAIL',
|
339 |
+
'name' => __( 'Email', 'backwpup' ),
|
340 |
+
'description' => __( 'Backup sent via email', 'backwpup' ),
|
341 |
+
),
|
342 |
+
'can_sync' => FALSE,
|
343 |
+
'needed' => array(
|
344 |
+
'php_version' => '5.2.4',
|
345 |
+
'functions' => array(),
|
346 |
+
'classes' => array()
|
347 |
+
),
|
348 |
+
'autoload' => array()
|
349 |
+
);
|
350 |
+
// backup to ftp
|
351 |
+
self::$registered_destinations[ 'FTP' ] = array(
|
352 |
+
'class' => 'BackWPup_Destination_Ftp',
|
353 |
+
'info' => array(
|
354 |
+
'ID' => 'FTP',
|
355 |
+
'name' => __( 'FTP', 'backwpup' ),
|
356 |
+
'description' => __( 'Backup to FTP', 'backwpup' ),
|
357 |
+
),
|
358 |
+
'can_sync' => FALSE,
|
359 |
+
'needed' => array(
|
360 |
+
'mphp_version' => '',
|
361 |
+
'functions' => array( 'ftp_nb_fput' ),
|
362 |
+
'classes' => array()
|
363 |
+
),
|
364 |
+
'autoload' => array()
|
365 |
+
);
|
366 |
+
// backup to dropbox
|
367 |
+
self::$registered_destinations[ 'DROPBOX' ] = array(
|
368 |
+
'class' => 'BackWPup_Destination_Dropbox',
|
369 |
+
'info' => array(
|
370 |
+
'ID' => 'DROPBOX',
|
371 |
+
'name' => __( 'Dropbox', 'backwpup' ),
|
372 |
+
'description' => __( 'Backup to Dropbox', 'backwpup' ),
|
373 |
+
),
|
374 |
+
'can_sync' => FALSE,
|
375 |
+
'needed' => array(
|
376 |
+
'php_version' => '',
|
377 |
+
'functions' => array( 'curl_exec' ),
|
378 |
+
'classes' => array()
|
379 |
+
),
|
380 |
+
'autoload' => array()
|
381 |
+
);
|
382 |
+
// Backup to S3
|
383 |
+
self::$registered_destinations[ 'S3' ] = array(
|
384 |
+
'class' => 'BackWPup_Destination_S3',
|
385 |
+
'info' => array(
|
386 |
+
'ID' => 'S3',
|
387 |
+
'name' => __( 'S3 Service', 'backwpup' ),
|
388 |
+
'description' => __( 'Backup to an S3 Service', 'backwpup' ),
|
389 |
+
),
|
390 |
+
'can_sync' => FALSE,
|
391 |
+
'needed' => array(
|
392 |
+
'php_version' => '5.3.3',
|
393 |
+
'functions' => array( 'curl_exec' ),
|
394 |
+
'classes' => array( 'XMLWriter' )
|
395 |
+
),
|
396 |
+
'autoload' => array( 'Aws\\Common' => dirname( __FILE__ ) .'/vendor',
|
397 |
+
'Aws\\S3' => dirname( __FILE__ ) .'/vendor',
|
398 |
+
'Symfony\\Component\\EventDispatcher' => dirname( __FILE__ ) . '/vendor',
|
399 |
+
'Guzzle' => dirname( __FILE__ ) . '/vendor' )
|
400 |
+
);
|
401 |
+
// backup to MS Azure
|
402 |
+
self::$registered_destinations[ 'MSAZURE' ] = array(
|
403 |
+
'class' => 'BackWPup_Destination_MSAzure',
|
404 |
+
'info' => array(
|
405 |
+
'ID' => 'MSAZURE',
|
406 |
+
'name' => __( 'MS Azure', 'backwpup' ),
|
407 |
+
'description' => __( 'Backup to Microsoft Azure (Blob)', 'backwpup' ),
|
408 |
+
),
|
409 |
+
'can_sync' => FALSE,
|
410 |
+
'needed' => array(
|
411 |
+
'php_version' => '5.3.2',
|
412 |
+
'functions' => array(),
|
413 |
+
'classes' => array()
|
414 |
+
),
|
415 |
+
'autoload' => array( 'WindowsAzure' => dirname( __FILE__ ) . '/vendor' )
|
416 |
+
);
|
417 |
+
// backup to Rackspace Cloud
|
418 |
+
self::$registered_destinations[ 'RSC' ] = array(
|
419 |
+
'class' => 'BackWPup_Destination_RSC',
|
420 |
+
'info' => array(
|
421 |
+
'ID' => 'RSC',
|
422 |
+
'name' => __( 'RSC', 'backwpup' ),
|
423 |
+
'description' => __( 'Backup to Rackspace Cloud Files', 'backwpup' ),
|
424 |
+
),
|
425 |
+
'can_sync' => FALSE,
|
426 |
+
'needed' => array(
|
427 |
+
'php_version' => '5.3.3',
|
428 |
+
'functions' => array( 'curl_exec' ),
|
429 |
+
'classes' => array()
|
430 |
+
),
|
431 |
+
'autoload' => array( 'OpenCloud' => dirname( __FILE__ ) . '/vendor',
|
432 |
+
'Guzzle' => dirname( __FILE__ ) . '/vendor',
|
433 |
+
'Psr' => dirname( __FILE__ ) . '/vendor' )
|
434 |
+
);
|
435 |
+
// backup to Sugarsync
|
436 |
+
self::$registered_destinations[ 'SUGARSYNC' ] = array(
|
437 |
+
'class' => 'BackWPup_Destination_SugarSync',
|
438 |
+
'info' => array(
|
439 |
+
'ID' => 'SUGARSYNC',
|
440 |
+
'name' => __( 'SugarSync', 'backwpup' ),
|
441 |
+
'description' => __( 'Backup to SugarSync', 'backwpup' ),
|
442 |
+
),
|
443 |
+
'can_sync' => FALSE,
|
444 |
+
'needed' => array(
|
445 |
+
'php_version' => '',
|
446 |
+
'functions' => array( 'curl_exec' ),
|
447 |
+
'classes' => array()
|
448 |
+
),
|
449 |
+
'autoload' => array()
|
450 |
+
);
|
451 |
+
|
452 |
+
//Hook for adding Destinations like above
|
453 |
+
self::$registered_destinations = apply_filters( 'backwpup_register_destination', self::$registered_destinations );
|
454 |
+
|
455 |
+
//check BackWPup Destinations
|
456 |
+
foreach ( self::$registered_destinations as $dest_key => $dest ) {
|
457 |
+
self::$registered_destinations[ $dest_key ][ 'error'] = '';
|
458 |
+
// check PHP Version
|
459 |
+
if ( ! empty( $dest[ 'needed' ][ 'php_version' ] ) && version_compare( PHP_VERSION, $dest[ 'needed' ][ 'php_version' ], '<' ) ) {
|
460 |
+
self::$registered_destinations[ $dest_key ][ 'error' ] .= sprintf( __( 'PHP Version %1$s is to low, you need Version %2$s or above.', 'backwpup' ), PHP_VERSION, $dest[ 'needed' ][ 'php_version' ] ) . ' ';
|
461 |
+
self::$registered_destinations[ $dest_key ][ 'class' ] = NULL;
|
462 |
+
}
|
463 |
+
//check functions exists
|
464 |
+
if ( ! empty( $dest[ 'needed' ][ 'functions' ] ) ) {
|
465 |
+
foreach ( $dest[ 'needed' ][ 'functions' ] as $function_need ) {
|
466 |
+
if ( ! function_exists( $function_need ) ) {
|
467 |
+
self::$registered_destinations[ $dest_key ][ 'error' ] .= sprintf( __( 'Missing function "%s".', 'backwpup' ), $function_need ) . ' ';
|
468 |
+
self::$registered_destinations[ $dest_key ][ 'class' ] = NULL;
|
469 |
+
}
|
470 |
+
}
|
471 |
+
}
|
472 |
+
//check classes exists
|
473 |
+
if ( ! empty( $dest[ 'needed' ][ 'classes' ] ) ) {
|
474 |
+
foreach ( $dest[ 'needed' ][ 'classes' ] as $class_need ) {
|
475 |
+
if ( ! class_exists( $class_need ) ) {
|
476 |
+
self::$registered_destinations[ $dest_key ][ 'error' ] .= sprintf( __( 'Missing class "%s".', 'backwpup' ), $class_need ) . ' ';
|
477 |
+
self::$registered_destinations[ $dest_key ][ 'class' ] = NULL;
|
478 |
+
}
|
479 |
+
}
|
480 |
+
}
|
481 |
+
//add class/namespace to auto load
|
482 |
+
if ( ! empty( self::$registered_destinations[ $dest_key ][ 'class' ] ) && ! empty( self::$registered_destinations[ $dest_key ][ 'autoload' ] ) )
|
483 |
+
self::$autoload = array_merge( self::$autoload, self::$registered_destinations[ $dest_key ][ 'autoload' ] );
|
484 |
+
|
485 |
+
}
|
486 |
+
|
487 |
+
return self::$registered_destinations;
|
488 |
+
}
|
489 |
+
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Gets a array of instances from Job types
|
493 |
+
*
|
494 |
+
* @return array BackWPup_JobTypes
|
495 |
+
*/
|
496 |
+
public static function get_job_types() {
|
497 |
+
|
498 |
+
if ( !empty( self::$job_types ) )
|
499 |
+
return self::$job_types;
|
500 |
+
|
501 |
+
self::$job_types[ 'DBDUMP' ] = new BackWPup_JobType_DBDump;
|
502 |
+
self::$job_types[ 'FILE' ] = new BackWPup_JobType_File;
|
503 |
+
self::$job_types[ 'WPEXP' ] = new BackWPup_JobType_WPEXP;
|
504 |
+
self::$job_types[ 'WPPLUGIN' ] = new BackWPup_JobType_WPPlugin;
|
505 |
+
self::$job_types[ 'DBCHECK' ] = new BackWPup_JobType_DBCheck;
|
506 |
+
|
507 |
+
self::$job_types = apply_filters( 'backwpup_job_types', self::$job_types );
|
508 |
+
|
509 |
+
//remove types can't load
|
510 |
+
foreach ( self::$job_types as $key => $job_type ) {
|
511 |
+
if ( empty( $job_type ) || ! is_object( $job_type ) )
|
512 |
+
unset( self::$job_types[ $key ] );
|
513 |
+
}
|
514 |
+
|
515 |
+
return self::$job_types;
|
516 |
+
}
|
517 |
+
|
518 |
+
|
519 |
+
/**
|
520 |
+
* Gets a array of instances from Wizards
|
521 |
+
*
|
522 |
+
* @return array BackWPup_Pro_Wizards
|
523 |
+
*/
|
524 |
+
public static function get_wizards() {
|
525 |
+
|
526 |
+
if ( !empty( self::$wizards ) )
|
527 |
+
return self::$wizards;
|
528 |
+
|
529 |
+
self::$wizards = apply_filters( 'backwpup_pro_wizards', self::$wizards );
|
530 |
+
|
531 |
+
//remove wizards can't load
|
532 |
+
foreach ( self::$wizards as $key => $wizard ) {
|
533 |
+
if ( empty( $wizard ) || ! is_object( $wizard ) )
|
534 |
+
unset( self::$wizards[ $key ] );
|
535 |
+
}
|
536 |
+
|
537 |
+
return self::$wizards;
|
538 |
+
|
539 |
+
}
|
540 |
+
|
541 |
+
}
|
542 |
+
|
543 |
+
}
|
inc/class-become-inpsyder-widget.php
CHANGED
@@ -81,13 +81,6 @@ class BackWPup_Become_Inpsyder_Widget {
|
|
81 |
// If notice is dismissed for good, don't show it
|
82 |
self::$should_show = ! $option->is_dismissed( self::NOTICE_ID );
|
83 |
|
84 |
-
$expiration_date = new DateTime('2017-05-02 00:00:00');
|
85 |
-
$now = new DateTime('now');
|
86 |
-
|
87 |
-
if ( $now < $expiration_date ) {
|
88 |
-
self::$should_show = false;
|
89 |
-
}
|
90 |
-
|
91 |
return self::$should_show;
|
92 |
}
|
93 |
|
@@ -141,7 +134,7 @@ class BackWPup_Become_Inpsyder_Widget {
|
|
141 |
</p>
|
142 |
<p<?php echo $btn_float === 'right' ? ' align="right' : '' ?>">
|
143 |
<a
|
144 |
-
style="background: #
|
145 |
class="button button-large button-primary"
|
146 |
href="<?php echo esc_url( $job_url ) ?>"
|
147 |
target="_blank">
|
81 |
// If notice is dismissed for good, don't show it
|
82 |
self::$should_show = ! $option->is_dismissed( self::NOTICE_ID );
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
return self::$should_show;
|
85 |
}
|
86 |
|
134 |
</p>
|
135 |
<p<?php echo $btn_float === 'right' ? ' align="right' : '' ?>">
|
136 |
<a
|
137 |
+
style="background: #9FC65D; border-color: #7ba617 #719c0d #719c0d; -webkit-box-shadow: 0 1px 0 #719c0d; box-shadow: 0 1px 0 #719c0d; text-shadow: 0 -1px 1px #719c0d, 1px 0 1px #719c0d, 0 1px 1px #719c0d, -1px 0 1px #719c0d;"
|
138 |
class="button button-large button-primary"
|
139 |
href="<?php echo esc_url( $job_url ) ?>"
|
140 |
target="_blank">
|
inc/class-betatester-admin-notice.php
CHANGED
@@ -51,13 +51,6 @@ class BackWPup_BetaTester_Admin_Notice {
|
|
51 |
self::$should_show = ! $option->is_dismissed( self::NOTICE_ID );
|
52 |
}
|
53 |
|
54 |
-
$expiration_date = new DateTime('2017-05-02 00:00:00');
|
55 |
-
$now = new DateTime('now');
|
56 |
-
|
57 |
-
if ( $now < $expiration_date ) {
|
58 |
-
self::$should_show = false;
|
59 |
-
}
|
60 |
-
|
61 |
return self::$should_show;
|
62 |
}
|
63 |
|
@@ -89,7 +82,7 @@ class BackWPup_BetaTester_Admin_Notice {
|
|
89 |
</p>
|
90 |
<p>
|
91 |
<a
|
92 |
-
style="background: #
|
93 |
class="button button-primary"
|
94 |
href="<?php echo esc_url( $join_us_url ) ?>"
|
95 |
target="_blank">
|
51 |
self::$should_show = ! $option->is_dismissed( self::NOTICE_ID );
|
52 |
}
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
return self::$should_show;
|
55 |
}
|
56 |
|
82 |
</p>
|
83 |
<p>
|
84 |
<a
|
85 |
+
style="background: #9FC65D; border-color: #7ba617 #719c0d #719c0d; -webkit-box-shadow: 0 1px 0 #719c0d; box-shadow: 0 1px 0 #719c0d; text-shadow: 0 -1px 1px #719c0d, 1px 0 1px #719c0d, 0 1px 1px #719c0d, -1px 0 1px #719c0d;"
|
86 |
class="button button-primary"
|
87 |
href="<?php echo esc_url( $join_us_url ) ?>"
|
88 |
target="_blank">
|
inc/class-cron.php
CHANGED
@@ -73,27 +73,32 @@ class BackWPup_Cron {
|
|
73 |
}
|
74 |
|
75 |
//Compress not compressed logs
|
76 |
-
if ( is_readable( $log_folder ) && function_exists( 'gzopen' )
|
|
|
77 |
//Compress old not compressed logs
|
78 |
-
|
|
|
|
|
79 |
$jobids = BackWPup_Option::get_job_ids();
|
80 |
-
|
81 |
-
if (
|
82 |
-
$compress = new BackWPup_Create_Archive( $
|
83 |
-
if ( $compress->add_file( $
|
84 |
-
unlink( $
|
85 |
//change last logfile in jobs
|
86 |
foreach( $jobids as $jobid ) {
|
87 |
$job_logfile = BackWPup_Option::get( $jobid, 'logfile' );
|
88 |
-
if ( ! empty( $job_logfile ) && $job_logfile === $
|
89 |
-
BackWPup_Option::update( $jobid, 'logfile', $
|
90 |
}
|
91 |
}
|
92 |
}
|
93 |
unset( $compress );
|
94 |
}
|
95 |
}
|
96 |
-
|
|
|
|
|
97 |
}
|
98 |
}
|
99 |
|
@@ -168,6 +173,11 @@ class BackWPup_Cron {
|
|
168 |
|
169 |
if ( $args['run'] === 'restart' ) {
|
170 |
$job_object = BackWPup_Job::get_working_data();
|
|
|
|
|
|
|
|
|
|
|
171 |
//restart job if not working or a restart wished
|
172 |
$not_worked_time = microtime( TRUE ) - $job_object->timestamp_last_update;
|
173 |
if ( ! $job_object->pid || $not_worked_time > 300 ) {
|
73 |
}
|
74 |
|
75 |
//Compress not compressed logs
|
76 |
+
if ( is_readable( $log_folder ) && function_exists( 'gzopen' )
|
77 |
+
&& get_site_option( 'backwpup_cfg_gzlogs' ) && ! is_object( $job_object ) ) {
|
78 |
//Compress old not compressed logs
|
79 |
+
try {
|
80 |
+
$dir = new BackWPup_Directory( $log_folder );
|
81 |
+
|
82 |
$jobids = BackWPup_Option::get_job_ids();
|
83 |
+
foreach ( $dir as $file ) {
|
84 |
+
if ( $file->isWritable() && '.html' == substr( $file->getFilename(), -5 ) ) {
|
85 |
+
$compress = new BackWPup_Create_Archive( $file->getPathname() . '.gz' );
|
86 |
+
if ( $compress->add_file( $file->getPathname() ) ) {
|
87 |
+
unlink( $file->getPathname() );
|
88 |
//change last logfile in jobs
|
89 |
foreach( $jobids as $jobid ) {
|
90 |
$job_logfile = BackWPup_Option::get( $jobid, 'logfile' );
|
91 |
+
if ( ! empty( $job_logfile ) && $job_logfile === $file->getPathname() ) {
|
92 |
+
BackWPup_Option::update( $jobid, 'logfile', $file->getPathname() . '.gz' );
|
93 |
}
|
94 |
}
|
95 |
}
|
96 |
unset( $compress );
|
97 |
}
|
98 |
}
|
99 |
+
}
|
100 |
+
catch ( UnexpectedValueException $e ) {
|
101 |
+
$job_object->log( sprintf( __( "Could not open path: %s", 'backwpup' ), $e->getMessage() ), E_USER_WARNING );
|
102 |
}
|
103 |
}
|
104 |
|
173 |
|
174 |
if ( $args['run'] === 'restart' ) {
|
175 |
$job_object = BackWPup_Job::get_working_data();
|
176 |
+
// Restart if cannot find job
|
177 |
+
if ( ! $job_object ) {
|
178 |
+
BackWPup_Job::start_http( 'restart' );
|
179 |
+
return;
|
180 |
+
}
|
181 |
//restart job if not working or a restart wished
|
182 |
$not_worked_time = microtime( TRUE ) - $job_object->timestamp_last_update;
|
183 |
if ( ! $job_object->pid || $not_worked_time > 300 ) {
|
inc/class-destination-dropbox.php
CHANGED
@@ -1,7 +1,9 @@
|
|
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
-
*
|
|
|
|
|
5 |
*/
|
6 |
class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
7 |
|
@@ -14,17 +16,15 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
14 |
* @return array
|
15 |
*/
|
16 |
public function option_defaults() {
|
17 |
-
|
18 |
return array(
|
19 |
'dropboxtoken' => array(),
|
20 |
'dropboxroot' => 'sandbox',
|
21 |
'dropboxmaxbackups' => 15,
|
22 |
'dropboxsyncnodelete' => true,
|
23 |
-
'dropboxdir' => trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) )
|
24 |
);
|
25 |
}
|
26 |
|
27 |
-
|
28 |
/**
|
29 |
* @param $jobid
|
30 |
*/
|
@@ -34,21 +34,14 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
34 |
//disable token on dropbox
|
35 |
try {
|
36 |
$dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
|
37 |
-
if ( BackWPup_Option::get( $jobid, 'dropboxsecret' ) ) {
|
38 |
-
$dropbox->setOAuthTokens( array(
|
39 |
-
'access_token' => BackWPup_Option::get( $jobid, 'dropboxtoken' ),
|
40 |
-
'oauth_token_secret' => BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'dropboxsecret' ) )
|
41 |
-
) );
|
42 |
-
} else {
|
43 |
$dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
echo '<div id="message" class="error"><p>' . sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ) . '</p></div>';
|
48 |
}
|
49 |
BackWPup_Option::update( $jobid, 'dropboxtoken', array() );
|
50 |
BackWPup_Option::update( $jobid, 'dropboxroot', 'sandbox' );
|
51 |
-
BackWPup_Option::delete( $jobid, 'dropboxsecret' );
|
52 |
}
|
53 |
|
54 |
$dropbox = new BackWPup_Destination_Dropbox_API( 'dropbox' );
|
@@ -124,6 +117,7 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
124 |
<input id="iddropboxmaxbackups" name="dropboxmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'dropboxmaxbackups' ) ); ?>" class="small-text" />
|
125 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
126 |
</label>
|
|
|
127 |
<?php } else { ?>
|
128 |
<label for="iddropboxsyncnodelete">
|
129 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'dropboxsyncnodelete' ), true ); ?> name="dropboxsyncnodelete" id="iddropboxsyncnodelete" />
|
@@ -139,8 +133,6 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
139 |
|
140 |
/**
|
141 |
* @param $jobid
|
142 |
-
*
|
143 |
-
* @return string|void
|
144 |
*/
|
145 |
public function edit_form_post_save( $jobid ) {
|
146 |
|
@@ -151,7 +143,8 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
151 |
$dropboxtoken = $dropbox->oAuthToken( $_POST['sandbox_code'] );
|
152 |
BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
|
153 |
BackWPup_Option::update( $jobid, 'dropboxroot', 'sandbox' );
|
154 |
-
}
|
|
|
155 |
BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
|
156 |
}
|
157 |
}
|
@@ -162,7 +155,8 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
162 |
$dropboxtoken = $dropbox->oAuthToken( $_POST['dropbbox_code'] );
|
163 |
BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
|
164 |
BackWPup_Option::update( $jobid, 'dropboxroot', 'dropbox' );
|
165 |
-
}
|
|
|
166 |
BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
|
167 |
}
|
168 |
}
|
@@ -171,9 +165,6 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
171 |
BackWPup_Option::update( $jobid, 'dropboxmaxbackups', ! empty( $_POST['dropboxmaxbackups'] ) ? absint( $_POST['dropboxmaxbackups'] ) : 0 );
|
172 |
|
173 |
$_POST['dropboxdir'] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( sanitize_text_field( $_POST['dropboxdir'] ) ) ) ) );
|
174 |
-
if ( substr( $_POST['dropboxdir'], 0, 1 ) === '/' ) {
|
175 |
-
$_POST['dropboxdir'] = substr( $_POST['dropboxdir'], 1 );
|
176 |
-
}
|
177 |
if ( $_POST['dropboxdir'] === '/' ) {
|
178 |
$_POST['dropboxdir'] = '';
|
179 |
}
|
@@ -186,14 +177,14 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
186 |
* @param $backupfile
|
187 |
*/
|
188 |
public function file_delete( $jobdest, $backupfile ) {
|
189 |
-
|
190 |
$files = get_site_transient( 'backwpup_' . strtolower( $jobdest ) );
|
191 |
list( $jobid, $dest ) = explode( '_', $jobdest );
|
192 |
|
193 |
try {
|
194 |
$dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
|
195 |
$dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
|
196 |
-
$dropbox->
|
|
|
197 |
//update file list
|
198 |
foreach ( $files as $key => $file ) {
|
199 |
if ( is_array( $file ) && $file['file'] == $backupfile ) {
|
@@ -201,7 +192,8 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
201 |
}
|
202 |
}
|
203 |
unset( $dropbox );
|
204 |
-
}
|
|
|
205 |
BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
|
206 |
}
|
207 |
|
@@ -213,16 +205,16 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
213 |
* @param $get_file
|
214 |
*/
|
215 |
public function file_download( $jobid, $get_file ) {
|
216 |
-
|
217 |
try {
|
218 |
$dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
|
219 |
$dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
|
220 |
-
$
|
221 |
-
if ( ! empty( $
|
222 |
-
header( "Location: " . $
|
223 |
}
|
224 |
die();
|
225 |
-
}
|
|
|
226 |
die( $e->getMessage() );
|
227 |
}
|
228 |
}
|
@@ -242,43 +234,35 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
242 |
* @return bool
|
243 |
*/
|
244 |
public function job_run_archive( BackWPup_Job $job_object ) {
|
245 |
-
|
246 |
$job_object->substeps_todo = 2 + $job_object->backup_filesize;
|
247 |
if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
|
248 |
$job_object->log( sprintf( __( '%d. Try to send backup file to Dropbox …', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) );
|
249 |
}
|
250 |
|
251 |
try {
|
252 |
-
$dropbox = new BackWPup_Destination_Dropbox_API( $job_object->job['dropboxroot'] );
|
253 |
-
// cahnge oauth1 to oauth2 token
|
254 |
-
if ( ! empty( $job_object->job['dropboxsecret'] ) && empty( $job_object->job['dropboxtoken']['access_token'] ) ) {
|
255 |
-
$dropbox->setOAuthTokens( array(
|
256 |
-
'access_token' => $job_object->job['dropboxtoken'],
|
257 |
-
'oauth_token_secret' => BackWPup_Encryption::decrypt( $job_object->job['dropboxsecret'] )
|
258 |
-
) );
|
259 |
-
$job_object->job['dropboxtoken'] = $dropbox->token_from_oauth1();
|
260 |
-
BackWPup_Option::update( $job_object->job['jobid'], 'dropboxtoken', $job_object->job['dropboxtoken'] );
|
261 |
-
BackWPup_Option::delete( $job_object->job['jobid'], 'dropboxsecret' );
|
262 |
-
}
|
263 |
-
// set the tokens
|
264 |
$dropbox->setOAuthTokens( $job_object->job['dropboxtoken'] );
|
265 |
|
266 |
//get account info
|
267 |
if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
|
268 |
-
$info = $dropbox->
|
269 |
-
if ( ! empty( $info['
|
270 |
if ( $job_object->is_debug() ) {
|
271 |
-
$user = $info['display_name'] . ' (' . $info['email'] . ')';
|
272 |
-
}
|
273 |
-
|
|
|
274 |
}
|
275 |
$job_object->log( sprintf( __( 'Authenticated with Dropbox of user: %s', 'backwpup' ), $user ) );
|
|
|
276 |
//Quota
|
277 |
if ( $job_object->is_debug() ) {
|
278 |
-
$
|
|
|
279 |
$job_object->log( sprintf( __( '%s available on your Dropbox', 'backwpup' ), size_format( $dropboxfreespase, 2 ) ) );
|
280 |
}
|
281 |
-
}
|
|
|
282 |
$job_object->log( __( 'Not Authenticated with Dropbox!', 'backwpup' ), E_USER_ERROR );
|
283 |
|
284 |
return false;
|
@@ -291,16 +275,18 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
291 |
|
292 |
if ( $job_object->substeps_done < $job_object->backup_filesize ) { //only if upload not complete
|
293 |
$response = $dropbox->upload( $job_object->backup_folder . $job_object->backup_file, $job_object->job['dropboxdir'] . $job_object->backup_file );
|
294 |
-
if ( $response['
|
295 |
if ( ! empty( $job_object->job['jobid'] ) ) {
|
296 |
-
BackWPup_Option::update( $job_object->job['jobid'], 'lastbackupdownloadurl', network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloaddropbox&file=' . ltrim( $response['
|
297 |
}
|
298 |
$job_object->substeps_done = 1 + $job_object->backup_filesize;
|
299 |
-
$job_object->log( sprintf( __( 'Backup transferred to %s', 'backwpup' ),
|
300 |
-
}
|
301 |
-
|
|
|
302 |
$job_object->log( __( 'Uploaded file size and local file size don\'t match.', 'backwpup' ), E_USER_ERROR );
|
303 |
-
}
|
|
|
304 |
$job_object->log(
|
305 |
sprintf(
|
306 |
__( 'Error transfering backup to %s.', 'backwpup' ) . ' ' . $response['error'],
|
@@ -312,28 +298,25 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
312 |
}
|
313 |
}
|
314 |
|
315 |
-
|
316 |
$backupfilelist = array();
|
317 |
$filecounter = 0;
|
318 |
$files = array();
|
319 |
-
$
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
$file = basename( $data['path'] );
|
324 |
if ( $job_object->is_backup_archive( $file ) ) {
|
325 |
-
$backupfilelist[ strtotime( $data['
|
326 |
}
|
327 |
-
$files[ $filecounter ]['folder'] =
|
328 |
-
$files[ $filecounter ]['file'] = $data['
|
329 |
-
$files[ $filecounter ]['filename'] =
|
330 |
-
$files[ $filecounter ]['downloadurl'] = network_admin_url( 'admin.php?page=backwpupbackups&action=downloaddropbox&file=' . $data['
|
331 |
-
$files[ $filecounter ]['filesize'] = $data['
|
332 |
-
$files[ $filecounter ]['time'] = strtotime( $data['
|
333 |
$filecounter ++;
|
334 |
}
|
335 |
}
|
336 |
-
}
|
337 |
if ( $job_object->job['dropboxmaxbackups'] > 0 && is_object( $dropbox ) ) { //Delete old backups
|
338 |
if ( count( $backupfilelist ) > $job_object->job['dropboxmaxbackups'] ) {
|
339 |
ksort( $backupfilelist );
|
@@ -342,17 +325,13 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
342 |
if ( count( $backupfilelist ) < $job_object->job['dropboxmaxbackups'] ) {
|
343 |
break;
|
344 |
}
|
345 |
-
$response = $dropbox->
|
346 |
-
if ( $response['is_deleted'] == 'true' ) {
|
347 |
foreach ( $files as $key => $filedata ) {
|
348 |
if ( $filedata['file'] == '/' . $job_object->job['dropboxdir'] . $file ) {
|
349 |
unset( $files[ $key ] );
|
350 |
}
|
351 |
}
|
352 |
$numdeltefiles ++;
|
353 |
-
} else {
|
354 |
-
$job_object->log( sprintf( __( 'Error while deleting file from Dropbox: %s', 'backwpup' ), $file ), E_USER_ERROR );
|
355 |
-
}
|
356 |
}
|
357 |
if ( $numdeltefiles > 0 ) {
|
358 |
$job_object->log( sprintf( _n( 'One file deleted from Dropbox', '%d files deleted on Dropbox', $numdeltefiles, 'backwpup' ), $numdeltefiles ), E_USER_NOTICE );
|
@@ -360,9 +339,9 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
360 |
}
|
361 |
}
|
362 |
set_site_transient( 'backwpup_' . $job_object->job['jobid'] . '_dropbox', $files, YEAR_IN_SECONDS );
|
363 |
-
}
|
364 |
-
|
365 |
-
|
366 |
return false;
|
367 |
}
|
368 |
$job_object->substeps_done ++;
|
@@ -376,7 +355,6 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
376 |
* @return bool
|
377 |
*/
|
378 |
public function can_run( array $job_settings ) {
|
379 |
-
|
380 |
if ( empty( $job_settings['dropboxtoken'] ) ) {
|
381 |
return false;
|
382 |
}
|
@@ -386,38 +364,30 @@ class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
|
386 |
|
387 |
}
|
388 |
|
389 |
-
|
390 |
/**
|
391 |
-
*
|
392 |
*/
|
393 |
final class BackWPup_Destination_Dropbox_API {
|
394 |
|
395 |
/**
|
396 |
-
*
|
397 |
*/
|
398 |
const API_URL = 'https://api.dropboxapi.com/';
|
399 |
|
400 |
/**
|
401 |
-
*
|
402 |
*/
|
403 |
const API_CONTENT_URL = 'https://content.dropboxapi.com/';
|
404 |
|
405 |
/**
|
406 |
-
*
|
407 |
*/
|
408 |
const API_WWW_URL = 'https://www.dropbox.com/';
|
409 |
|
410 |
/**
|
411 |
-
*
|
412 |
-
*/
|
413 |
-
const API_VERSION_URL = '1/';
|
414 |
-
|
415 |
-
/**
|
416 |
-
* dropbox vars
|
417 |
-
*
|
418 |
-
* @var string
|
419 |
*/
|
420 |
-
|
421 |
|
422 |
/**
|
423 |
* oAuth vars
|
@@ -430,82 +400,80 @@ final class BackWPup_Destination_Dropbox_API {
|
|
430 |
* @var string
|
431 |
*/
|
432 |
private $oauth_app_secret = '';
|
|
|
433 |
/**
|
434 |
* @var string
|
435 |
*/
|
436 |
private $oauth_token = '';
|
437 |
|
|
|
|
|
|
|
|
|
|
|
|
|
438 |
|
439 |
/**
|
440 |
* @param string $boxtype
|
441 |
*
|
442 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
443 |
*/
|
444 |
-
public function __construct( $boxtype = 'dropbox' ) {
|
445 |
-
|
446 |
if ( $boxtype == 'dropbox' ) {
|
447 |
$this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxappkey', base64_decode( "dHZkcjk1MnRhZnM1NmZ2" ) );
|
448 |
$this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxappsecret', base64_decode( "OWV2bDR5MHJvZ2RlYmx1" ) ) );
|
449 |
-
|
450 |
-
|
451 |
$this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxsandboxappkey', base64_decode( "cHVrZmp1a3JoZHR5OTFk" ) );
|
452 |
$this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxsandboxappsecret', base64_decode( "eGNoYzhxdTk5eHE0eWdq" ) ) );
|
453 |
-
$this->root = 'sandbox';
|
454 |
}
|
455 |
|
456 |
if ( empty( $this->oauth_app_key ) || empty( $this->oauth_app_secret ) ) {
|
457 |
throw new BackWPup_Destination_Dropbox_API_Exception( "No App key or App Secret specified." );
|
458 |
}
|
459 |
-
}
|
460 |
-
|
461 |
-
/**
|
462 |
-
* @param $token
|
463 |
-
*
|
464 |
-
* @throws BackWPup_Destination_Dropbox_API_Exception
|
465 |
-
*/
|
466 |
-
public function setOAuthTokens( $token ) {
|
467 |
-
|
468 |
-
if ( empty( $token['access_token'] ) ) {
|
469 |
-
throw new BackWPup_Destination_Dropbox_API_Exception( "No oAuth token specified." );
|
470 |
-
}
|
471 |
|
472 |
-
$this->
|
473 |
}
|
474 |
|
475 |
-
|
476 |
-
|
477 |
-
$url = self::API_URL . self::API_VERSION_URL . 'oauth2/token_from_oauth1';
|
478 |
-
|
479 |
-
return $this->request( $url, array(), 'POST' );
|
480 |
-
}
|
481 |
|
482 |
/**
|
483 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
*/
|
485 |
-
public function
|
|
|
|
|
|
|
486 |
|
487 |
-
$
|
488 |
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
$url = self::API_URL . self::API_VERSION_URL . 'disable_access_token';
|
495 |
|
496 |
-
return $
|
497 |
}
|
498 |
|
499 |
/**
|
|
|
|
|
500 |
* @param $file
|
501 |
* @param string $path
|
502 |
* @param bool $overwrite
|
503 |
*
|
504 |
-
* @return array
|
505 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
506 |
*/
|
507 |
public function upload( $file, $path = '', $overwrite = true ) {
|
508 |
-
|
509 |
$file = str_replace( "\\", "/", $file );
|
510 |
|
511 |
if ( ! is_readable( $file ) ) {
|
@@ -513,10 +481,14 @@ final class BackWPup_Destination_Dropbox_API {
|
|
513 |
}
|
514 |
|
515 |
if ( filesize( $file ) < 5242880 ) { //chunk transfer on bigger uploads
|
516 |
-
$
|
517 |
-
|
518 |
-
|
519 |
-
|
|
|
|
|
|
|
|
|
520 |
}
|
521 |
|
522 |
return $output;
|
@@ -530,10 +502,7 @@ final class BackWPup_Destination_Dropbox_API {
|
|
530 |
* @return array|mixed|string
|
531 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
532 |
*/
|
533 |
-
public function
|
534 |
-
|
535 |
-
$backwpup_job_object = BackWPup_Destination_Dropbox::$backwpup_job_object;
|
536 |
-
|
537 |
$file = str_replace( "\\", "/", $file );
|
538 |
|
539 |
if ( ! is_readable( $file ) ) {
|
@@ -547,33 +516,43 @@ final class BackWPup_Destination_Dropbox_API {
|
|
547 |
throw new BackWPup_Destination_Dropbox_API_Exception( "Can not open source file for transfer." );
|
548 |
}
|
549 |
|
550 |
-
if ( ! isset( $
|
551 |
-
$
|
|
|
|
|
|
|
|
|
|
|
552 |
}
|
553 |
-
if ( ! isset( $
|
554 |
-
$
|
555 |
}
|
556 |
|
557 |
//seek to current position
|
558 |
-
if ( $
|
559 |
-
fseek( $file_handel, $
|
560 |
}
|
561 |
|
562 |
while ( $data = fread( $file_handel, $chunk_size ) ) {
|
563 |
$chunk_upload_start = microtime( true );
|
564 |
-
|
565 |
-
$
|
566 |
-
|
567 |
-
'
|
568 |
-
|
|
|
|
|
|
|
|
|
569 |
$chunk_upload_time = microtime( true ) - $chunk_upload_start;
|
|
|
|
|
570 |
//args for next chunk
|
571 |
-
$
|
572 |
-
|
573 |
-
|
574 |
-
$backwpup_job_object->substeps_done = $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['offset'];
|
575 |
if ( strlen( $data ) == $chunk_size ) {
|
576 |
-
$time_remaining = $
|
577 |
//calc next chunk
|
578 |
if ( $time_remaining < $chunk_upload_time ) {
|
579 |
$chunk_size = floor( $chunk_size / $chunk_upload_time * ( $time_remaining - 3 ) );
|
@@ -586,151 +565,372 @@ final class BackWPup_Destination_Dropbox_API {
|
|
586 |
}
|
587 |
}
|
588 |
}
|
589 |
-
$
|
590 |
//correct position
|
591 |
-
fseek( $file_handel, $
|
592 |
}
|
593 |
|
594 |
fclose( $file_handel );
|
595 |
|
596 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
597 |
|
598 |
-
|
599 |
-
|
600 |
-
'upload_id' => $backwpup_job_object->steps_data[ $backwpup_job_object->step_working ]['uploadid']
|
601 |
-
), 'POST' );
|
602 |
|
603 |
-
|
604 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
605 |
|
606 |
-
|
607 |
}
|
608 |
|
609 |
/**
|
610 |
-
*
|
611 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
612 |
*
|
613 |
-
* @return
|
|
|
614 |
*/
|
615 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
616 |
|
617 |
-
|
618 |
-
if ( ! $echo ) {
|
619 |
-
return $this->request( $url );
|
620 |
-
} else {
|
621 |
-
$this->request( $url, null, 'GET', '', true );
|
622 |
|
623 |
-
|
624 |
-
|
|
|
|
|
|
|
|
|
|
|
625 |
}
|
626 |
|
|
|
|
|
627 |
/**
|
628 |
-
*
|
629 |
-
* @param bool $listContents
|
630 |
-
* @param int $fileLimit
|
631 |
-
* @param string $hash
|
632 |
*
|
633 |
-
* @
|
|
|
|
|
634 |
*/
|
635 |
-
public function
|
|
|
636 |
|
637 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
638 |
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
644 |
}
|
645 |
|
646 |
/**
|
647 |
-
*
|
648 |
*
|
649 |
-
* @
|
|
|
|
|
650 |
*/
|
651 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
652 |
|
653 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
654 |
|
655 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
656 |
}
|
657 |
|
658 |
/**
|
659 |
-
*
|
660 |
*
|
661 |
-
*
|
|
|
|
|
|
|
|
|
662 |
*/
|
663 |
-
public function
|
|
|
664 |
|
665 |
-
|
|
|
|
|
|
|
666 |
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
)
|
|
|
|
|
671 |
}
|
672 |
|
673 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
674 |
|
675 |
-
|
|
|
|
|
676 |
}
|
677 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
678 |
|
679 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
680 |
|
681 |
-
|
682 |
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
|
|
|
|
689 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
690 |
}
|
691 |
|
|
|
692 |
|
693 |
/**
|
694 |
* @param $url
|
695 |
* @param array $args
|
696 |
-
* @param string $
|
697 |
* @param string $data
|
698 |
* @param bool $echo
|
699 |
*
|
700 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
701 |
-
* @internal param null $file
|
702 |
* @return array|mixed|string
|
703 |
*/
|
704 |
-
private function request( $
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
$
|
710 |
-
|
711 |
-
|
712 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
713 |
}
|
714 |
|
715 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
716 |
|
717 |
-
|
718 |
$ch = curl_init();
|
719 |
-
if ( $method == 'POST' ) {
|
720 |
-
curl_setopt( $ch, CURLOPT_POST, true );
|
721 |
-
curl_setopt( $ch, CURLOPT_POSTFIELDS, $args );
|
722 |
curl_setopt( $ch, CURLOPT_URL, $url );
|
723 |
-
|
724 |
-
|
725 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
726 |
$headers[] = 'Content-Type: application/octet-stream';
|
727 |
-
|
728 |
-
|
729 |
-
|
|
|
|
|
|
|
|
|
|
|
730 |
curl_setopt( $ch, CURLOPT_BINARYTRANSFER, true );
|
731 |
-
$
|
732 |
-
curl_setopt( $ch, CURLOPT_URL, $url . $args );
|
733 |
}
|
|
|
734 |
curl_setopt( $ch, CURLOPT_USERAGENT, BackWPup::get_plugin_data( 'User-Agent' ) );
|
735 |
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
736 |
if ( BackWPup::get_plugin_data( 'cacert' ) ) {
|
@@ -768,102 +968,302 @@ final class BackWPup_Destination_Dropbox_API {
|
|
768 |
}
|
769 |
curl_setopt( $ch, CURLOPT_CAINFO, BackWPup::get_plugin_data( 'cacert' ) );
|
770 |
curl_setopt( $ch, CURLOPT_CAPATH, dirname( BackWPup::get_plugin_data( 'cacert' ) ) );
|
771 |
-
}
|
|
|
772 |
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
|
773 |
}
|
774 |
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
|
775 |
$output = '';
|
776 |
if ( $echo ) {
|
777 |
echo curl_exec( $ch );
|
778 |
-
}
|
|
|
779 |
curl_setopt( $ch, CURLOPT_HEADER, true );
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
$output = json_decode( $responce[1], true );
|
784 |
-
}
|
785 |
}
|
786 |
}
|
787 |
$status = curl_getinfo( $ch );
|
788 |
-
|
|
|
|
|
|
|
|
|
|
|
789 |
$wait = 0;
|
790 |
-
if ( preg_match( "/retry-after
|
791 |
$wait = trim( $matches[1] );
|
792 |
}
|
793 |
//only wait if we get a retry-after header.
|
794 |
if ( ! empty( $wait ) ) {
|
795 |
-
trigger_error( sprintf( '(
|
796 |
sleep( $wait );
|
797 |
-
}
|
798 |
-
|
|
|
799 |
}
|
800 |
|
801 |
//redo request
|
802 |
-
return $this->request( $url, $args, $
|
803 |
-
}
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
trigger_error( '(' . $status['http_code'] . ') ' . $output['error'], E_USER_WARNING );
|
809 |
-
|
810 |
-
return false;
|
811 |
-
} elseif ( isset( $output['error'] ) || $status['http_code'] >= 300 || $status['http_code'] < 200 || curl_errno( $ch ) > 0 ) {
|
812 |
-
if ( isset( $output['error'] ) && is_string( $output['error'] ) ) {
|
813 |
-
$args = ( is_array( $args ) ) ? '?' . http_build_query( $args, '', '&' ) : $args;
|
814 |
-
$message = '(' . $status['http_code'] . ') ' . $output['error'] . ' ' . $url . $args;
|
815 |
-
} elseif ( isset( $output['error']['hash'] ) && $output['error']['hash'] != '' ) {
|
816 |
-
$message = (string) '(' . $status['http_code'] . ') ' . $output['error']['hash'] . ' ' . $url . $args;
|
817 |
-
} elseif ( 0 != curl_errno( $ch ) ) {
|
818 |
$message = '(' . curl_errno( $ch ) . ') ' . curl_error( $ch );
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
$message = '(400) Bad input parameter: ' . strip_tags( $responce[1] );
|
823 |
-
}
|
|
|
824 |
$message = '(401) Bad or expired token. This can happen if the user or Dropbox revoked or expired an access token. To fix, you should re-authenticate the user.';
|
825 |
-
}
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
$message = '(
|
831 |
-
}
|
832 |
-
|
833 |
-
} elseif ( $status['http_code'] == 411 ) {
|
834 |
-
$message = '(411) Missing Content-Length header (this endpoint doesn\'t support HTTP chunked transfer encoding).';
|
835 |
-
} elseif ( $status['http_code'] == 415 ) {
|
836 |
-
$message = '(415) The image is invalid and cannot be converted to a thumbnail.';
|
837 |
-
} elseif ( $status['http_code'] == 429 ) {
|
838 |
-
$message = '(429) Your app is making too many requests and is being rate limited. 429s can trigger on a per-app or per-user basis.';
|
839 |
-
} elseif ( $status['http_code'] == 507 ) {
|
840 |
-
$message = '(507) User is over Dropbox storage quota.';
|
841 |
-
} else {
|
842 |
$message = '(' . $status['http_code'] . ') Invalid response.';
|
843 |
}
|
844 |
-
|
845 |
-
|
|
|
|
|
|
|
|
|
846 |
curl_close( $ch );
|
847 |
if ( ! is_array( $output ) ) {
|
848 |
return $responce[1];
|
849 |
-
}
|
|
|
850 |
return $output;
|
851 |
}
|
852 |
}
|
853 |
}
|
854 |
|
855 |
/**
|
856 |
-
*
|
857 |
*
|
858 |
-
* @
|
|
|
|
|
859 |
*/
|
860 |
-
private function
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
|
865 |
return $path;
|
866 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
867 |
}
|
868 |
|
869 |
/**
|
@@ -872,3 +1272,24 @@ final class BackWPup_Destination_Dropbox_API {
|
|
872 |
class BackWPup_Destination_Dropbox_API_Exception extends Exception {
|
873 |
|
874 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
+
* This class allows the user to back up to Dropbox.
|
5 |
+
*
|
6 |
+
* Documentation: https://www.dropbox.com/developers/documentation/http/overview
|
7 |
*/
|
8 |
class BackWPup_Destination_Dropbox extends BackWPup_Destinations {
|
9 |
|
16 |
* @return array
|
17 |
*/
|
18 |
public function option_defaults() {
|
|
|
19 |
return array(
|
20 |
'dropboxtoken' => array(),
|
21 |
'dropboxroot' => 'sandbox',
|
22 |
'dropboxmaxbackups' => 15,
|
23 |
'dropboxsyncnodelete' => true,
|
24 |
+
'dropboxdir' => '/' . trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) )
|
25 |
);
|
26 |
}
|
27 |
|
|
|
28 |
/**
|
29 |
* @param $jobid
|
30 |
*/
|
34 |
//disable token on dropbox
|
35 |
try {
|
36 |
$dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
$dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
|
38 |
+
$dropbox->authTokenRevoke();
|
39 |
+
}
|
40 |
+
catch ( Exception $e ) {
|
41 |
echo '<div id="message" class="error"><p>' . sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ) . '</p></div>';
|
42 |
}
|
43 |
BackWPup_Option::update( $jobid, 'dropboxtoken', array() );
|
44 |
BackWPup_Option::update( $jobid, 'dropboxroot', 'sandbox' );
|
|
|
45 |
}
|
46 |
|
47 |
$dropbox = new BackWPup_Destination_Dropbox_API( 'dropbox' );
|
117 |
<input id="iddropboxmaxbackups" name="dropboxmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'dropboxmaxbackups' ) ); ?>" class="small-text" />
|
118 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
119 |
</label>
|
120 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
121 |
<?php } else { ?>
|
122 |
<label for="iddropboxsyncnodelete">
|
123 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'dropboxsyncnodelete' ), true ); ?> name="dropboxsyncnodelete" id="iddropboxsyncnodelete" />
|
133 |
|
134 |
/**
|
135 |
* @param $jobid
|
|
|
|
|
136 |
*/
|
137 |
public function edit_form_post_save( $jobid ) {
|
138 |
|
143 |
$dropboxtoken = $dropbox->oAuthToken( $_POST['sandbox_code'] );
|
144 |
BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
|
145 |
BackWPup_Option::update( $jobid, 'dropboxroot', 'sandbox' );
|
146 |
+
}
|
147 |
+
catch ( Exception $e ) {
|
148 |
BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
|
149 |
}
|
150 |
}
|
155 |
$dropboxtoken = $dropbox->oAuthToken( $_POST['dropbbox_code'] );
|
156 |
BackWPup_Option::update( $jobid, 'dropboxtoken', $dropboxtoken );
|
157 |
BackWPup_Option::update( $jobid, 'dropboxroot', 'dropbox' );
|
158 |
+
}
|
159 |
+
catch ( Exception $e ) {
|
160 |
BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
|
161 |
}
|
162 |
}
|
165 |
BackWPup_Option::update( $jobid, 'dropboxmaxbackups', ! empty( $_POST['dropboxmaxbackups'] ) ? absint( $_POST['dropboxmaxbackups'] ) : 0 );
|
166 |
|
167 |
$_POST['dropboxdir'] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( sanitize_text_field( $_POST['dropboxdir'] ) ) ) ) );
|
|
|
|
|
|
|
168 |
if ( $_POST['dropboxdir'] === '/' ) {
|
169 |
$_POST['dropboxdir'] = '';
|
170 |
}
|
177 |
* @param $backupfile
|
178 |
*/
|
179 |
public function file_delete( $jobdest, $backupfile ) {
|
|
|
180 |
$files = get_site_transient( 'backwpup_' . strtolower( $jobdest ) );
|
181 |
list( $jobid, $dest ) = explode( '_', $jobdest );
|
182 |
|
183 |
try {
|
184 |
$dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
|
185 |
$dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
|
186 |
+
$dropbox->filesDelete( array( 'path' => $backupfile ) );
|
187 |
+
|
188 |
//update file list
|
189 |
foreach ( $files as $key => $file ) {
|
190 |
if ( is_array( $file ) && $file['file'] == $backupfile ) {
|
192 |
}
|
193 |
}
|
194 |
unset( $dropbox );
|
195 |
+
}
|
196 |
+
catch ( Exception $e ) {
|
197 |
BackWPup_Admin::message( 'DROPBOX: ' . $e->getMessage(), true );
|
198 |
}
|
199 |
|
205 |
* @param $get_file
|
206 |
*/
|
207 |
public function file_download( $jobid, $get_file ) {
|
|
|
208 |
try {
|
209 |
$dropbox = new BackWPup_Destination_Dropbox_API( BackWPup_Option::get( $jobid, 'dropboxroot' ) );
|
210 |
$dropbox->setOAuthTokens( BackWPup_Option::get( $jobid, 'dropboxtoken' ) );
|
211 |
+
$tempLink = $dropbox->filesGetTemporaryLink( array( 'path' => $get_file ) );
|
212 |
+
if ( ! empty( $tempLink['link'] ) ) {
|
213 |
+
header( "Location: " . $tempLink['link'] );
|
214 |
}
|
215 |
die();
|
216 |
+
}
|
217 |
+
catch ( Exception $e ) {
|
218 |
die( $e->getMessage() );
|
219 |
}
|
220 |
}
|
234 |
* @return bool
|
235 |
*/
|
236 |
public function job_run_archive( BackWPup_Job $job_object ) {
|
|
|
237 |
$job_object->substeps_todo = 2 + $job_object->backup_filesize;
|
238 |
if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
|
239 |
$job_object->log( sprintf( __( '%d. Try to send backup file to Dropbox …', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) );
|
240 |
}
|
241 |
|
242 |
try {
|
243 |
+
$dropbox = new BackWPup_Destination_Dropbox_API( $job_object->job['dropboxroot'], $job_object );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
$dropbox->setOAuthTokens( $job_object->job['dropboxtoken'] );
|
245 |
|
246 |
//get account info
|
247 |
if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ]['STEP_TRY'] ) {
|
248 |
+
$info = $dropbox->usersGetCurrentAccount();
|
249 |
+
if ( ! empty( $info['account_id'] ) ) {
|
250 |
if ( $job_object->is_debug() ) {
|
251 |
+
$user = $info['name']['display_name'] . ' (' . $info['email'] . ')';
|
252 |
+
}
|
253 |
+
else {
|
254 |
+
$user = $info['name']['display_name'];
|
255 |
}
|
256 |
$job_object->log( sprintf( __( 'Authenticated with Dropbox of user: %s', 'backwpup' ), $user ) );
|
257 |
+
|
258 |
//Quota
|
259 |
if ( $job_object->is_debug() ) {
|
260 |
+
$quota = $dropbox->usersGetSpaceUsage();
|
261 |
+
$dropboxfreespase = $quota['allocation']['allocated'] - $quota['used'];
|
262 |
$job_object->log( sprintf( __( '%s available on your Dropbox', 'backwpup' ), size_format( $dropboxfreespase, 2 ) ) );
|
263 |
}
|
264 |
+
}
|
265 |
+
else {
|
266 |
$job_object->log( __( 'Not Authenticated with Dropbox!', 'backwpup' ), E_USER_ERROR );
|
267 |
|
268 |
return false;
|
275 |
|
276 |
if ( $job_object->substeps_done < $job_object->backup_filesize ) { //only if upload not complete
|
277 |
$response = $dropbox->upload( $job_object->backup_folder . $job_object->backup_file, $job_object->job['dropboxdir'] . $job_object->backup_file );
|
278 |
+
if ( $response['size'] == $job_object->backup_filesize ) {
|
279 |
if ( ! empty( $job_object->job['jobid'] ) ) {
|
280 |
+
BackWPup_Option::update( $job_object->job['jobid'], 'lastbackupdownloadurl', network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloaddropbox&file=' . ltrim( $response['path_display'], '/' ) . '&jobid=' . $job_object->job['jobid'] );
|
281 |
}
|
282 |
$job_object->substeps_done = 1 + $job_object->backup_filesize;
|
283 |
+
$job_object->log( sprintf( __( 'Backup transferred to %s', 'backwpup' ), $response['path_display'] ), E_USER_NOTICE );
|
284 |
+
}
|
285 |
+
else {
|
286 |
+
if ( $response['size'] != $job_object->backup_filesize ) {
|
287 |
$job_object->log( __( 'Uploaded file size and local file size don\'t match.', 'backwpup' ), E_USER_ERROR );
|
288 |
+
}
|
289 |
+
else {
|
290 |
$job_object->log(
|
291 |
sprintf(
|
292 |
__( 'Error transfering backup to %s.', 'backwpup' ) . ' ' . $response['error'],
|
298 |
}
|
299 |
}
|
300 |
|
|
|
301 |
$backupfilelist = array();
|
302 |
$filecounter = 0;
|
303 |
$files = array();
|
304 |
+
$filesList = $dropbox->listFolder( $job_object->job['dropboxdir'] );
|
305 |
+
foreach ( $filesList as $data ) {
|
306 |
+
if ( $data['.tag'] == 'file' && $job_object->owns_backup_archive( $data['name'] ) == true ) {
|
307 |
+
$file = $data['name'];
|
|
|
308 |
if ( $job_object->is_backup_archive( $file ) ) {
|
309 |
+
$backupfilelist[ strtotime( $data['server_modified'] ) ] = $file;
|
310 |
}
|
311 |
+
$files[ $filecounter ]['folder'] = dirname( $data['path_display'] );
|
312 |
+
$files[ $filecounter ]['file'] = $data['path_display'];
|
313 |
+
$files[ $filecounter ]['filename'] = $data['name'];
|
314 |
+
$files[ $filecounter ]['downloadurl'] = network_admin_url( 'admin.php?page=backwpupbackups&action=downloaddropbox&file=' . $data['path_display'] . '&jobid=' . $job_object->job['jobid'] );
|
315 |
+
$files[ $filecounter ]['filesize'] = $data['size'];
|
316 |
+
$files[ $filecounter ]['time'] = strtotime( $data['server_modified'] ) + ( get_option( 'gmt_offset' ) * 3600 );
|
317 |
$filecounter ++;
|
318 |
}
|
319 |
}
|
|
|
320 |
if ( $job_object->job['dropboxmaxbackups'] > 0 && is_object( $dropbox ) ) { //Delete old backups
|
321 |
if ( count( $backupfilelist ) > $job_object->job['dropboxmaxbackups'] ) {
|
322 |
ksort( $backupfilelist );
|
325 |
if ( count( $backupfilelist ) < $job_object->job['dropboxmaxbackups'] ) {
|
326 |
break;
|
327 |
}
|
328 |
+
$response = $dropbox->filesDelete( array( 'path' => $job_object->job['dropboxdir'] . $file ) ); //delete files on Cloud
|
|
|
329 |
foreach ( $files as $key => $filedata ) {
|
330 |
if ( $filedata['file'] == '/' . $job_object->job['dropboxdir'] . $file ) {
|
331 |
unset( $files[ $key ] );
|
332 |
}
|
333 |
}
|
334 |
$numdeltefiles ++;
|
|
|
|
|
|
|
335 |
}
|
336 |
if ( $numdeltefiles > 0 ) {
|
337 |
$job_object->log( sprintf( _n( 'One file deleted from Dropbox', '%d files deleted on Dropbox', $numdeltefiles, 'backwpup' ), $numdeltefiles ), E_USER_NOTICE );
|
339 |
}
|
340 |
}
|
341 |
set_site_transient( 'backwpup_' . $job_object->job['jobid'] . '_dropbox', $files, YEAR_IN_SECONDS );
|
342 |
+
}
|
343 |
+
catch ( Exception $e ) {
|
344 |
+
$job_object->log( sprintf( __( 'Dropbox API: %s', 'backwpup' ), $e->getMessage() ), $e->getFile(), $e->getLine(), E_USER_ERROR );
|
345 |
return false;
|
346 |
}
|
347 |
$job_object->substeps_done ++;
|
355 |
* @return bool
|
356 |
*/
|
357 |
public function can_run( array $job_settings ) {
|
|
|
358 |
if ( empty( $job_settings['dropboxtoken'] ) ) {
|
359 |
return false;
|
360 |
}
|
364 |
|
365 |
}
|
366 |
|
|
|
367 |
/**
|
368 |
+
* Class for communicating with Dropbox API V2.
|
369 |
*/
|
370 |
final class BackWPup_Destination_Dropbox_API {
|
371 |
|
372 |
/**
|
373 |
+
* URL to Dropbox API endpoint.
|
374 |
*/
|
375 |
const API_URL = 'https://api.dropboxapi.com/';
|
376 |
|
377 |
/**
|
378 |
+
* URL to Dropbox content endpoint.
|
379 |
*/
|
380 |
const API_CONTENT_URL = 'https://content.dropboxapi.com/';
|
381 |
|
382 |
/**
|
383 |
+
* URL to Dropbox for authentication.
|
384 |
*/
|
385 |
const API_WWW_URL = 'https://www.dropbox.com/';
|
386 |
|
387 |
/**
|
388 |
+
* API version.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
389 |
*/
|
390 |
+
const API_VERSION_URL = '2/';
|
391 |
|
392 |
/**
|
393 |
* oAuth vars
|
400 |
* @var string
|
401 |
*/
|
402 |
private $oauth_app_secret = '';
|
403 |
+
|
404 |
/**
|
405 |
* @var string
|
406 |
*/
|
407 |
private $oauth_token = '';
|
408 |
|
409 |
+
/**
|
410 |
+
* Job object for logging.
|
411 |
+
*
|
412 |
+
* @var BackWPup_Job
|
413 |
+
*/
|
414 |
+
private $job_object;
|
415 |
|
416 |
/**
|
417 |
* @param string $boxtype
|
418 |
*
|
419 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
420 |
*/
|
421 |
+
public function __construct( $boxtype = 'dropbox', BackWPup_Job $job_object = null ) {
|
|
|
422 |
if ( $boxtype == 'dropbox' ) {
|
423 |
$this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxappkey', base64_decode( "dHZkcjk1MnRhZnM1NmZ2" ) );
|
424 |
$this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxappsecret', base64_decode( "OWV2bDR5MHJvZ2RlYmx1" ) ) );
|
425 |
+
}
|
426 |
+
else {
|
427 |
$this->oauth_app_key = get_site_option( 'backwpup_cfg_dropboxsandboxappkey', base64_decode( "cHVrZmp1a3JoZHR5OTFk" ) );
|
428 |
$this->oauth_app_secret = BackWPup_Encryption::decrypt( get_site_option( 'backwpup_cfg_dropboxsandboxappsecret', base64_decode( "eGNoYzhxdTk5eHE0eWdq" ) ) );
|
|
|
429 |
}
|
430 |
|
431 |
if ( empty( $this->oauth_app_key ) || empty( $this->oauth_app_secret ) ) {
|
432 |
throw new BackWPup_Destination_Dropbox_API_Exception( "No App key or App Secret specified." );
|
433 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
434 |
|
435 |
+
$this->job_object = $job_object;
|
436 |
}
|
437 |
|
438 |
+
// Helper methods
|
|
|
|
|
|
|
|
|
|
|
439 |
|
440 |
/**
|
441 |
+
* List a folder
|
442 |
+
*
|
443 |
+
* This is a helper method to use filesListFolder and
|
444 |
+
* filesListFolderContinue to construct an array of files within a given
|
445 |
+
* folder path.
|
446 |
+
*
|
447 |
+
* @param string $path
|
448 |
+
*
|
449 |
+
* @return array
|
450 |
*/
|
451 |
+
public function listFolder( $path ) {
|
452 |
+
$files = array();
|
453 |
+
$result = $this->filesListFolder( array( 'path' => $path ) );
|
454 |
+
$files = array_merge( $files, $result['entries'] );
|
455 |
|
456 |
+
$args = array( 'cursor' => $result['cursor'] );
|
457 |
|
458 |
+
while ( $result['has_more'] == true ) {
|
459 |
+
$result = $this->filesListFolderContinue( $args );
|
460 |
+
$files = array_merge( $files, $result['entries'] );
|
461 |
+
}
|
|
|
|
|
462 |
|
463 |
+
return $files;
|
464 |
}
|
465 |
|
466 |
/**
|
467 |
+
* Uploads a file to Dropbox.
|
468 |
+
*
|
469 |
* @param $file
|
470 |
* @param string $path
|
471 |
* @param bool $overwrite
|
472 |
*
|
473 |
+
* @return array
|
474 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
475 |
*/
|
476 |
public function upload( $file, $path = '', $overwrite = true ) {
|
|
|
477 |
$file = str_replace( "\\", "/", $file );
|
478 |
|
479 |
if ( ! is_readable( $file ) ) {
|
481 |
}
|
482 |
|
483 |
if ( filesize( $file ) < 5242880 ) { //chunk transfer on bigger uploads
|
484 |
+
$output = $this->filesUpload( array(
|
485 |
+
'contents' => file_get_contents( $file ),
|
486 |
+
'path' => $path,
|
487 |
+
'mode' => ( $overwrite ) ? 'overwrite' : 'add',
|
488 |
+
) );
|
489 |
+
}
|
490 |
+
else {
|
491 |
+
$output = $this->multipartUpload( $file, $path, $overwrite );
|
492 |
}
|
493 |
|
494 |
return $output;
|
502 |
* @return array|mixed|string
|
503 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
504 |
*/
|
505 |
+
public function multipartUpload( $file, $path = '', $overwrite = true ) {
|
|
|
|
|
|
|
506 |
$file = str_replace( "\\", "/", $file );
|
507 |
|
508 |
if ( ! is_readable( $file ) ) {
|
516 |
throw new BackWPup_Destination_Dropbox_API_Exception( "Can not open source file for transfer." );
|
517 |
}
|
518 |
|
519 |
+
if ( ! isset( $this->job_object->steps_data[ $this->job_object->step_working ]['uploadid'] ) ) {
|
520 |
+
$this->job_object->log( __( 'Beginning new file upload session', 'backwpup' ) );
|
521 |
+
$session = $this->filesUploadSessionStart();
|
522 |
+
$this->job_object->steps_data[ $this->job_object->step_working ]['uploadid'] = $session['session_id'];
|
523 |
+
}
|
524 |
+
if ( ! isset( $this->job_object->steps_data[ $this->job_object->step_working ]['offset'] ) ) {
|
525 |
+
$this->job_object->steps_data[ $this->job_object->step_working ]['offset'] = 0;
|
526 |
}
|
527 |
+
if ( ! isset( $this->job_object->steps_data[ $this->job_object->step_working ]['totalread'] ) ) {
|
528 |
+
$this->job_object->steps_data[ $this->job_object->step_working ]['totalread'] = 0;
|
529 |
}
|
530 |
|
531 |
//seek to current position
|
532 |
+
if ( $this->job_object->steps_data[ $this->job_object->step_working ]['offset'] > 0 ) {
|
533 |
+
fseek( $file_handel, $this->job_object->steps_data[ $this->job_object->step_working ]['offset'] );
|
534 |
}
|
535 |
|
536 |
while ( $data = fread( $file_handel, $chunk_size ) ) {
|
537 |
$chunk_upload_start = microtime( true );
|
538 |
+
|
539 |
+
$this->job_object->log( sprintf( __( 'Uploading %s of data', 'backwpup' ), size_format( strlen( $data ) ) ) );
|
540 |
+
$this->filesUploadSessionAppendV2( array(
|
541 |
+
'contents' => $data,
|
542 |
+
'cursor' => array(
|
543 |
+
'session_id' => $this->job_object->steps_data[ $this->job_object->step_working ]['uploadid'],
|
544 |
+
'offset' => $this->job_object->steps_data[ $this->job_object->step_working ]['offset']
|
545 |
+
),
|
546 |
+
) );
|
547 |
$chunk_upload_time = microtime( true ) - $chunk_upload_start;
|
548 |
+
$this->job_object->steps_data[ $this->job_object->step_working ]['totalread'] += strlen( $data );
|
549 |
+
|
550 |
//args for next chunk
|
551 |
+
$this->job_object->steps_data[ $this->job_object->step_working ]['offset'] += $chunk_size;
|
552 |
+
if ( $this->job_object->job['backuptype'] === 'archive' ) {
|
553 |
+
$this->job_object->substeps_done = $this->job_object->steps_data[ $this->job_object->step_working ]['offset'];
|
|
|
554 |
if ( strlen( $data ) == $chunk_size ) {
|
555 |
+
$time_remaining = $this->job_object->do_restart_time();
|
556 |
//calc next chunk
|
557 |
if ( $time_remaining < $chunk_upload_time ) {
|
558 |
$chunk_size = floor( $chunk_size / $chunk_upload_time * ( $time_remaining - 3 ) );
|
565 |
}
|
566 |
}
|
567 |
}
|
568 |
+
$this->job_object->update_working_data();
|
569 |
//correct position
|
570 |
+
fseek( $file_handel, $this->job_object->steps_data[ $this->job_object->step_working ]['offset'] );
|
571 |
}
|
572 |
|
573 |
fclose( $file_handel );
|
574 |
|
575 |
+
$this->job_object->log( sprintf( __( 'Finishing upload session with a total of %s uploaded', 'backwpup' ), size_format( $this->job_object->steps_data[ $this->job_object->step_working ]['totalread'] ) ) );
|
576 |
+
$response = $this->filesUploadSessionFinish( array(
|
577 |
+
'cursor' => array(
|
578 |
+
'session_id' => $this->job_object->steps_data[ $this->job_object->step_working ]['uploadid'],
|
579 |
+
'offset' => $this->job_object->steps_data[ $this->job_object->step_working ]['totalread'],
|
580 |
+
),
|
581 |
+
'commit' => array(
|
582 |
+
'path' => $path,
|
583 |
+
'mode' => ( $overwrite ) ? 'overwrite' : 'add',
|
584 |
+
),
|
585 |
+
) );
|
586 |
+
|
587 |
+
unset( $this->job_object->steps_data[ $this->job_object->step_working ]['uploadid'] );
|
588 |
+
unset( $this->job_object->steps_data[ $this->job_object->step_working ]['offset'] );
|
589 |
|
590 |
+
return $response;
|
591 |
+
}
|
|
|
|
|
592 |
|
593 |
+
// Authentication
|
594 |
+
|
595 |
+
/**
|
596 |
+
* Set the oauth tokens for this request.
|
597 |
+
*
|
598 |
+
* @param $token
|
599 |
+
*
|
600 |
+
* @throws BackWPup_Destination_Dropbox_API_Exception
|
601 |
+
*/
|
602 |
+
public function setOAuthTokens( $token ) {
|
603 |
+
if ( empty( $token['access_token'] ) ) {
|
604 |
+
throw new BackWPup_Destination_Dropbox_API_Exception( "No oAuth token specified." );
|
605 |
+
}
|
606 |
|
607 |
+
$this->oauth_token = $token;
|
608 |
}
|
609 |
|
610 |
/**
|
611 |
+
* Returns the URL to authorize the user.
|
612 |
+
*
|
613 |
+
* @return string The authorization URL
|
614 |
+
*/
|
615 |
+
public function oAuthAuthorize() {
|
616 |
+
return self::API_WWW_URL . 'oauth2/authorize?response_type=code&client_id=' . $this->oauth_app_key;
|
617 |
+
}
|
618 |
+
|
619 |
+
/**
|
620 |
+
* Tkes the oauth code and returns the access token.
|
621 |
+
*
|
622 |
+
* @param string $code The oauth code
|
623 |
*
|
624 |
+
* @return array An array including the access token, account ID, and
|
625 |
+
* other information.
|
626 |
*/
|
627 |
+
public function oAuthToken( $code ) {
|
628 |
+
return $this->request( 'oauth2/token', array(
|
629 |
+
'code' => trim( $code ),
|
630 |
+
'grant_type' => 'authorization_code',
|
631 |
+
'client_id' => $this->oauth_app_key,
|
632 |
+
'client_secret' => $this->oauth_app_secret
|
633 |
+
), 'oauth' );
|
634 |
+
}
|
635 |
|
636 |
+
// Auth Endpoints
|
|
|
|
|
|
|
|
|
637 |
|
638 |
+
/**
|
639 |
+
* Revokes the auth token.
|
640 |
+
*
|
641 |
+
* @return array
|
642 |
+
*/
|
643 |
+
public function authTokenRevoke() {
|
644 |
+
return $this->request( 'auth/token/revoke' );
|
645 |
}
|
646 |
|
647 |
+
// Files Endpoints
|
648 |
+
|
649 |
/**
|
650 |
+
* Deletes a file.
|
|
|
|
|
|
|
651 |
*
|
652 |
+
* @param array $args An array of arguments
|
653 |
+
*
|
654 |
+
* @return array Information on the deleted file
|
655 |
*/
|
656 |
+
public function filesDelete( $args ) {
|
657 |
+
$args['path'] = $this->formatPath( $args['path'] );
|
658 |
|
659 |
+
try {
|
660 |
+
return $this->request( 'files/delete', $args );
|
661 |
+
}
|
662 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
663 |
+
$this->handleFilesDeleteError( $e->getError() );
|
664 |
+
}
|
665 |
+
}
|
666 |
|
667 |
+
/**
|
668 |
+
* Gets the metadata of a file.
|
669 |
+
*
|
670 |
+
* @param array $args An array of arguments
|
671 |
+
*
|
672 |
+
* @return array The file's metadata
|
673 |
+
*/
|
674 |
+
public function filesGetMetadata( $args ) {
|
675 |
+
$args['path'] = $this->formatPath( $args['path'] );
|
676 |
+
try {
|
677 |
+
return $this->request( 'files/get_metadata', $args );
|
678 |
+
}
|
679 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
680 |
+
$this->handleFilesGetMetadataError( $e->error() );
|
681 |
+
}
|
682 |
}
|
683 |
|
684 |
/**
|
685 |
+
* Gets a temporary link from Dropbox to access the file.
|
686 |
*
|
687 |
+
* @param array $args An array of arguments
|
688 |
+
*
|
689 |
+
* @return array Information on the file and link
|
690 |
*/
|
691 |
+
public function filesGetTemporaryLink( $args ) {
|
692 |
+
$args['path'] = $this->formatPath( $args['path'] );
|
693 |
+
try {
|
694 |
+
return $this->request( 'files/get_temporary_link', $args );
|
695 |
+
}
|
696 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
697 |
+
$this->handleFilesGetTemporaryLinkError( $e->getError() );
|
698 |
+
}
|
699 |
+
}
|
700 |
|
701 |
+
/**
|
702 |
+
* Lists all the files within a folder.
|
703 |
+
*
|
704 |
+
* @param array $args An array of arguments
|
705 |
+
*
|
706 |
+
* @return array A list of files
|
707 |
+
*/
|
708 |
+
public function filesListFolder( $args ) {
|
709 |
+
$args['path'] = $this->formatPath( $args['path'] );
|
710 |
+
try {
|
711 |
+
Return $this->request( 'files/list_folder', $args );
|
712 |
+
}
|
713 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
714 |
+
$this->handleFilesListFolderError( $e->error() );
|
715 |
+
}
|
716 |
+
}
|
717 |
|
718 |
+
/**
|
719 |
+
* Continue to list more files.
|
720 |
+
*
|
721 |
+
* When a folder has a lot of files, the API won't return all at once.
|
722 |
+
* So this method is to fetch more of them.
|
723 |
+
*
|
724 |
+
* @param array $args An array of arguments
|
725 |
+
*
|
726 |
+
* @return array An array of files
|
727 |
+
*/
|
728 |
+
public function filesListFolderContinue( $args ) {
|
729 |
+
try {
|
730 |
+
Return $this->request( 'files/list_folder/continue', $args );
|
731 |
+
}
|
732 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
733 |
+
$this->handleFilesListFolderContinueError( $e->error() );
|
734 |
+
}
|
735 |
}
|
736 |
|
737 |
/**
|
738 |
+
* Uploads a file to Dropbox.
|
739 |
*
|
740 |
+
* The file must be no greater than 150 MB.
|
741 |
+
*
|
742 |
+
* @param array $args An array of arguments
|
743 |
+
*
|
744 |
+
* @return array The uploaded file's information.
|
745 |
*/
|
746 |
+
public function filesUpload( $args ) {
|
747 |
+
$args['path'] = $this->formatPath( $args['path'] );
|
748 |
|
749 |
+
if ( isset( $args['client_modified'] )
|
750 |
+
&& $args['client_modified'] instanceof DateTime ) {
|
751 |
+
$args['client_modified'] = $args['client_modified']->format( 'Y-m-d\TH:m:s\Z' );
|
752 |
+
}
|
753 |
|
754 |
+
try {
|
755 |
+
return $this->request( 'files/upload', $args, 'upload' );
|
756 |
+
}
|
757 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
758 |
+
$this->handleFilesUploadError( $e->getError() );
|
759 |
+
}
|
760 |
}
|
761 |
|
762 |
+
/**
|
763 |
+
* Append more data to an uploading file
|
764 |
+
*
|
765 |
+
* @param array $args An array of arguments
|
766 |
+
*/
|
767 |
+
public function filesUploadSessionAppendV2( $args ) {
|
768 |
+
try {
|
769 |
+
return $this->request( 'files/upload_session/append_v2', $args,
|
770 |
+
'upload' );
|
771 |
+
}
|
772 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
773 |
+
$error = $e->getError();
|
774 |
+
|
775 |
+
// See if we can fix the error first
|
776 |
+
if ( $error['.tag'] == 'incorrect_offset' ) {
|
777 |
+
$args['cursor']['offset'] = $error['correct_offset'];
|
778 |
+
return $this->request( 'files/upload_session/append_v2', $args,
|
779 |
+
'upload' );
|
780 |
+
}
|
781 |
|
782 |
+
// Otherwise, can't fix
|
783 |
+
$this->handleFilesUploadSessionLookupError( $error );
|
784 |
+
}
|
785 |
}
|
786 |
|
787 |
+
/**
|
788 |
+
* Finish an upload session.
|
789 |
+
*
|
790 |
+
* @param array $args
|
791 |
+
*
|
792 |
+
* @return array Information on the uploaded file
|
793 |
+
*/
|
794 |
+
public function filesUploadSessionFinish( $args ) {
|
795 |
+
$args['commit']['path'] = $this->formatPath( $args['commit']['path'] );;
|
796 |
+
try {
|
797 |
+
return $this->request( 'files/upload_session/finish', $args, 'upload' );
|
798 |
+
}
|
799 |
+
catch ( BackWPup_Destination_Dropbox_API_Request_Exception $e ) {
|
800 |
+
$error = $e->getError();
|
801 |
+
if ( $error['.tag'] == 'lookup_failed' ) {
|
802 |
+
if ( $error['lookup_failed']['.tag'] == 'incorrect_offset' ) {
|
803 |
+
$args['cursor']['offset'] = $error['lookup_failed']['correct_offset'];
|
804 |
+
return $this->request( 'files/upload_session/finish', $args, 'upload' );
|
805 |
+
}
|
806 |
+
}
|
807 |
+
$this->handleFilesUploadSessionFinishError( $e->getError() );
|
808 |
+
}
|
809 |
+
}
|
810 |
|
811 |
+
/**
|
812 |
+
* Starts an upload session.
|
813 |
+
*
|
814 |
+
* When a file larger than 150 MB needs to be uploaded, then this API
|
815 |
+
* endpoint is used to start a session to allow the file to be uploaded in
|
816 |
+
* chunks.
|
817 |
+
*
|
818 |
+
* @param array $args
|
819 |
+
*
|
820 |
+
* @return array An array containing the session's ID.
|
821 |
+
*/
|
822 |
+
public function filesUploadSessionStart( $args = array() ) {
|
823 |
+
return $this->request( 'files/upload_session/start', $args, 'upload' );
|
824 |
+
}
|
825 |
|
826 |
+
// Users endpoints
|
827 |
|
828 |
+
/**
|
829 |
+
* Get user's current account info.
|
830 |
+
*
|
831 |
+
* @return array
|
832 |
+
*/
|
833 |
+
public function usersGetCurrentAccount() {
|
834 |
+
return $this->request( 'users/get_current_account' );
|
835 |
+
}
|
836 |
|
837 |
+
/**
|
838 |
+
* Get quota info for this user.
|
839 |
+
*
|
840 |
+
* @return array
|
841 |
+
*/
|
842 |
+
public function usersGetSpaceUsage() {
|
843 |
+
return $this->request( 'users/get_space_usage' );
|
844 |
}
|
845 |
|
846 |
+
// Private functions
|
847 |
|
848 |
/**
|
849 |
* @param $url
|
850 |
* @param array $args
|
851 |
+
* @param string $endpointFormat
|
852 |
* @param string $data
|
853 |
* @param bool $echo
|
854 |
*
|
855 |
* @throws BackWPup_Destination_Dropbox_API_Exception
|
|
|
856 |
* @return array|mixed|string
|
857 |
*/
|
858 |
+
private function request( $endpoint, $args = array(), $endpointFormat = 'rpc', $echo = false ) {
|
859 |
+
|
860 |
+
// Get complete URL
|
861 |
+
switch ( $endpointFormat ) {
|
862 |
+
case 'oauth':
|
863 |
+
$url = self::API_URL . $endpoint;
|
864 |
+
break;
|
865 |
+
|
866 |
+
case 'rpc':
|
867 |
+
$url = self::API_URL . self::API_VERSION_URL . $endpoint;
|
868 |
+
break;
|
869 |
+
|
870 |
+
case 'upload':
|
871 |
+
case 'download':
|
872 |
+
$url = self::API_CONTENT_URL . self::API_VERSION_URL . $endpoint;
|
873 |
+
break;
|
874 |
}
|
875 |
|
876 |
+
if ( $this->job_object && $this->job_object->is_debug() && $endpointFormat != 'oauth' ) {
|
877 |
+
$message = 'Call to ' . $endpoint;
|
878 |
+
$parameters = $args;
|
879 |
+
if ( isset( $parameters['contents'] ) ) {
|
880 |
+
$message .= ', with ' . size_format( strlen( $parameters['contents'] ) ) . ' of data';
|
881 |
+
unset( $parameters['contents'] );
|
882 |
+
}
|
883 |
+
if ( ! empty( $parameters ) ) {
|
884 |
+
$message .= ', with parameters: ' . json_encode( $parameters );
|
885 |
+
}
|
886 |
+
$this->job_object->log( $message );
|
887 |
+
}
|
888 |
|
889 |
+
// Build cURL Request
|
890 |
$ch = curl_init();
|
|
|
|
|
|
|
891 |
curl_setopt( $ch, CURLOPT_URL, $url );
|
892 |
+
curl_setopt( $ch, CURLOPT_POST, true );
|
893 |
+
|
894 |
+
$headers[] = 'Expect:';
|
895 |
+
|
896 |
+
if ( $endpointFormat != 'oauth' ) {
|
897 |
+
$headers[] = 'Authorization: Bearer ' . $this->oauth_token['access_token'];
|
898 |
+
}
|
899 |
+
|
900 |
+
if ( $endpointFormat == 'oauth' ) {
|
901 |
+
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $args ) );
|
902 |
+
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
|
903 |
+
}
|
904 |
+
elseif ( $endpointFormat == 'rpc' ) {
|
905 |
+
if ( ! empty( $args ) ) {
|
906 |
+
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $args ) );
|
907 |
+
}
|
908 |
+
else {
|
909 |
+
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( null ) );
|
910 |
+
}
|
911 |
+
$headers[] = 'Content-Type: application/json';
|
912 |
+
}
|
913 |
+
elseif ( $endpointFormat == 'upload' ) {
|
914 |
+
if ( isset( $args['contents'] ) ) {
|
915 |
+
curl_setopt( $ch, CURLOPT_POSTFIELDS, $args['contents'] );
|
916 |
+
unset( $args['contents'] );
|
917 |
+
}
|
918 |
+
else {
|
919 |
+
curl_setopt( $ch, CURLOPT_POSTFIELDS, '' );
|
920 |
+
}
|
921 |
$headers[] = 'Content-Type: application/octet-stream';
|
922 |
+
if ( ! empty( $args ) ) {
|
923 |
+
$headers[] = 'Dropbox-API-Arg: ' . json_encode( $args );
|
924 |
+
}
|
925 |
+
else {
|
926 |
+
$headers[] = 'Dropbox-API-Arg: {}';
|
927 |
+
}
|
928 |
+
}
|
929 |
+
else {
|
930 |
curl_setopt( $ch, CURLOPT_BINARYTRANSFER, true );
|
931 |
+
$headers[] = 'Dropbox-API-Arg: ' . json_encode( $args );
|
|
|
932 |
}
|
933 |
+
|
934 |
curl_setopt( $ch, CURLOPT_USERAGENT, BackWPup::get_plugin_data( 'User-Agent' ) );
|
935 |
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
936 |
if ( BackWPup::get_plugin_data( 'cacert' ) ) {
|
968 |
}
|
969 |
curl_setopt( $ch, CURLOPT_CAINFO, BackWPup::get_plugin_data( 'cacert' ) );
|
970 |
curl_setopt( $ch, CURLOPT_CAPATH, dirname( BackWPup::get_plugin_data( 'cacert' ) ) );
|
971 |
+
}
|
972 |
+
else {
|
973 |
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
|
974 |
}
|
975 |
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
|
976 |
$output = '';
|
977 |
if ( $echo ) {
|
978 |
echo curl_exec( $ch );
|
979 |
+
}
|
980 |
+
else {
|
981 |
curl_setopt( $ch, CURLOPT_HEADER, true );
|
982 |
+
$responce = explode( "\r\n\r\n", curl_exec( $ch ), 2 );
|
983 |
+
if ( ! empty( $responce[1] ) ) {
|
984 |
+
$output = json_decode( $responce[1], true );
|
|
|
|
|
985 |
}
|
986 |
}
|
987 |
$status = curl_getinfo( $ch );
|
988 |
+
|
989 |
+
// Handle error codes
|
990 |
+
// If 409 (endpoint-specific error), let the calling method handle it
|
991 |
+
|
992 |
+
// Code 429 = rate limited
|
993 |
+
if ( $status['http_code'] == 429 ) {
|
994 |
$wait = 0;
|
995 |
+
if ( preg_match( "/retry-after:\s*(.*?)\r/i", $responce[0], $matches ) ) {
|
996 |
$wait = trim( $matches[1] );
|
997 |
}
|
998 |
//only wait if we get a retry-after header.
|
999 |
if ( ! empty( $wait ) ) {
|
1000 |
+
trigger_error( sprintf( '(429) Your app is making too many requests and is being rate limited. Error 429 can be triggered on a per-app or per-user basis. Wait for %d seconds.', $wait ), E_USER_WARNING );
|
1001 |
sleep( $wait );
|
1002 |
+
}
|
1003 |
+
else {
|
1004 |
+
throw new BackWPup_Destination_Dropbox_API_Exception( '(429) This indicates a transient server error.' );
|
1005 |
}
|
1006 |
|
1007 |
//redo request
|
1008 |
+
return $this->request( $url, $args, $endpointFormat, $data, $echo );
|
1009 |
+
}
|
1010 |
+
// We can't really handle anything else, so throw it back to the caller
|
1011 |
+
elseif ( isset( $output['error'] ) || $status['http_code'] >= 400 || curl_errno( $ch ) > 0 ) {
|
1012 |
+
$code = $status['http_code'];
|
1013 |
+
if ( curl_errno( $ch ) != 0 ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1014 |
$message = '(' . curl_errno( $ch ) . ') ' . curl_error( $ch );
|
1015 |
+
$code = 0;
|
1016 |
+
}
|
1017 |
+
elseif ( $status['http_code'] == 400 ) {
|
1018 |
$message = '(400) Bad input parameter: ' . strip_tags( $responce[1] );
|
1019 |
+
}
|
1020 |
+
elseif ( $status['http_code'] == 401 ) {
|
1021 |
$message = '(401) Bad or expired token. This can happen if the user or Dropbox revoked or expired an access token. To fix, you should re-authenticate the user.';
|
1022 |
+
}
|
1023 |
+
elseif ( $status['http_code'] == 409 ) {
|
1024 |
+
$message = $output['error_summary'];
|
1025 |
+
}
|
1026 |
+
elseif ( $status['http_code'] >= 500 ) {
|
1027 |
+
$message = '(' . $status['http_code'] . ') There is an error on the Dropbox server.';
|
1028 |
+
}
|
1029 |
+
else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1030 |
$message = '(' . $status['http_code'] . ') Invalid response.';
|
1031 |
}
|
1032 |
+
if ( $this->job_object && $this->job_object->is_debug() ) {
|
1033 |
+
$this->job_object->log( 'Response with header: ' . $responce[0] );
|
1034 |
+
}
|
1035 |
+
throw new BackWPup_Destination_Dropbox_API_Request_Exception( $message, $code, null, isset( $output['error'] ) ? $output['error'] : null );
|
1036 |
+
}
|
1037 |
+
else {
|
1038 |
curl_close( $ch );
|
1039 |
if ( ! is_array( $output ) ) {
|
1040 |
return $responce[1];
|
1041 |
+
}
|
1042 |
+
else {
|
1043 |
return $output;
|
1044 |
}
|
1045 |
}
|
1046 |
}
|
1047 |
|
1048 |
/**
|
1049 |
+
* Formats a path to be valid for Dropbox.
|
1050 |
*
|
1051 |
+
* @param string $path
|
1052 |
+
*
|
1053 |
+
* @return string The formatted path
|
1054 |
*/
|
1055 |
+
private function formatPath( $path ) {
|
1056 |
+
if ( substr( $path, 0, 1 ) != '/' ) {
|
1057 |
+
$path = "/$path";
|
1058 |
+
}
|
1059 |
|
1060 |
return $path;
|
1061 |
}
|
1062 |
+
|
1063 |
+
// Error Handlers
|
1064 |
+
|
1065 |
+
private function handleFilesDeleteError( $error ) {
|
1066 |
+
switch ( $error['.tag'] ) {
|
1067 |
+
case 'path_lookup':
|
1068 |
+
$this->handleFilesLookupError( $error['path_lookup'] );
|
1069 |
+
break;
|
1070 |
+
|
1071 |
+
case 'path_write':
|
1072 |
+
$this->handleFilesWriteError( $error['path_write'] );
|
1073 |
+
break;
|
1074 |
+
|
1075 |
+
case 'other':
|
1076 |
+
trigger_error( 'Could not delete file.', E_USER_WARNING );
|
1077 |
+
break;
|
1078 |
+
}
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
private function handleFilesGetMetadataError( $error ) {
|
1082 |
+
switch ( $error['.tag'] ) {
|
1083 |
+
case 'path':
|
1084 |
+
$this->handleFilesLookupError( $error['path'] );
|
1085 |
+
break;
|
1086 |
+
|
1087 |
+
case 'other':
|
1088 |
+
trigger_error( 'Cannot look up file metadata.', E_USER_WARNING );
|
1089 |
+
break;
|
1090 |
+
}
|
1091 |
+
}
|
1092 |
+
|
1093 |
+
private function handleFilesGetTemporaryLinkError( $error ) {
|
1094 |
+
switch ( $error['.tag'] ) {
|
1095 |
+
case 'path':
|
1096 |
+
$this->handleFilesLookupError( $error['path'] );
|
1097 |
+
break;
|
1098 |
+
|
1099 |
+
case 'other':
|
1100 |
+
trigger_error( 'Cannot get temporary link.', E_USER_WARNING );
|
1101 |
+
break;
|
1102 |
+
}
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
private function handleFilesListFolderError( $error ) {
|
1106 |
+
switch ( $error['.tag'] ) {
|
1107 |
+
case 'path':
|
1108 |
+
$this->handleFilesLookupError( $error['path'] );
|
1109 |
+
break;
|
1110 |
+
|
1111 |
+
case 'other':
|
1112 |
+
trigger_error( 'Cannot list files in folder.', E_USER_WARNING );
|
1113 |
+
break;
|
1114 |
+
}
|
1115 |
+
}
|
1116 |
+
|
1117 |
+
private function handleFilesListFolderContinueError( $error ) {
|
1118 |
+
switch ( $error['.tag'] ) {
|
1119 |
+
case 'path':
|
1120 |
+
$this->handleFilesLookupError( $error['path'] );
|
1121 |
+
break;
|
1122 |
+
|
1123 |
+
case 'reset':
|
1124 |
+
trigger_error( 'This cursor has been invalidated.', E_USER_WARNING );
|
1125 |
+
break;
|
1126 |
+
|
1127 |
+
case 'other':
|
1128 |
+
trigger_error( 'Cannot list files in folder.', E_USER_WARNING );
|
1129 |
+
break;
|
1130 |
+
}
|
1131 |
+
}
|
1132 |
+
|
1133 |
+
private function handleFilesLookupError( $error ) {
|
1134 |
+
switch ( $error['.tag'] ) {
|
1135 |
+
case 'malformed_path':
|
1136 |
+
trigger_error( 'The path was malformed.', E_USER_WARNING );
|
1137 |
+
break;
|
1138 |
+
|
1139 |
+
case 'not_found':
|
1140 |
+
trigger_error( 'File could not be found.', E_USER_WARNING );
|
1141 |
+
break;
|
1142 |
+
|
1143 |
+
case 'not_file':
|
1144 |
+
trigger_error( 'That is not a file.', E_USER_WARNING );
|
1145 |
+
break;
|
1146 |
+
|
1147 |
+
case 'not_folder':
|
1148 |
+
trigger_error( 'That is not a folder.', E_USER_WARNING );
|
1149 |
+
break;
|
1150 |
+
|
1151 |
+
case 'restricted_content':
|
1152 |
+
trigger_error( 'This content is restricted.', E_USER_WARNING );
|
1153 |
+
break;
|
1154 |
+
|
1155 |
+
case 'invalid_path_root':
|
1156 |
+
trigger_error( 'Path root is invalid.', E_USER_WARNING );
|
1157 |
+
break;
|
1158 |
+
|
1159 |
+
case 'other':
|
1160 |
+
trigger_error( 'File could not be found.', E_USER_WARNING );
|
1161 |
+
break;
|
1162 |
+
}
|
1163 |
+
}
|
1164 |
+
|
1165 |
+
private function handleFilesUploadSessionFinishError( $error ) {
|
1166 |
+
switch ( $error['.tag'] ) {
|
1167 |
+
case 'lookup_failed':
|
1168 |
+
$this->handleFilesUploadSessionLookupError(
|
1169 |
+
$error['lookup_failed'] );
|
1170 |
+
break;
|
1171 |
+
|
1172 |
+
case 'path':
|
1173 |
+
$this->handleFilesWriteError( $error['path'] );
|
1174 |
+
break;
|
1175 |
+
|
1176 |
+
case 'too_many_shared_folder_targets':
|
1177 |
+
trigger_error( 'Too many shared folder targets.', E_USER_WARNING );
|
1178 |
+
break;
|
1179 |
+
|
1180 |
+
case 'other':
|
1181 |
+
trigger_error( 'The file could not be uploaded.', E_USER_WARNING );
|
1182 |
+
break;
|
1183 |
+
}
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
private function handleFilesUploadSessionLookupError( $error ) {
|
1187 |
+
switch ( $error['.tag'] ) {
|
1188 |
+
case 'not_found':
|
1189 |
+
trigger_error( 'Session not found.', E_USER_WARNING );
|
1190 |
+
break;
|
1191 |
+
|
1192 |
+
case 'incorrect_offset':
|
1193 |
+
trigger_error( 'Incorrect offset given. Correct offset is ' .
|
1194 |
+
$error['correct_offset'] . '.',
|
1195 |
+
E_USER_WARNING );
|
1196 |
+
break;
|
1197 |
+
|
1198 |
+
case 'closed':
|
1199 |
+
trigger_error( 'This session has been closed already.',
|
1200 |
+
E_USER_WARNING );
|
1201 |
+
break;
|
1202 |
+
|
1203 |
+
case 'not_closed':
|
1204 |
+
trigger_error( 'This session is not closed.', E_USER_WARNING );
|
1205 |
+
break;
|
1206 |
+
|
1207 |
+
case 'other':
|
1208 |
+
trigger_error( 'Could not look up the file session.',
|
1209 |
+
E_USER_WARNING );
|
1210 |
+
break;
|
1211 |
+
}
|
1212 |
+
}
|
1213 |
+
|
1214 |
+
private function handleFilesUploadError( $error ) {
|
1215 |
+
switch ( $error['.tag'] ) {
|
1216 |
+
case 'path':
|
1217 |
+
$this->handleFilesUploadWriteFailed( $error['path'] );
|
1218 |
+
break;
|
1219 |
+
|
1220 |
+
case 'other':
|
1221 |
+
trigger_error( 'There was an unknown error when uploading the file.', E_USER_WARNING );
|
1222 |
+
break;
|
1223 |
+
}
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
private function handleFilesUploadWriteFailed( $error ) {
|
1227 |
+
$this->handleFilesWriteError( $error['reason'] );
|
1228 |
+
}
|
1229 |
+
|
1230 |
+
private function handleFilesWriteError( $error ) {
|
1231 |
+
$message = '';
|
1232 |
+
|
1233 |
+
// Type of error
|
1234 |
+
switch ( $error['.tag'] ) {
|
1235 |
+
case 'malformed_path':
|
1236 |
+
$message = 'The path was malformed.';
|
1237 |
+
break;
|
1238 |
+
|
1239 |
+
case 'conflict':
|
1240 |
+
$message = 'Cannot write to the target path due to conflict.';
|
1241 |
+
break;
|
1242 |
+
|
1243 |
+
case 'no_write_permission':
|
1244 |
+
$message = 'You do not have permission to save to this location.';
|
1245 |
+
break;
|
1246 |
+
|
1247 |
+
case 'insufficient_space':
|
1248 |
+
$message = 'You do not have enough space in your Dropbox.';
|
1249 |
+
break;
|
1250 |
+
|
1251 |
+
case 'disallowed_name':
|
1252 |
+
$message = 'The given name is disallowed by Dropbox.';
|
1253 |
+
break;
|
1254 |
+
|
1255 |
+
case 'team_folder':
|
1256 |
+
$message = 'Unable to modify team folders.';
|
1257 |
+
break;
|
1258 |
+
|
1259 |
+
case 'other':
|
1260 |
+
$message = 'There was an unknown error when uploading the file.';
|
1261 |
+
break;
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
trigger_error( $message, E_USER_WARNING );
|
1265 |
+
}
|
1266 |
+
|
1267 |
}
|
1268 |
|
1269 |
/**
|
1272 |
class BackWPup_Destination_Dropbox_API_Exception extends Exception {
|
1273 |
|
1274 |
}
|
1275 |
+
|
1276 |
+
/**
|
1277 |
+
* Exception thrown when there is an error in the Dropbox request.
|
1278 |
+
*/
|
1279 |
+
class BackWPup_Destination_Dropbox_API_Request_Exception extends BackWPup_Destination_Dropbox_API_Exception {
|
1280 |
+
|
1281 |
+
/**
|
1282 |
+
* The request error array.
|
1283 |
+
*/
|
1284 |
+
protected $error;
|
1285 |
+
|
1286 |
+
public function __construct( $message, $code = 0, $previous = null, $error = null ) {
|
1287 |
+
$this->error = $error;
|
1288 |
+
parent::__construct( $message, $code, $previous );
|
1289 |
+
}
|
1290 |
+
|
1291 |
+
public function getError() {
|
1292 |
+
return $this->error;
|
1293 |
+
}
|
1294 |
+
|
1295 |
+
}
|
inc/class-destination-email.php
CHANGED
@@ -38,7 +38,7 @@ class BackWPup_Destination_Email extends BackWPup_Destinations {
|
|
38 |
<h3 class="title"><?php esc_html_e( 'Email address', 'backwpup' ); ?></h3>
|
39 |
<table class="form-table">
|
40 |
<tr>
|
41 |
-
<th scope="row"><label for="emailaddress"><?php esc_html_e( 'To email address', 'backwpup' ); ?></label></th>
|
42 |
<td>
|
43 |
<input name="emailaddress" id="emailaddress" type="text" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'emailaddress' ) );?>" class="regular-text" />
|
44 |
</td>
|
@@ -176,7 +176,7 @@ class BackWPup_Destination_Email extends BackWPup_Destinations {
|
|
176 |
*/
|
177 |
public function edit_form_post_save( $jobid ) {
|
178 |
|
179 |
-
BackWPup_Option::update( $jobid, 'emailaddress', isset( $_POST[
|
180 |
BackWPup_Option::update( $jobid, 'emailefilesize', ! empty( $_POST[ 'emailefilesize' ] ) ? absint( $_POST[ 'emailefilesize' ] ) : 0 );
|
181 |
BackWPup_Option::update( $jobid, 'emailsndemail', sanitize_email( $_POST[ 'emailsndemail' ] ) );
|
182 |
BackWPup_Option::update( $jobid, 'emailmethod', ( $_POST[ 'emailmethod' ] === '' || $_POST[ 'emailmethod' ] === 'mail' || $_POST[ 'emailmethod' ] === 'sendmail' || $_POST[ 'emailmethod' ] === 'smtp' ) ? $_POST[ 'emailmethod' ] : '' );
|
@@ -288,7 +288,7 @@ class BackWPup_Destination_Email extends BackWPup_Destinations {
|
|
288 |
// Create a message
|
289 |
$message = Swift_Message::newInstance( sprintf( __( 'BackWPup archive from %1$s: %2$s', 'backwpup' ), date_i18n( 'd-M-Y H:i', $job_object->start_time, TRUE ), esc_attr($job_object->job[ 'name' ] ) ) );
|
290 |
$message->setFrom( array( $job_object->job[ 'emailsndemail' ] => $job_object->job[ 'emailsndemailname' ] ) );
|
291 |
-
$message->setTo(
|
292 |
$message->setBody( sprintf( __( 'Backup archive: %s', 'backwpup' ), $job_object->backup_file ), 'text/plain', strtolower( get_bloginfo( 'charset' ) ) );
|
293 |
$message->attach( Swift_Attachment::fromPath( $job_object->backup_folder . $job_object->backup_file, $job_object->get_mime_type( $job_object->backup_folder . $job_object->backup_file ) ) );
|
294 |
// Send the message
|
@@ -413,7 +413,7 @@ class BackWPup_Destination_Email extends BackWPup_Destinations {
|
|
413 |
// Create a message
|
414 |
$message = Swift_Message::newInstance( __( 'BackWPup archive sending TEST Message', 'backwpup' ) );
|
415 |
$message->setFrom( array( $_POST[ 'emailsndemail' ] => sanitize_email( $_POST[ 'emailsndemailname' ] ) ) );
|
416 |
-
$message->setTo(
|
417 |
$message->setBody( __( 'If this message reaches your inbox, sending backup archives via email should work for you.', 'backwpup' ) );
|
418 |
// Send the message
|
419 |
$result = $emailer->send( $message );
|
@@ -433,4 +433,25 @@ class BackWPup_Destination_Email extends BackWPup_Destinations {
|
|
433 |
}
|
434 |
die();
|
435 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
436 |
}
|
38 |
<h3 class="title"><?php esc_html_e( 'Email address', 'backwpup' ); ?></h3>
|
39 |
<table class="form-table">
|
40 |
<tr>
|
41 |
+
<th scope="row"><label for="emailaddress"><?php esc_html_e( 'To email address (separate with commas for multiple addresses)', 'backwpup' ); ?></label></th>
|
42 |
<td>
|
43 |
<input name="emailaddress" id="emailaddress" type="text" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'emailaddress' ) );?>" class="regular-text" />
|
44 |
</td>
|
176 |
*/
|
177 |
public function edit_form_post_save( $jobid ) {
|
178 |
|
179 |
+
BackWPup_Option::update( $jobid, 'emailaddress', isset( $_POST['emailaddress'] ) ? implode( ', ', $this->get_email_array( $_POST['emailaddress'] ) ) : '' );
|
180 |
BackWPup_Option::update( $jobid, 'emailefilesize', ! empty( $_POST[ 'emailefilesize' ] ) ? absint( $_POST[ 'emailefilesize' ] ) : 0 );
|
181 |
BackWPup_Option::update( $jobid, 'emailsndemail', sanitize_email( $_POST[ 'emailsndemail' ] ) );
|
182 |
BackWPup_Option::update( $jobid, 'emailmethod', ( $_POST[ 'emailmethod' ] === '' || $_POST[ 'emailmethod' ] === 'mail' || $_POST[ 'emailmethod' ] === 'sendmail' || $_POST[ 'emailmethod' ] === 'smtp' ) ? $_POST[ 'emailmethod' ] : '' );
|
288 |
// Create a message
|
289 |
$message = Swift_Message::newInstance( sprintf( __( 'BackWPup archive from %1$s: %2$s', 'backwpup' ), date_i18n( 'd-M-Y H:i', $job_object->start_time, TRUE ), esc_attr($job_object->job[ 'name' ] ) ) );
|
290 |
$message->setFrom( array( $job_object->job[ 'emailsndemail' ] => $job_object->job[ 'emailsndemailname' ] ) );
|
291 |
+
$message->setTo( $this->get_email_array( $job_object->job['emailaddress'] ) );
|
292 |
$message->setBody( sprintf( __( 'Backup archive: %s', 'backwpup' ), $job_object->backup_file ), 'text/plain', strtolower( get_bloginfo( 'charset' ) ) );
|
293 |
$message->attach( Swift_Attachment::fromPath( $job_object->backup_folder . $job_object->backup_file, $job_object->get_mime_type( $job_object->backup_folder . $job_object->backup_file ) ) );
|
294 |
// Send the message
|
413 |
// Create a message
|
414 |
$message = Swift_Message::newInstance( __( 'BackWPup archive sending TEST Message', 'backwpup' ) );
|
415 |
$message->setFrom( array( $_POST[ 'emailsndemail' ] => sanitize_email( $_POST[ 'emailsndemailname' ] ) ) );
|
416 |
+
$message->setTo( $this->get_email_array( $_POST['emailaddress'] ) );
|
417 |
$message->setBody( __( 'If this message reaches your inbox, sending backup archives via email should work for you.', 'backwpup' ) );
|
418 |
// Send the message
|
419 |
$result = $emailer->send( $message );
|
433 |
}
|
434 |
die();
|
435 |
}
|
436 |
+
|
437 |
+
/**
|
438 |
+
* Get an array of emails from comma-separated string.
|
439 |
+
*
|
440 |
+
* @param string $emailString
|
441 |
+
*
|
442 |
+
* @return array
|
443 |
+
*/
|
444 |
+
private function get_email_array( $emailString ) {
|
445 |
+
$emails = explode( ',', sanitize_text_field( $emailString ) );
|
446 |
+
|
447 |
+
foreach ( $emails as $key => $email ) {
|
448 |
+
$emails[ $key ] = sanitize_email( trim( $email ) );
|
449 |
+
if ( ! is_email( $emails[ $key ] ) ) {
|
450 |
+
unset( $emails[ $key ] );
|
451 |
+
}
|
452 |
+
}
|
453 |
+
|
454 |
+
return $emails;
|
455 |
+
}
|
456 |
+
|
457 |
}
|
inc/class-destination-folder.php
CHANGED
@@ -45,6 +45,7 @@ class BackWPup_Destination_Folder extends BackWPup_Destinations {
|
|
45 |
<input id="idmaxbackups" name="maxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'maxbackups' ) ); ?>" class="small-text"/>
|
46 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
47 |
</label>
|
|
|
48 |
<?php } else { ?>
|
49 |
<label for="idbackupsyncnodelete">
|
50 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'backupsyncnodelete' ), true ); ?> name="backupsyncnodelete" id="idbackupsyncnodelete"/>
|
@@ -143,28 +144,31 @@ class BackWPup_Destination_Folder extends BackWPup_Destinations {
|
|
143 |
$files = array();
|
144 |
$backup_folder = BackWPup_Option::get( $jobid, 'backupdir' );
|
145 |
$backup_folder = BackWPup_File::get_absolute_path( $backup_folder );
|
146 |
-
|
147 |
-
|
148 |
-
|
|
|
|
|
|
|
149 |
continue;
|
150 |
}
|
151 |
-
|
|
|
152 |
//file list for backups
|
153 |
$files[ $filecounter ][ 'folder' ] = $backup_folder;
|
154 |
-
$files[ $filecounter ][ 'file' ] =
|
155 |
-
$files[ $filecounter ][ 'filename' ] = $file;
|
156 |
$files[ $filecounter ][ 'downloadurl' ] = add_query_arg( array(
|
157 |
'page' => 'backwpupbackups',
|
158 |
'action' => 'downloadfolder',
|
159 |
-
'file' => $file,
|
160 |
'jobid' => $jobid
|
161 |
), network_admin_url( 'admin.php' ) );
|
162 |
-
$files[ $filecounter ][ 'filesize' ] =
|
163 |
-
$files[ $filecounter ][ 'time' ] =
|
164 |
$filecounter ++;
|
165 |
}
|
166 |
}
|
167 |
-
closedir( $dir );
|
168 |
}
|
169 |
|
170 |
return $files;
|
@@ -187,17 +191,25 @@ class BackWPup_Destination_Folder extends BackWPup_Destinations {
|
|
187 |
//Delete old Backupfiles
|
188 |
$backupfilelist = array();
|
189 |
$files = array();
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
|
|
|
|
|
|
|
|
|
|
196 |
}
|
197 |
}
|
198 |
}
|
199 |
-
|
|
|
|
|
200 |
}
|
|
|
201 |
if ( $job_object->job[ 'maxbackups' ] > 0 ) {
|
202 |
if ( count( $backupfilelist ) > $job_object->job[ 'maxbackups' ] ) {
|
203 |
ksort( $backupfilelist );
|
@@ -205,9 +217,9 @@ class BackWPup_Destination_Folder extends BackWPup_Destinations {
|
|
205 |
while ( $file = array_shift( $backupfilelist ) ) {
|
206 |
if ( count( $backupfilelist ) < $job_object->job[ 'maxbackups' ] )
|
207 |
break;
|
208 |
-
unlink( $
|
209 |
foreach ( $files as $key => $filedata ) {
|
210 |
-
if ( $filedata[ 'file' ] == $
|
211 |
unset( $files[ $key ] );
|
212 |
}
|
213 |
}
|
45 |
<input id="idmaxbackups" name="maxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'maxbackups' ) ); ?>" class="small-text"/>
|
46 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
47 |
</label>
|
48 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
49 |
<?php } else { ?>
|
50 |
<label for="idbackupsyncnodelete">
|
51 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'backupsyncnodelete' ), true ); ?> name="backupsyncnodelete" id="idbackupsyncnodelete"/>
|
144 |
$files = array();
|
145 |
$backup_folder = BackWPup_Option::get( $jobid, 'backupdir' );
|
146 |
$backup_folder = BackWPup_File::get_absolute_path( $backup_folder );
|
147 |
+
|
148 |
+
if ( is_dir( $backup_folder ) ) { //make file list
|
149 |
+
$dir = new BackWPup_Directory( $backup_folder );
|
150 |
+
|
151 |
+
foreach ( $dir as $file ) {
|
152 |
+
if ( $file->isDot() || in_array( $file->getFilename(), array( 'index.php', '.htaccess', '.donotbackup', 'Web.config' ), true ) || $file->isDir() || $file->isLink() ) {
|
153 |
continue;
|
154 |
}
|
155 |
+
|
156 |
+
if ( $file->isReadable() ) {
|
157 |
//file list for backups
|
158 |
$files[ $filecounter ][ 'folder' ] = $backup_folder;
|
159 |
+
$files[ $filecounter ][ 'file' ] = str_replace( '\\', '/', $file->getPathname() );
|
160 |
+
$files[ $filecounter ][ 'filename' ] = $file->getFilename();
|
161 |
$files[ $filecounter ][ 'downloadurl' ] = add_query_arg( array(
|
162 |
'page' => 'backwpupbackups',
|
163 |
'action' => 'downloadfolder',
|
164 |
+
'file' => $file->getFilename(),
|
165 |
'jobid' => $jobid
|
166 |
), network_admin_url( 'admin.php' ) );
|
167 |
+
$files[ $filecounter ][ 'filesize' ] = $file->getSize();
|
168 |
+
$files[ $filecounter ][ 'time' ] = $file->getMTime() + ( get_option( 'gmt_offset' ) * 3600 );
|
169 |
$filecounter ++;
|
170 |
}
|
171 |
}
|
|
|
172 |
}
|
173 |
|
174 |
return $files;
|
191 |
//Delete old Backupfiles
|
192 |
$backupfilelist = array();
|
193 |
$files = array();
|
194 |
+
|
195 |
+
if ( is_writable( $job_object->backup_folder ) ) { //make file list
|
196 |
+
try {
|
197 |
+
$dir = new BackWPup_Directory( $job_object->backup_folder );
|
198 |
+
|
199 |
+
foreach ( $dir as $file ) {
|
200 |
+
if ( $file->isWritable() && ! $file->isDir() && ! $file->isLink() ) {
|
201 |
+
//list for deletion
|
202 |
+
if ( $job_object->is_backup_archive( $file->getFilename() ) && $job_object->owns_backup_archive( $file->getFilename() ) ) {
|
203 |
+
$backupfilelist[ $file->getMTime() ] = clone $file;
|
204 |
+
}
|
205 |
}
|
206 |
}
|
207 |
}
|
208 |
+
catch ( UnexpectedValueException $e ) {
|
209 |
+
$job_object->log( sprintf( __( "Could not open path: %s", 'backwpup' ), $e->getMessage() ), E_USER_WARNING );
|
210 |
+
}
|
211 |
}
|
212 |
+
|
213 |
if ( $job_object->job[ 'maxbackups' ] > 0 ) {
|
214 |
if ( count( $backupfilelist ) > $job_object->job[ 'maxbackups' ] ) {
|
215 |
ksort( $backupfilelist );
|
217 |
while ( $file = array_shift( $backupfilelist ) ) {
|
218 |
if ( count( $backupfilelist ) < $job_object->job[ 'maxbackups' ] )
|
219 |
break;
|
220 |
+
unlink( $file->getPathname() );
|
221 |
foreach ( $files as $key => $filedata ) {
|
222 |
+
if ( $filedata[ 'file' ] == $file->getPathname() ) {
|
223 |
unset( $files[ $key ] );
|
224 |
}
|
225 |
}
|
inc/class-destination-ftp.php
CHANGED
@@ -65,6 +65,7 @@ class BackWPup_Destination_Ftp extends BackWPup_Destinations {
|
|
65 |
<input id="idftpmaxbackups" name="ftpmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'ftpmaxbackups' ) ); ?>" class="small-text" />
|
66 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
67 |
</label>
|
|
|
68 |
<?php } else { ?>
|
69 |
<label for="idftpsyncnodelete">
|
70 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'ftpsyncnodelete' ), true ); ?> name="ftpsyncnodelete" id="idftpsyncnodelete" />
|
@@ -351,7 +352,7 @@ class BackWPup_Destination_Ftp extends BackWPup_Destinations {
|
|
351 |
if ( $filelist = ftp_nlist( $ftp_conn_id, '.' ) ) {
|
352 |
foreach ( $filelist as $file ) {
|
353 |
if ( basename( $file ) != '.' && basename( $file ) != '..' ) {
|
354 |
-
if ( $job_object->is_backup_archive( $file ) ) {
|
355 |
$time = ftp_mdtm( $ftp_conn_id, $file );
|
356 |
if ( $time != - 1 )
|
357 |
$backupfilelist[ $time ] = basename( $file );
|
65 |
<input id="idftpmaxbackups" name="ftpmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'ftpmaxbackups' ) ); ?>" class="small-text" />
|
66 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
67 |
</label>
|
68 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
69 |
<?php } else { ?>
|
70 |
<label for="idftpsyncnodelete">
|
71 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'ftpsyncnodelete' ), true ); ?> name="ftpsyncnodelete" id="idftpsyncnodelete" />
|
352 |
if ( $filelist = ftp_nlist( $ftp_conn_id, '.' ) ) {
|
353 |
foreach ( $filelist as $file ) {
|
354 |
if ( basename( $file ) != '.' && basename( $file ) != '..' ) {
|
355 |
+
if ( $job_object->is_backup_archive( $file ) && $job_object->owns_backup_archive( $file ) == true ) {
|
356 |
$time = ftp_mdtm( $ftp_conn_id, $file );
|
357 |
if ( $time != - 1 )
|
358 |
$backupfilelist[ $time ] = basename( $file );
|
inc/class-destination-msazure.php
CHANGED
@@ -1,462 +1,463 @@
|
|
1 |
-
<?php
|
2 |
-
// Windows Azure SDK v0.4.1
|
3 |
-
// http://www.windowsazure.com/en-us/develop/php/
|
4 |
-
// https://github.com/WindowsAzure/azure-sdk-for-php
|
5 |
-
|
6 |
-
/**
|
7 |
-
* Documentation: http://www.windowsazure.com/en-us/develop/php/how-to-guides/blob-service/
|
8 |
-
*/
|
9 |
-
class BackWPup_Destination_MSAzure extends BackWPup_Destinations {
|
10 |
-
|
11 |
-
/**
|
12 |
-
* @return array
|
13 |
-
*/
|
14 |
-
public function option_defaults() {
|
15 |
-
|
16 |
-
return array( 'msazureaccname' => '', 'msazurekey' => '', 'msazurecontainer' => '', 'msazuredir' => trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) ), 'msazuremaxbackups' => 15, 'msazuresyncnodelete' => TRUE );
|
17 |
-
}
|
18 |
-
|
19 |
-
|
20 |
-
/**
|
21 |
-
* @param $jobid
|
22 |
-
*/
|
23 |
-
public function edit_tab( $jobid ) {
|
24 |
-
?>
|
25 |
-
<h3 class="title"><?php esc_html_e( 'MS Azure access keys', 'backwpup' ); ?></h3>
|
26 |
-
<p></p>
|
27 |
-
<table class="form-table">
|
28 |
-
<tr>
|
29 |
-
<th scope="row"><label for="msazureaccname"><?php esc_html_e( 'Account name', 'backwpup' ); ?></label></th>
|
30 |
-
<td>
|
31 |
-
<input id="msazureaccname" name="msazureaccname" type="text"
|
32 |
-
value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazureaccname' ) );?>" class="regular-text" autocomplete="off" />
|
33 |
-
</td>
|
34 |
-
</tr>
|
35 |
-
<tr>
|
36 |
-
<th scope="row"><label for="msazurekey"><?php esc_html_e( 'Access key', 'backwpup' ); ?></label></th>
|
37 |
-
<td>
|
38 |
-
<input id="msazurekey" name="msazurekey" type="password"
|
39 |
-
value="<?php echo esc_attr( BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );?>" class="regular-text" autocomplete="off" />
|
40 |
-
</td>
|
41 |
-
</tr>
|
42 |
-
</table>
|
43 |
-
|
44 |
-
<h3 class="title"><?php esc_html_e( 'Blob container', 'backwpup' ); ?></h3>
|
45 |
-
<p></p>
|
46 |
-
<table class="form-table">
|
47 |
-
<tr>
|
48 |
-
<th scope="row"><label for="msazurecontainerselected"><?php esc_html_e( 'Container selection', 'backwpup' ); ?></label></th>
|
49 |
-
<td>
|
50 |
-
<input id="msazurecontainerselected" name="msazurecontainerselected" type="hidden" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazurecontainer' ) );?>" />
|
51 |
-
<?php if ( BackWPup_Option::get( $jobid, 'msazureaccname' ) && BackWPup_Option::get( $jobid, 'msazurekey' ) ) $this->edit_ajax( array(
|
52 |
-
'msazureaccname' => BackWPup_Option::get( $jobid, 'msazureaccname' ),
|
53 |
-
'msazurekey' => BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ),
|
54 |
-
'msazureselected' => BackWPup_Option::get( $jobid, 'msazurecontainer' )
|
55 |
-
) ); ?>
|
56 |
-
</td>
|
57 |
-
</tr>
|
58 |
-
<tr>
|
59 |
-
<th scope="row"><label for="newmsazurecontainer"><?php esc_html_e( 'Create a new container', 'backwpup' ); ?></label></th>
|
60 |
-
<td>
|
61 |
-
<input id="newmsazurecontainer" name="newmsazurecontainer" type="text" value="" class="small-text" autocomplete="off" />
|
62 |
-
</td>
|
63 |
-
</tr>
|
64 |
-
</table>
|
65 |
-
|
66 |
-
<h3 class="title"><?php esc_html_e( 'Backup settings', 'backwpup' ); ?></h3>
|
67 |
-
<p></p>
|
68 |
-
<table class="form-table">
|
69 |
-
<tr>
|
70 |
-
<th scope="row"><label for="idmsazuredir"><?php esc_html_e( 'Folder in container', 'backwpup' ); ?></label></th>
|
71 |
-
<td>
|
72 |
-
<input id="idmsazuredir" name="msazuredir" type="text" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazuredir' ) ); ?>" class="regular-text" />
|
73 |
-
</td>
|
74 |
-
</tr>
|
75 |
-
<tr>
|
76 |
-
<th scope="row"><?php esc_html_e( 'File deletion', 'backwpup' ); ?></th>
|
77 |
-
<td>
|
78 |
-
<?php
|
79 |
-
if ( BackWPup_Option::get( $jobid, 'backuptype' ) === 'archive' ) {
|
80 |
-
?>
|
81 |
-
<label for="idmsazuremaxbackups">
|
82 |
-
<input id="idmsazuremaxbackups" name="msazuremaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazuremaxbackups' ) ); ?>" class="small-text" />
|
83 |
-
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
84 |
-
</label>
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
* @
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
BackWPup_Option::update( $jobid, '
|
106 |
-
BackWPup_Option::update( $jobid, '
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
BackWPup_Option::update( $jobid, '
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
$
|
124 |
-
$container_options
|
125 |
-
$
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
* @param $
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
$blobRestProxy->
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
* @param $
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
$
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
header( 'Content-
|
182 |
-
header( 'Content-
|
183 |
-
header( 'Content-
|
184 |
-
header( 'Content-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
* @
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
* @
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
$blobRestProxy
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
$
|
257 |
-
$
|
258 |
-
$
|
259 |
-
$
|
260 |
-
$
|
261 |
-
$
|
262 |
-
$
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
$job_object->
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
$job_object->
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
$
|
305 |
-
$
|
306 |
-
$
|
307 |
-
$blob_options
|
308 |
-
$
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
$files[ $filecounter ][ '
|
317 |
-
$files[ $filecounter ][ '
|
318 |
-
$files[ $filecounter ][ '
|
319 |
-
$files[ $filecounter ][ '
|
320 |
-
$files[ $filecounter ][ '
|
321 |
-
$filecounter
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
$
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
* @
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
$('#
|
393 |
-
$('#
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
$args[ '
|
424 |
-
$args[ '
|
425 |
-
$
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
$
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
}
|
|
1 |
+
<?php
|
2 |
+
// Windows Azure SDK v0.4.1
|
3 |
+
// http://www.windowsazure.com/en-us/develop/php/
|
4 |
+
// https://github.com/WindowsAzure/azure-sdk-for-php
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Documentation: http://www.windowsazure.com/en-us/develop/php/how-to-guides/blob-service/
|
8 |
+
*/
|
9 |
+
class BackWPup_Destination_MSAzure extends BackWPup_Destinations {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @return array
|
13 |
+
*/
|
14 |
+
public function option_defaults() {
|
15 |
+
|
16 |
+
return array( 'msazureaccname' => '', 'msazurekey' => '', 'msazurecontainer' => '', 'msazuredir' => trailingslashit( sanitize_file_name( get_bloginfo( 'name' ) ) ), 'msazuremaxbackups' => 15, 'msazuresyncnodelete' => TRUE );
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param $jobid
|
22 |
+
*/
|
23 |
+
public function edit_tab( $jobid ) {
|
24 |
+
?>
|
25 |
+
<h3 class="title"><?php esc_html_e( 'MS Azure access keys', 'backwpup' ); ?></h3>
|
26 |
+
<p></p>
|
27 |
+
<table class="form-table">
|
28 |
+
<tr>
|
29 |
+
<th scope="row"><label for="msazureaccname"><?php esc_html_e( 'Account name', 'backwpup' ); ?></label></th>
|
30 |
+
<td>
|
31 |
+
<input id="msazureaccname" name="msazureaccname" type="text"
|
32 |
+
value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazureaccname' ) );?>" class="regular-text" autocomplete="off" />
|
33 |
+
</td>
|
34 |
+
</tr>
|
35 |
+
<tr>
|
36 |
+
<th scope="row"><label for="msazurekey"><?php esc_html_e( 'Access key', 'backwpup' ); ?></label></th>
|
37 |
+
<td>
|
38 |
+
<input id="msazurekey" name="msazurekey" type="password"
|
39 |
+
value="<?php echo esc_attr( BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );?>" class="regular-text" autocomplete="off" />
|
40 |
+
</td>
|
41 |
+
</tr>
|
42 |
+
</table>
|
43 |
+
|
44 |
+
<h3 class="title"><?php esc_html_e( 'Blob container', 'backwpup' ); ?></h3>
|
45 |
+
<p></p>
|
46 |
+
<table class="form-table">
|
47 |
+
<tr>
|
48 |
+
<th scope="row"><label for="msazurecontainerselected"><?php esc_html_e( 'Container selection', 'backwpup' ); ?></label></th>
|
49 |
+
<td>
|
50 |
+
<input id="msazurecontainerselected" name="msazurecontainerselected" type="hidden" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazurecontainer' ) );?>" />
|
51 |
+
<?php if ( BackWPup_Option::get( $jobid, 'msazureaccname' ) && BackWPup_Option::get( $jobid, 'msazurekey' ) ) $this->edit_ajax( array(
|
52 |
+
'msazureaccname' => BackWPup_Option::get( $jobid, 'msazureaccname' ),
|
53 |
+
'msazurekey' => BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ),
|
54 |
+
'msazureselected' => BackWPup_Option::get( $jobid, 'msazurecontainer' )
|
55 |
+
) ); ?>
|
56 |
+
</td>
|
57 |
+
</tr>
|
58 |
+
<tr>
|
59 |
+
<th scope="row"><label for="newmsazurecontainer"><?php esc_html_e( 'Create a new container', 'backwpup' ); ?></label></th>
|
60 |
+
<td>
|
61 |
+
<input id="newmsazurecontainer" name="newmsazurecontainer" type="text" value="" class="small-text" autocomplete="off" />
|
62 |
+
</td>
|
63 |
+
</tr>
|
64 |
+
</table>
|
65 |
+
|
66 |
+
<h3 class="title"><?php esc_html_e( 'Backup settings', 'backwpup' ); ?></h3>
|
67 |
+
<p></p>
|
68 |
+
<table class="form-table">
|
69 |
+
<tr>
|
70 |
+
<th scope="row"><label for="idmsazuredir"><?php esc_html_e( 'Folder in container', 'backwpup' ); ?></label></th>
|
71 |
+
<td>
|
72 |
+
<input id="idmsazuredir" name="msazuredir" type="text" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazuredir' ) ); ?>" class="regular-text" />
|
73 |
+
</td>
|
74 |
+
</tr>
|
75 |
+
<tr>
|
76 |
+
<th scope="row"><?php esc_html_e( 'File deletion', 'backwpup' ); ?></th>
|
77 |
+
<td>
|
78 |
+
<?php
|
79 |
+
if ( BackWPup_Option::get( $jobid, 'backuptype' ) === 'archive' ) {
|
80 |
+
?>
|
81 |
+
<label for="idmsazuremaxbackups">
|
82 |
+
<input id="idmsazuremaxbackups" name="msazuremaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazuremaxbackups' ) ); ?>" class="small-text" />
|
83 |
+
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
84 |
+
</label>
|
85 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
86 |
+
<?php } else { ?>
|
87 |
+
<label for="idmsazuresyncnodelete">
|
88 |
+
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'msazuresyncnodelete' ), true ); ?> name="msazuresyncnodelete" id="idmsazuresyncnodelete" />
|
89 |
+
<?php esc_html_e( 'Do not delete files while syncing to destination!', 'backwpup' ); ?>
|
90 |
+
</label>
|
91 |
+
<?php } ?>
|
92 |
+
</td>
|
93 |
+
</tr>
|
94 |
+
</table>
|
95 |
+
<?php
|
96 |
+
}
|
97 |
+
|
98 |
+
|
99 |
+
/**
|
100 |
+
* @param $jobid
|
101 |
+
* @return string
|
102 |
+
*/
|
103 |
+
public function edit_form_post_save( $jobid ) {
|
104 |
+
|
105 |
+
BackWPup_Option::update( $jobid, 'msazureaccname', sanitize_text_field( $_POST[ 'msazureaccname' ] ) );
|
106 |
+
BackWPup_Option::update( $jobid, 'msazurekey', sanitize_text_field( $_POST[ 'msazurekey' ] ) );
|
107 |
+
BackWPup_Option::update( $jobid, 'msazurecontainer', sanitize_text_field( $_POST[ 'msazurecontainer' ] ) );
|
108 |
+
|
109 |
+
$_POST[ 'msazuredir' ] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( sanitize_text_field( $_POST[ 'msazuredir' ] ) ) ) ) );
|
110 |
+
if ( substr( $_POST[ 'msazuredir' ], 0, 1 ) == '/' )
|
111 |
+
$_POST[ 'msazuredir' ] = substr( $_POST[ 'msazuredir' ], 1 );
|
112 |
+
if ( $_POST[ 'msazuredir' ] == '/' )
|
113 |
+
$_POST[ 'msazuredir' ] = '';
|
114 |
+
BackWPup_Option::update( $jobid, 'msazuredir', $_POST[ 'msazuredir' ] );
|
115 |
+
|
116 |
+
BackWPup_Option::update( $jobid, 'msazuremaxbackups', ! empty( $_POST[ 'msazuremaxbackups' ] ) ? absint( $_POST[ 'msazuremaxbackups' ] ) : 0 );
|
117 |
+
BackWPup_Option::update( $jobid, 'msazuresyncnodelete', ! empty( $_POST[ 'msazuresyncnodelete' ] ) );
|
118 |
+
|
119 |
+
//create a new container
|
120 |
+
if ( ! empty( $_POST[ 'newmsazurecontainer' ] ) && ! empty( $_POST[ 'msazureaccname' ] ) && ! empty( $_POST[ 'msazurekey' ] ) ) {
|
121 |
+
try {
|
122 |
+
set_include_path( get_include_path() . PATH_SEPARATOR . BackWPup::get_plugin_data( 'plugindir' ) .'/vendor/PEAR/');
|
123 |
+
$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . sanitize_text_field( $_POST[ 'msazureaccname' ] ) . ';AccountKey=' . sanitize_text_field( $_POST[ 'msazurekey' ] ) );
|
124 |
+
$container_options = new WindowsAzure\Blob\Models\CreateContainerOptions();
|
125 |
+
$container_options->setPublicAccess( WindowsAzure\Blob\Models\PublicAccessType::NONE );
|
126 |
+
$blobRestProxy->createContainer( $_POST[ 'newmsazurecontainer' ], $container_options );
|
127 |
+
BackWPup_Option::update( $jobid, 'msazurecontainer', sanitize_text_field( $_POST[ 'newmsazurecontainer' ] ) );
|
128 |
+
BackWPup_Admin::message( sprintf( __( 'MS Azure container "%s" created.', 'backwpup' ), esc_html( sanitize_text_field( $_POST[ 'newmsazurecontainer' ] ) ) ) );
|
129 |
+
}
|
130 |
+
catch ( Exception $e ) {
|
131 |
+
BackWPup_Admin::message( sprintf( __( 'MS Azure container create: %s', 'backwpup' ), $e->getMessage() ), TRUE );
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
|
137 |
+
/**
|
138 |
+
* @param $jobdest
|
139 |
+
* @param $backupfile
|
140 |
+
*/
|
141 |
+
public function file_delete( $jobdest, $backupfile ) {
|
142 |
+
|
143 |
+
$files = get_site_transient( 'backwpup_'. strtolower( $jobdest ) );
|
144 |
+
list( $jobid, $dest ) = explode( '_', $jobdest );
|
145 |
+
|
146 |
+
if ( BackWPup_Option::get( $jobid, 'msazureaccname' ) && BackWPup_Option::get( $jobid, 'msazurekey' ) && BackWPup_Option::get( $jobid, 'msazurecontainer' ) ) {
|
147 |
+
try {
|
148 |
+
set_include_path( get_include_path() . PATH_SEPARATOR . BackWPup::get_plugin_data( 'plugindir' ) .'/vendor/PEAR/');
|
149 |
+
$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . BackWPup_Option::get( $jobid, 'msazureaccname' ) . ';AccountKey=' . BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );
|
150 |
+
$blobRestProxy->deleteBlob( BackWPup_Option::get( $jobid, 'msazurecontainer' ), $backupfile );
|
151 |
+
//update file list
|
152 |
+
foreach ( $files as $key => $file ) {
|
153 |
+
if ( is_array( $file ) && $file[ 'file' ] == $backupfile )
|
154 |
+
unset( $files[ $key ] );
|
155 |
+
}
|
156 |
+
}
|
157 |
+
catch ( Exception $e ) {
|
158 |
+
BackWPup_Admin::message( 'MS AZURE: ' . $e->getMessage(), TRUE );
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
set_site_transient( 'backwpup_' . strtolower( $jobdest ), $files, YEAR_IN_SECONDS );
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* @param $jobid
|
167 |
+
* @param $get_file
|
168 |
+
*/
|
169 |
+
public function file_download( $jobid, $get_file ) {
|
170 |
+
try {
|
171 |
+
set_include_path( get_include_path() . PATH_SEPARATOR . BackWPup::get_plugin_data( 'plugindir' ) .'/vendor/PEAR/');
|
172 |
+
$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . BackWPup_Option::get( $jobid, 'msazureaccname' ) . ';AccountKey=' . BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );
|
173 |
+
$blob = $blobRestProxy->getBlob( BackWPup_Option::get( $jobid, 'msazurecontainer' ), $get_file );
|
174 |
+
if ( $level = ob_get_level() ) {
|
175 |
+
for ( $i = 0; $i < $level; $i ++ ) {
|
176 |
+
ob_end_clean();
|
177 |
+
}
|
178 |
+
}
|
179 |
+
@set_time_limit( 300 );
|
180 |
+
nocache_headers();
|
181 |
+
header( 'Content-Description: File Transfer' );
|
182 |
+
header( 'Content-Type: ' . BackWPup_Job::get_mime_type( $get_file ) );
|
183 |
+
header( 'Content-Disposition: attachment; filename="' . basename( $get_file ) . '"' );
|
184 |
+
header( 'Content-Transfer-Encoding: binary' );
|
185 |
+
header( 'Content-Length: ' . $blob->getProperties()->getContentLength() );
|
186 |
+
fpassthru( $blob->getContentStream() );
|
187 |
+
die();
|
188 |
+
}
|
189 |
+
catch ( Exception $e ) {
|
190 |
+
die( $e->getMessage() );
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* @param $jobdest
|
196 |
+
* @return mixed
|
197 |
+
*/
|
198 |
+
public function file_get_list( $jobdest ) {
|
199 |
+
return get_site_transient( 'backwpup_' . $jobdest );
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* @param $job_object
|
204 |
+
* @return bool
|
205 |
+
*/
|
206 |
+
public function job_run_archive( BackWPup_Job $job_object ) {
|
207 |
+
|
208 |
+
$job_object->substeps_todo = $job_object->backup_filesize + 2;
|
209 |
+
|
210 |
+
if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] )
|
211 |
+
$job_object->log( sprintf( __( '%d. Try sending backup to a Microsoft Azure (Blob) …', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] ), E_USER_NOTICE );
|
212 |
+
|
213 |
+
try {
|
214 |
+
set_include_path( get_include_path() . PATH_SEPARATOR . BackWPup::get_plugin_data( 'plugindir' ) .'/vendor/PEAR/');
|
215 |
+
/* @var $blobRestProxy WindowsAzure\Blob\BlobRestProxy */ //https causes an error SSL: Connection reset by peer that is why http
|
216 |
+
$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService('DefaultEndpointsProtocol=http;AccountName=' . $job_object->job[ 'msazureaccname' ] . ';AccountKey=' . BackWPup_Encryption::decrypt( $job_object->job[ 'msazurekey' ] ) );
|
217 |
+
|
218 |
+
|
219 |
+
if ( $job_object->steps_data[ $job_object->step_working ]['SAVE_STEP_TRY'] != $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] ) {
|
220 |
+
|
221 |
+
//test vor existing container
|
222 |
+
$containers = $blobRestProxy->listContainers()->getContainers();
|
223 |
+
|
224 |
+
$job_object->steps_data[ $job_object->step_working ][ 'container_url' ] = '';
|
225 |
+
foreach( $containers as $container ) {
|
226 |
+
if ( $container->getName() == $job_object->job[ 'msazurecontainer' ] ) {
|
227 |
+
$job_object->steps_data[ $job_object->step_working ][ 'container_url' ] = $container->getUrl();
|
228 |
+
break;
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
if ( ! $job_object->steps_data[ $job_object->step_working ][ 'container_url' ] ) {
|
233 |
+
$job_object->log( sprintf( __( 'MS Azure container "%s" does not exist!', 'backwpup'), $job_object->job[ 'msazurecontainer' ] ), E_USER_ERROR );
|
234 |
+
|
235 |
+
return TRUE;
|
236 |
+
} else {
|
237 |
+
$job_object->log( sprintf( __( 'Connected to MS Azure container "%s".', 'backwpup'), $job_object->job[ 'msazurecontainer' ] ), E_USER_NOTICE );
|
238 |
+
}
|
239 |
+
|
240 |
+
$job_object->log( __( 'Starting upload to MS Azure …', 'backwpup' ), E_USER_NOTICE );
|
241 |
+
}
|
242 |
+
|
243 |
+
//Prepare Upload
|
244 |
+
if ( $file_handel = fopen( $job_object->backup_folder . $job_object->backup_file, 'rb' ) ) {
|
245 |
+
fseek( $file_handel, $job_object->substeps_done );
|
246 |
+
|
247 |
+
if ( empty( $job_object->steps_data[ $job_object->step_working ][ 'BlockList' ] ) ) {
|
248 |
+
$job_object->steps_data[ $job_object->step_working ][ 'BlockList' ] = array();
|
249 |
+
}
|
250 |
+
|
251 |
+
while ( ! feof( $file_handel ) ) {
|
252 |
+
$data = fread( $file_handel, 1048576 * 4 ); //4MB
|
253 |
+
if ( strlen( $data ) == 0 ) {
|
254 |
+
continue;
|
255 |
+
}
|
256 |
+
$chunk_upload_start = microtime( TRUE );
|
257 |
+
$block_count = count( $job_object->steps_data[ $job_object->step_working ][ 'BlockList' ] ) + 1;
|
258 |
+
$block_id = md5( $data ) . str_pad( $block_count, 6, "0", STR_PAD_LEFT );
|
259 |
+
$blobRestProxy->createBlobBlock( $job_object->job[ 'msazurecontainer' ], $job_object->job[ 'msazuredir' ] . $job_object->backup_file, $block_id, $data );
|
260 |
+
$job_object->steps_data[ $job_object->step_working ][ 'BlockList' ][] = $block_id;
|
261 |
+
$chunk_upload_time = microtime( TRUE ) - $chunk_upload_start;
|
262 |
+
$job_object->substeps_done = $job_object->substeps_done + strlen( $data );
|
263 |
+
$time_remaining = $job_object->do_restart_time();
|
264 |
+
if ( $time_remaining < $chunk_upload_time ) {
|
265 |
+
$job_object->do_restart_time( TRUE );
|
266 |
+
}
|
267 |
+
$job_object->update_working_data();
|
268 |
+
}
|
269 |
+
fclose( $file_handel );
|
270 |
+
} else {
|
271 |
+
$job_object->log( __( 'Can not open source file for transfer.', 'backwpup' ), E_USER_ERROR );
|
272 |
+
return FALSE;
|
273 |
+
}
|
274 |
+
|
275 |
+
//crate blog list
|
276 |
+
$blocklist = new WindowsAzure\Blob\Models\BlockList();
|
277 |
+
foreach( $job_object->steps_data[ $job_object->step_working ][ 'BlockList' ] as $block_id ) {
|
278 |
+
$blocklist->addUncommittedEntry( $block_id );
|
279 |
+
}
|
280 |
+
unset( $job_object->steps_data[ $job_object->step_working ][ 'BlockList' ] );
|
281 |
+
|
282 |
+
//Commit Blocks
|
283 |
+
$blobRestProxy->commitBlobBlocks( $job_object->job[ 'msazurecontainer' ], $job_object->job[ 'msazuredir' ] . $job_object->backup_file, $blocklist->getEntries() );
|
284 |
+
|
285 |
+
$job_object->substeps_done ++;
|
286 |
+
$job_object->log( sprintf( __( 'Backup transferred to %s', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ][ 'container_url' ] . '/' . $job_object->job[ 'msazuredir' ] . $job_object->backup_file ), E_USER_NOTICE );
|
287 |
+
if ( !empty( $job_object->job[ 'jobid' ] ) ) {
|
288 |
+
BackWPup_Option::update( $job_object->job[ 'jobid' ] , 'lastbackupdownloadurl', network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloadmsazure&file=' . $job_object->job[ 'msazuredir' ] . $job_object->backup_file . '&jobid=' . $job_object->job[ 'jobid' ] );
|
289 |
+
}
|
290 |
+
}
|
291 |
+
catch ( Exception $e ) {
|
292 |
+
$job_object->log( E_USER_ERROR, sprintf( __( 'Microsoft Azure API: %s', 'backwpup' ), $e->getMessage() ), $e->getFile(), $e->getLine() );
|
293 |
+
$job_object->substeps_done = 0;
|
294 |
+
unset( $job_object->steps_data[ $job_object->step_working ][ 'BlockList' ] );
|
295 |
+
if ( isset( $file_handel ) && is_resource( $file_handel ) )
|
296 |
+
fclose( $file_handel );
|
297 |
+
|
298 |
+
return FALSE;
|
299 |
+
}
|
300 |
+
|
301 |
+
|
302 |
+
try {
|
303 |
+
|
304 |
+
$backupfilelist = array();
|
305 |
+
$filecounter = 0;
|
306 |
+
$files = array();
|
307 |
+
$blob_options = new WindowsAzure\Blob\Models\ListBlobsOptions();
|
308 |
+
$blob_options->setPrefix( $job_object->job[ 'msazuredir' ] );
|
309 |
+
$blobs = $blobRestProxy->listBlobs( $job_object->job[ 'msazurecontainer' ], $blob_options )->getBlobs();
|
310 |
+
|
311 |
+
if ( is_array( $blobs ) ) {
|
312 |
+
foreach ( $blobs as $blob ) {
|
313 |
+
$file = basename( $blob->getName() );
|
314 |
+
if ( $job_object->is_backup_archive( $file ) && $job_object->owns_backup_archive( $file ) == true )
|
315 |
+
$backupfilelist[ $blob->getProperties()->getLastModified()->getTimestamp() ] = $file;
|
316 |
+
$files[ $filecounter ][ 'folder' ] = $job_object->steps_data[ $job_object->step_working ][ 'container_url' ] . "/" . dirname( $blob->getName() ) . "/";
|
317 |
+
$files[ $filecounter ][ 'file' ] = $blob->getName();
|
318 |
+
$files[ $filecounter ][ 'filename' ] = basename( $blob->getName() );
|
319 |
+
$files[ $filecounter ][ 'downloadurl' ] = network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloadmsazure&file=' . $blob->getName() . '&jobid=' . $job_object->job[ 'jobid' ];
|
320 |
+
$files[ $filecounter ][ 'filesize' ] = $blob->getProperties()->getContentLength();
|
321 |
+
$files[ $filecounter ][ 'time' ] = $blob->getProperties()->getLastModified()->getTimestamp() + ( get_option( 'gmt_offset' ) * 3600 );
|
322 |
+
$filecounter ++;
|
323 |
+
}
|
324 |
+
}
|
325 |
+
// Delete old backups
|
326 |
+
if ( ! empty ($job_object->job[ 'msazuremaxbackups' ] ) && $job_object->job[ 'msazuremaxbackups' ] > 0 ) {
|
327 |
+
if ( count( $backupfilelist ) > $job_object->job[ 'msazuremaxbackups' ] ) {
|
328 |
+
ksort( $backupfilelist );
|
329 |
+
$numdeltefiles = 0;
|
330 |
+
while ( $file = array_shift( $backupfilelist ) ) {
|
331 |
+
if ( count( $backupfilelist ) < $job_object->job[ 'msazuremaxbackups' ] )
|
332 |
+
break;
|
333 |
+
$blobRestProxy->deleteBlob( $job_object->job[ 'msazurecontainer' ], $job_object->job[ 'msazuredir' ] . $file );
|
334 |
+
foreach ( $files as $key => $filedata ) {
|
335 |
+
if ( $filedata[ 'file' ] == $job_object->job[ 'msazuredir' ] . $file )
|
336 |
+
unset( $files[ $key ] );
|
337 |
+
}
|
338 |
+
$numdeltefiles ++;
|
339 |
+
}
|
340 |
+
if ( $numdeltefiles > 0 )
|
341 |
+
$job_object->log( sprintf( _n( 'One file deleted on Microsoft Azure container.', '%d files deleted on Microsoft Azure container.', $numdeltefiles, 'backwpup' ), $numdeltefiles ), E_USER_NOTICE );
|
342 |
+
|
343 |
+
}
|
344 |
+
}
|
345 |
+
set_site_transient( 'backwpup_' . $job_object->job[ 'jobid' ] . '_msazure', $files, YEAR_IN_SECONDS );
|
346 |
+
}
|
347 |
+
catch ( Exception $e ) {
|
348 |
+
$job_object->log( E_USER_ERROR, sprintf( __( 'Microsoft Azure API: %s', 'backwpup' ), $e->getMessage() ), $e->getFile(), $e->getLine() );
|
349 |
+
|
350 |
+
return FALSE;
|
351 |
+
}
|
352 |
+
|
353 |
+
$job_object->substeps_done = $job_object->backup_filesize + 2;
|
354 |
+
|
355 |
+
return TRUE;
|
356 |
+
}
|
357 |
+
|
358 |
+
/**
|
359 |
+
* @param $job_settings array
|
360 |
+
* @return bool
|
361 |
+
*/
|
362 |
+
public function can_run( array $job_settings ) {
|
363 |
+
|
364 |
+
if ( empty( $job_settings[ 'msazureaccname' ] ) )
|
365 |
+
return FALSE;
|
366 |
+
|
367 |
+
if ( empty( $job_settings[ 'msazurekey' ]) )
|
368 |
+
return FALSE;
|
369 |
+
|
370 |
+
if ( empty( $job_settings[ 'msazurecontainer' ] ) )
|
371 |
+
return FALSE;
|
372 |
+
|
373 |
+
return TRUE;
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
*
|
378 |
+
*/
|
379 |
+
public function edit_inline_js() {
|
380 |
+
?>
|
381 |
+
<script type="text/javascript">
|
382 |
+
jQuery(document).ready(function ($) {
|
383 |
+
function msazuregetcontainer() {
|
384 |
+
var data = {
|
385 |
+
action: 'backwpup_dest_msazure',
|
386 |
+
msazureaccname: $('#msazureaccname').val(),
|
387 |
+
msazurekey: $('#msazurekey').val(),
|
388 |
+
msazureselected: $('#msazurecontainerselected').val(),
|
389 |
+
_ajax_nonce: $('#backwpupajaxnonce').val()
|
390 |
+
};
|
391 |
+
$.post(ajaxurl, data, function (response) {
|
392 |
+
$('#msazurecontainererror').remove();
|
393 |
+
$('#msazurecontainer').remove();
|
394 |
+
$('#msazurecontainerselected').after(response);
|
395 |
+
});
|
396 |
+
}
|
397 |
+
|
398 |
+
$('#msazureaccname').backwpupDelayKeyup(function () {
|
399 |
+
msazuregetcontainer();
|
400 |
+
});
|
401 |
+
$('#msazurekey').backwpupDelayKeyup(function () {
|
402 |
+
msazuregetcontainer();
|
403 |
+
});
|
404 |
+
});
|
405 |
+
</script>
|
406 |
+
<?php
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* @param string $args
|
411 |
+
*/
|
412 |
+
public function edit_ajax( $args = '' ) {
|
413 |
+
|
414 |
+
$error = '';
|
415 |
+
|
416 |
+
if ( is_array( $args ) ) {
|
417 |
+
$ajax = FALSE;
|
418 |
+
}
|
419 |
+
else {
|
420 |
+
if ( ! current_user_can( 'backwpup_jobs_edit' ) )
|
421 |
+
wp_die( -1 );
|
422 |
+
check_ajax_referer( 'backwpup_ajax_nonce' );
|
423 |
+
$args[ 'msazureaccname' ] = sanitize_text_field( $_POST[ 'msazureaccname' ] );
|
424 |
+
$args[ 'msazurekey' ] = sanitize_text_field( $_POST[ 'msazurekey' ] );
|
425 |
+
$args[ 'msazureselected' ] = sanitize_text_field( $_POST[ 'msazureselected' ] );
|
426 |
+
$ajax = TRUE;
|
427 |
+
}
|
428 |
+
echo '<span id="msazurecontainererror" style="color:red;">';
|
429 |
+
|
430 |
+
if ( ! empty( $args[ 'msazureaccname' ] ) && ! empty( $args[ 'msazurekey' ] ) ) {
|
431 |
+
try {
|
432 |
+
set_include_path( get_include_path() . PATH_SEPARATOR . BackWPup::get_plugin_data( 'plugindir' ) .'/vendor/PEAR/');
|
433 |
+
$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . $args[ 'msazureaccname' ] . ';AccountKey=' . BackWPup_Encryption::decrypt( $args[ 'msazurekey' ] ) );
|
434 |
+
$containers = $blobRestProxy->listContainers()->getContainers();
|
435 |
+
}
|
436 |
+
catch ( Exception $e ) {
|
437 |
+
$error = $e->getMessage();
|
438 |
+
}
|
439 |
+
}
|
440 |
+
|
441 |
+
if ( empty( $args[ 'msazureaccname' ] ) )
|
442 |
+
_e( 'Missing account name!', 'backwpup' );
|
443 |
+
elseif ( empty( $args[ 'msazurekey' ] ) )
|
444 |
+
_e( 'Missing access key!', 'backwpup' );
|
445 |
+
elseif ( ! empty( $error ) )
|
446 |
+
echo esc_html( $error );
|
447 |
+
elseif ( empty( $containers ) )
|
448 |
+
_e( 'No container found!', 'backwpup' );
|
449 |
+
echo '</span>';
|
450 |
+
|
451 |
+
if ( !empty( $containers ) ) {
|
452 |
+
echo '<select name="msazurecontainer" id="msazurecontainer">';
|
453 |
+
foreach ( $containers as $container ) {
|
454 |
+
echo "<option " . selected( strtolower( $args[ 'msazureselected' ] ), strtolower( $container->getName() ), FALSE ) . ">" . esc_html( $container->getName() ) . "</option>";
|
455 |
+
}
|
456 |
+
echo '</select>';
|
457 |
+
}
|
458 |
+
if ( $ajax )
|
459 |
+
die();
|
460 |
+
else
|
461 |
+
return;
|
462 |
+
}
|
463 |
+
}
|
inc/class-destination-rsc.php
CHANGED
@@ -111,6 +111,7 @@ class BackWPup_Destination_RSC extends BackWPup_Destinations {
|
|
111 |
<input id="idrscmaxbackups" name="rscmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'rscmaxbackups' ) ); ?>" class="small-text" />
|
112 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
113 |
</label>
|
|
|
114 |
<?php } else { ?>
|
115 |
<label for="idrscsyncnodelete">
|
116 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'rscsyncnodelete' ), true ); ?> name="rscsyncnodelete" id="idrscsyncnodelete" />
|
@@ -323,7 +324,7 @@ class BackWPup_Destination_RSC extends BackWPup_Destinations {
|
|
323 |
while ( $object = $objlist->next() ) {
|
324 |
$file = basename( $object->getName() );
|
325 |
if ( $job_object->job[ 'rscdir' ] . $file == $object->getName() ) { //only in the folder and not in complete bucket
|
326 |
-
if ( $job_object->is_backup_archive( $file ) )
|
327 |
$backupfilelist[ strtotime( $object->getLastModified() ) ] = $object;
|
328 |
}
|
329 |
$files[ $filecounter ][ 'folder' ] = "RSC://" . $job_object->job[ 'rsccontainer' ] . "/" . dirname( $object->getName() ) . "/";
|
111 |
<input id="idrscmaxbackups" name="rscmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'rscmaxbackups' ) ); ?>" class="small-text" />
|
112 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
113 |
</label>
|
114 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
115 |
<?php } else { ?>
|
116 |
<label for="idrscsyncnodelete">
|
117 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'rscsyncnodelete' ), true ); ?> name="rscsyncnodelete" id="idrscsyncnodelete" />
|
324 |
while ( $object = $objlist->next() ) {
|
325 |
$file = basename( $object->getName() );
|
326 |
if ( $job_object->job[ 'rscdir' ] . $file == $object->getName() ) { //only in the folder and not in complete bucket
|
327 |
+
if ( $job_object->is_backup_archive( $file ) && $job_object->owns_backup_archive( $file ) == true )
|
328 |
$backupfilelist[ strtotime( $object->getLastModified() ) ] = $object;
|
329 |
}
|
330 |
$files[ $filecounter ][ 'folder' ] = "RSC://" . $job_object->job[ 'rsccontainer' ] . "/" . dirname( $object->getName() ) . "/";
|
inc/class-destination-s3.php
CHANGED
@@ -47,7 +47,6 @@ class BackWPup_Destination_S3 extends BackWPup_Destinations {
|
|
47 |
<option value="google-storage-us" <?php selected( 'google-storage-us', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'Google Storage: USA', 'backwpup' ); ?></option>
|
48 |
<option value="google-storage-asia" <?php selected( 'google-storage-asia', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'Google Storage: Asia', 'backwpup' ); ?></option>
|
49 |
<option value="dreamhost" <?php selected( 'dreamhost', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'Dream Host Cloud Storage', 'backwpup' ); ?></option>
|
50 |
-
<option value="greenqloud" <?php selected( 'greenqloud', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'GreenQloud Storage Qloud', 'backwpup' ); ?></option>
|
51 |
</select>
|
52 |
</td>
|
53 |
</tr>
|
@@ -121,6 +120,7 @@ class BackWPup_Destination_S3 extends BackWPup_Destinations {
|
|
121 |
<input id="ids3maxbackups" name="s3maxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 's3maxbackups' ) ); ?>" class="small-text" />
|
122 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
123 |
</label>
|
|
|
124 |
<?php } else { ?>
|
125 |
<label for="ids3syncnodelete">
|
126 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 's3syncnodelete' ), true ); ?> name="s3syncnodelete" id="ids3syncnodelete" />
|
@@ -182,6 +182,7 @@ class BackWPup_Destination_S3 extends BackWPup_Destinations {
|
|
182 |
wp_die( -1 );
|
183 |
}
|
184 |
check_ajax_referer( 'backwpup_ajax_nonce' );
|
|
|
185 |
$args[ 's3accesskey' ] = sanitize_text_field( $_POST[ 's3accesskey' ] );
|
186 |
$args[ 's3secretkey' ] = sanitize_text_field( $_POST[ 's3secretkey' ] );
|
187 |
$args[ 's3bucketselected' ] = sanitize_text_field( $_POST[ 's3bucketselected' ] );
|
@@ -285,8 +286,6 @@ class BackWPup_Destination_S3 extends BackWPup_Destinations {
|
|
285 |
return 'https://storage.googleapis.com';
|
286 |
case 'dreamhost':
|
287 |
return 'https://objects-us-west-1.dream.io';
|
288 |
-
case 'greenqloud':
|
289 |
-
return 'http://s.greenqloud.com';
|
290 |
default:
|
291 |
return '';
|
292 |
}
|
@@ -626,7 +625,7 @@ class BackWPup_Destination_S3 extends BackWPup_Destinations {
|
|
626 |
foreach ( $objects as $object ) {
|
627 |
$file = basename( $object[ 'Key' ] );
|
628 |
$changetime = strtotime( $object[ 'LastModified' ] ) + ( get_option( 'gmt_offset' ) * 3600 );
|
629 |
-
if ( $job_object->is_backup_archive( $file ) )
|
630 |
$backupfilelist[ $changetime ] = $file;
|
631 |
$files[ $filecounter ][ 'folder' ] = $this->get_s3_base_url( $job_object->job[ 's3region' ], $job_object->job[ 's3base_url' ] ). '/' .$job_object->job[ 's3bucket' ] . '/' . dirname( $object[ 'Key' ] );
|
632 |
$files[ $filecounter ][ 'file' ] = $object[ 'Key' ];
|
47 |
<option value="google-storage-us" <?php selected( 'google-storage-us', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'Google Storage: USA', 'backwpup' ); ?></option>
|
48 |
<option value="google-storage-asia" <?php selected( 'google-storage-asia', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'Google Storage: Asia', 'backwpup' ); ?></option>
|
49 |
<option value="dreamhost" <?php selected( 'dreamhost', BackWPup_Option::get( $jobid, 's3region' ), TRUE ) ?>><?php esc_html_e( 'Dream Host Cloud Storage', 'backwpup' ); ?></option>
|
|
|
50 |
</select>
|
51 |
</td>
|
52 |
</tr>
|
120 |
<input id="ids3maxbackups" name="s3maxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 's3maxbackups' ) ); ?>" class="small-text" />
|
121 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
122 |
</label>
|
123 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
124 |
<?php } else { ?>
|
125 |
<label for="ids3syncnodelete">
|
126 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 's3syncnodelete' ), true ); ?> name="s3syncnodelete" id="ids3syncnodelete" />
|
182 |
wp_die( -1 );
|
183 |
}
|
184 |
check_ajax_referer( 'backwpup_ajax_nonce' );
|
185 |
+
$args = array();
|
186 |
$args[ 's3accesskey' ] = sanitize_text_field( $_POST[ 's3accesskey' ] );
|
187 |
$args[ 's3secretkey' ] = sanitize_text_field( $_POST[ 's3secretkey' ] );
|
188 |
$args[ 's3bucketselected' ] = sanitize_text_field( $_POST[ 's3bucketselected' ] );
|
286 |
return 'https://storage.googleapis.com';
|
287 |
case 'dreamhost':
|
288 |
return 'https://objects-us-west-1.dream.io';
|
|
|
|
|
289 |
default:
|
290 |
return '';
|
291 |
}
|
625 |
foreach ( $objects as $object ) {
|
626 |
$file = basename( $object[ 'Key' ] );
|
627 |
$changetime = strtotime( $object[ 'LastModified' ] ) + ( get_option( 'gmt_offset' ) * 3600 );
|
628 |
+
if ( $job_object->is_backup_archive( $file ) && $job_object->owns_backup_archive( $file ) == true )
|
629 |
$backupfilelist[ $changetime ] = $file;
|
630 |
$files[ $filecounter ][ 'folder' ] = $this->get_s3_base_url( $job_object->job[ 's3region' ], $job_object->job[ 's3base_url' ] ). '/' .$job_object->job[ 's3bucket' ] . '/' . dirname( $object[ 'Key' ] );
|
631 |
$files[ $filecounter ][ 'file' ] = $object[ 'Key' ];
|
inc/class-destination-sugarsync.php
CHANGED
@@ -97,6 +97,7 @@ class BackWPup_Destination_SugarSync extends BackWPup_Destinations {
|
|
97 |
<input id="idsugarmaxbackups" name="sugarmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'sugarmaxbackups' ) ); ?>" class="small-text" />
|
98 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
99 |
</label>
|
|
|
100 |
<?php } else { ?>
|
101 |
<label for="idsugarsyncnodelete">
|
102 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'sugarsyncnodelete' ), true ); ?> name="sugarsyncnodelete" id="idsugarsyncnodelete" />
|
@@ -272,7 +273,7 @@ class BackWPup_Destination_SugarSync extends BackWPup_Destinations {
|
|
272 |
if ( is_object( $getfiles ) ) {
|
273 |
foreach ( $getfiles->file as $getfile ) {
|
274 |
$getfile->displayName = utf8_decode( (string)$getfile->displayName );
|
275 |
-
if ( $job_object->is_backup_archive( $getfile->displayName ) )
|
276 |
$backupfilelist[ strtotime( (string)$getfile->lastModified ) ] = (string)$getfile->ref;
|
277 |
$files[ $filecounter ][ 'folder' ] = 'https://' . (string)$user->nickname . '.sugarsync.com/' . $dir;
|
278 |
$files[ $filecounter ][ 'file' ] = (string)$getfile->ref;
|
97 |
<input id="idsugarmaxbackups" name="sugarmaxbackups" type="number" min="0" step="1" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'sugarmaxbackups' ) ); ?>" class="small-text" />
|
98 |
<?php esc_html_e( 'Number of files to keep in folder.', 'backwpup' ); ?>
|
99 |
</label>
|
100 |
+
<p><?php _e( '<strong>Warning</strong>: Files belonging to this job are now tracked. Old backup archives which are untracked will not be automatically deleted.', 'backwpup' ) ?></p>
|
101 |
<?php } else { ?>
|
102 |
<label for="idsugarsyncnodelete">
|
103 |
<input class="checkbox" value="1" type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'sugarsyncnodelete' ), true ); ?> name="sugarsyncnodelete" id="idsugarsyncnodelete" />
|
273 |
if ( is_object( $getfiles ) ) {
|
274 |
foreach ( $getfiles->file as $getfile ) {
|
275 |
$getfile->displayName = utf8_decode( (string)$getfile->displayName );
|
276 |
+
if ( $job_object->is_backup_archive( $getfile->displayName ) && $job_object->owns_backup_archive( $getfile->displayName ) == true )
|
277 |
$backupfilelist[ strtotime( (string)$getfile->lastModified ) ] = (string)$getfile->ref;
|
278 |
$files[ $filecounter ][ 'folder' ] = 'https://' . (string)$user->nickname . '.sugarsync.com/' . $dir;
|
279 |
$files[ $filecounter ][ 'file' ] = (string)$getfile->ref;
|
inc/class-directory.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Wraps directory functions in PHP.
|
5 |
+
*
|
6 |
+
* @since 3.4.0
|
7 |
+
*/
|
8 |
+
class BackWPup_Directory extends DirectoryIterator {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Creates the iterator.
|
12 |
+
*
|
13 |
+
* Fixes the path before calling the parent constructor.
|
14 |
+
*
|
15 |
+
* @param string $path
|
16 |
+
*/
|
17 |
+
public function __construct( $path ) {
|
18 |
+
parent::__construct( BackWPup_Path_Fixer::fix_path( $path ) );
|
19 |
+
}
|
20 |
+
|
21 |
+
}
|
inc/class-file.php
CHANGED
@@ -70,36 +70,20 @@ class BackWPup_File {
|
|
70 |
* @param bool $deep went thrue suborders
|
71 |
* @return int folder size in byte
|
72 |
*/
|
73 |
-
public static function get_folder_size( $folder
|
74 |
-
|
75 |
$files_size = 0;
|
76 |
|
77 |
-
if ( ! is_readable( $folder ) )
|
78 |
return $files_size;
|
|
|
79 |
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
}
|
85 |
-
if ( $deep && is_dir( $folder . '/' . $file ) ) {
|
86 |
-
$files_size = $files_size + self::get_folder_size( $folder . '/' . $file, TRUE );
|
87 |
-
}
|
88 |
-
elseif ( is_link( $folder . '/' . $file ) ) {
|
89 |
-
continue;
|
90 |
-
}
|
91 |
-
elseif ( is_readable( $folder . '/' . $file ) ) {
|
92 |
-
$file_size = filesize( $folder . '/' . $file );
|
93 |
-
if ( empty( $file_size ) || ! is_int( $file_size ) ) {
|
94 |
-
continue;
|
95 |
-
}
|
96 |
-
$files_size = $files_size + $file_size;
|
97 |
-
}
|
98 |
-
}
|
99 |
-
closedir( $dir );
|
100 |
}
|
101 |
|
102 |
-
|
103 |
}
|
104 |
|
105 |
/**
|
@@ -176,8 +160,15 @@ class BackWPup_File {
|
|
176 |
$server_software = strtolower( $_SERVER[ 'SERVER_SOFTWARE' ] );
|
177 |
//IIS
|
178 |
if ( strstr( $server_software, 'microsoft-iis' ) ) {
|
179 |
-
if ( ! file_exists( $folder . '/
|
180 |
-
file_put_contents( $folder . '/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
}
|
182 |
} //Nginx
|
183 |
elseif ( strstr( $server_software, 'nginx' ) ) {
|
70 |
* @param bool $deep went thrue suborders
|
71 |
* @return int folder size in byte
|
72 |
*/
|
73 |
+
public static function get_folder_size( $folder ) {
|
|
|
74 |
$files_size = 0;
|
75 |
|
76 |
+
if ( ! is_readable( $folder ) ) {
|
77 |
return $files_size;
|
78 |
+
}
|
79 |
|
80 |
+
$iterator = new RecursiveIteratorIterator( new BackWPup_Recursive_Directory( $folder, FilesystemIterator::SKIP_DOTS ) );
|
81 |
+
|
82 |
+
foreach ( $iterator as $file ) {
|
83 |
+
$files_size += $file->getSize();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
}
|
85 |
|
86 |
+
return $files_size;
|
87 |
}
|
88 |
|
89 |
/**
|
160 |
$server_software = strtolower( $_SERVER[ 'SERVER_SOFTWARE' ] );
|
161 |
//IIS
|
162 |
if ( strstr( $server_software, 'microsoft-iis' ) ) {
|
163 |
+
if ( ! file_exists( $folder . '/Web.config' ) ) {
|
164 |
+
file_put_contents( $folder . '/Web.config',
|
165 |
+
"<configuration>" . PHP_EOL .
|
166 |
+
"\t<system.webServer>" . PHP_EOL .
|
167 |
+
"\t\t<authorization>" . PHP_EOL .
|
168 |
+
"\t\t\t<deny users=\"*\" />" . PHP_EOL .
|
169 |
+
"\t\t</authorization>" . PHP_EOL .
|
170 |
+
"\t</system.webServer>" . PHP_EOL .
|
171 |
+
"</configuration>" );
|
172 |
}
|
173 |
} //Nginx
|
174 |
elseif ( strstr( $server_software, 'nginx' ) ) {
|
inc/class-job.php
CHANGED
@@ -1,2552 +1,2580 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Class in that the BackWPup job runs
|
5 |
-
*/
|
6 |
-
final class BackWPup_Job {
|
7 |
-
|
8 |
-
/**
|
9 |
-
* @var array of the job settings
|
10 |
-
*/
|
11 |
-
public $job = array();
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var int The timestamp when the job starts
|
15 |
-
*/
|
16 |
-
public $start_time = 0;
|
17 |
-
|
18 |
-
/**
|
19 |
-
* @var string the logfile
|
20 |
-
*/
|
21 |
-
public $logfile = '';
|
22 |
-
/**
|
23 |
-
* @var array for temp values
|
24 |
-
*/
|
25 |
-
public $temp = array();
|
26 |
-
/**
|
27 |
-
* @var string Folder where is Backup files in
|
28 |
-
*/
|
29 |
-
public $backup_folder = '';
|
30 |
-
/**
|
31 |
-
* @var string the name of the Backup archive file
|
32 |
-
*/
|
33 |
-
public $backup_file = '';
|
34 |
-
/**
|
35 |
-
* @var int The size of the Backup archive file
|
36 |
-
*/
|
37 |
-
public $backup_filesize = 0;
|
38 |
-
/**
|
39 |
-
* @var int PID of script
|
40 |
-
*/
|
41 |
-
public $pid = 0;
|
42 |
-
/**
|
43 |
-
* @var float Timestamp of last update off .running file
|
44 |
-
*/
|
45 |
-
public $timestamp_last_update = 0;
|
46 |
-
/**
|
47 |
-
* @var int Number of warnings
|
48 |
-
*/
|
49 |
-
public $warnings = 0;
|
50 |
-
/**
|
51 |
-
* @var int Number of errors
|
52 |
-
*/
|
53 |
-
public $errors = 0;
|
54 |
-
/**
|
55 |
-
* @var string the last log notice message
|
56 |
-
*/
|
57 |
-
public $lastmsg = '';
|
58 |
-
/**
|
59 |
-
* @var string the last log error/waring message
|
60 |
-
*/
|
61 |
-
public $lasterrormsg = '';
|
62 |
-
/**
|
63 |
-
* @var array of steps to do
|
64 |
-
*/
|
65 |
-
public $steps_todo = array( 'CREATE' );
|
66 |
-
/**
|
67 |
-
* @var array of done steps
|
68 |
-
*/
|
69 |
-
public $steps_done = array();
|
70 |
-
/**
|
71 |
-
* @var array of steps data
|
72 |
-
*/
|
73 |
-
public $steps_data = array();
|
74 |
-
/**
|
75 |
-
* @var string working on step
|
76 |
-
*/
|
77 |
-
public $step_working = 'CREATE';
|
78 |
-
/**
|
79 |
-
* @var int Number of sub steps must do in step
|
80 |
-
*/
|
81 |
-
public $substeps_todo = 0;
|
82 |
-
/**
|
83 |
-
* @var int Number of sub steps done in step
|
84 |
-
*/
|
85 |
-
public $substeps_done = 0;
|
86 |
-
/**
|
87 |
-
* @var int Percent of steps done
|
88 |
-
*/
|
89 |
-
public $step_percent = 1;
|
90 |
-
/**
|
91 |
-
* @var int Percent of sub steps done
|
92 |
-
*/
|
93 |
-
public $substep_percent = 1;
|
94 |
-
/**
|
95 |
-
* @var array of files to additional to backup
|
96 |
-
*/
|
97 |
-
public $additional_files_to_backup = array();
|
98 |
-
/**
|
99 |
-
* @var array of files/folder to exclude from backup
|
100 |
-
*/
|
101 |
-
public $exclude_from_backup = array();
|
102 |
-
/**
|
103 |
-
* @var int count of affected files
|
104 |
-
*/
|
105 |
-
public $count_files = 0;
|
106 |
-
/**
|
107 |
-
* @var int count of affected file sizes
|
108 |
-
*/
|
109 |
-
public $count_files_size = 0;
|
110 |
-
/**
|
111 |
-
* @var int count of affected folders
|
112 |
-
*/
|
113 |
-
public $count_folder = 0;
|
114 |
-
/**
|
115 |
-
* If job aborted from user
|
116 |
-
* @var bool
|
117 |
-
*/
|
118 |
-
public $user_abort = false;
|
119 |
-
/**
|
120 |
-
* A uniqid ID uniqid('', true); to identify process
|
121 |
-
* @var string
|
122 |
-
*/
|
123 |
-
public $uniqid = '';
|
124 |
-
/**
|
125 |
-
* @var float Timestamp of script start
|
126 |
-
*/
|
127 |
-
private $timestamp_script_start = 0;
|
128 |
-
/**
|
129 |
-
* Stores data that will only used in a single run
|
130 |
-
* @var array
|
131 |
-
*/
|
132 |
-
private $run = array();
|
133 |
-
/**
|
134 |
-
* @var string logging level (normal|normal_untranslated|debug|debug_untranslated)
|
135 |
-
*/
|
136 |
-
private $log_level = 'normal';
|
137 |
-
|
138 |
-
/**
|
139 |
-
* @var int Signal of signal handler
|
140 |
-
*/
|
141 |
-
private $signal = 0;
|
142 |
-
|
143 |
-
/**
|
144 |
-
*
|
145 |
-
*/
|
146 |
-
public static function start_http( $starttype, $jobid = 0 ) {
|
147 |
-
|
148 |
-
//load text domain
|
149 |
-
$log_level = get_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
150 |
-
if ( strstr( $log_level, 'translated' ) ) {
|
151 |
-
BackWPup::load_text_domain();
|
152 |
-
} else {
|
153 |
-
add_filter( 'override_load_textdomain', '__return_true' );
|
154 |
-
$GLOBALS['l10n'] = array();
|
155 |
-
}
|
156 |
-
|
157 |
-
if ( $starttype !== 'restart' ) {
|
158 |
-
|
159 |
-
//check job id exists
|
160 |
-
if ( $jobid !== BackWPup_Option::get( $jobid, 'jobid' ) ) {
|
161 |
-
return false;
|
162 |
-
}
|
163 |
-
|
164 |
-
//check folders
|
165 |
-
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
166 |
-
$folder_message_log = BackWPup_File::check_folder( BackWPup_File::get_absolute_path( $log_folder ) );
|
167 |
-
$folder_message_temp = BackWPup_File::check_folder( BackWPup::get_plugin_data( 'TEMP' ), true );
|
168 |
-
if ( ! empty( $folder_message_log ) || ! empty( $folder_message_temp ) ) {
|
169 |
-
BackWPup_Admin::message( $folder_message_log, true );
|
170 |
-
BackWPup_Admin::message( $folder_message_temp, true );
|
171 |
-
return false;
|
172 |
-
}
|
173 |
-
}
|
174 |
-
|
175 |
-
// redirect
|
176 |
-
if ( $starttype === 'runnowalt' ) {
|
177 |
-
ob_start();
|
178 |
-
wp_redirect( add_query_arg( array( 'page' => 'backwpupjobs' ), network_admin_url( 'admin.php' ) ) );
|
179 |
-
echo ' ';
|
180 |
-
flush();
|
181 |
-
if ( $level = ob_get_level() ) {
|
182 |
-
for ( $i = 0; $i < $level; $i ++ ) {
|
183 |
-
ob_end_clean();
|
184 |
-
}
|
185 |
-
}
|
186 |
-
}
|
187 |
-
|
188 |
-
// Should be preventing doubled running job's on http requests
|
189 |
-
$random = mt_rand( 10, 90 ) * 10000;
|
190 |
-
usleep( $random );
|
191 |
-
|
192 |
-
//check running job
|
193 |
-
$backwpup_job_object = self::get_working_data();
|
194 |
-
//start class
|
195 |
-
if ( ! $backwpup_job_object && in_array( $starttype, array( 'runnow', 'runnowalt', 'runext', 'cronrun' ), true ) && $jobid ) {
|
196 |
-
//schedule restart event
|
197 |
-
wp_schedule_single_event( time() + 60, 'backwpup_cron', array( 'id' => 'restart' ) );
|
198 |
-
//start job
|
199 |
-
$backwpup_job_object = new self();
|
200 |
-
$backwpup_job_object->create( $starttype, $jobid );
|
201 |
-
}
|
202 |
-
if ( $backwpup_job_object ) {
|
203 |
-
$backwpup_job_object->run();
|
204 |
-
}
|
205 |
-
}
|
206 |
-
|
207 |
-
/**
|
208 |
-
*
|
209 |
-
* Get data off a working job
|
210 |
-
*
|
211 |
-
* @return bool|object BackWPup_Job Object or Bool if file not exits
|
212 |
-
*/
|
213 |
-
public static function get_working_data() {
|
214 |
-
|
215 |
-
if ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
|
216 |
-
clearstatcache( true, BackWPup::get_plugin_data( 'running_file' ) );
|
217 |
-
} else {
|
218 |
-
clearstatcache();
|
219 |
-
}
|
220 |
-
|
221 |
-
if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
|
222 |
-
return false;
|
223 |
-
}
|
224 |
-
|
225 |
-
$file_data = file_get_contents( BackWPup::get_plugin_data( 'running_file' ), false, null, 8 );
|
226 |
-
if ( empty( $file_data ) ) {
|
227 |
-
return false;
|
228 |
-
}
|
229 |
-
|
230 |
-
if ( $job_object = unserialize( $file_data ) ) {
|
231 |
-
if ( $job_object instanceof BackWPup_Job ) {
|
232 |
-
return $job_object;
|
233 |
-
}
|
234 |
-
}
|
235 |
-
|
236 |
-
return false;
|
237 |
-
|
238 |
-
}
|
239 |
-
|
240 |
-
/**
|
241 |
-
*
|
242 |
-
* This starts or restarts the job working
|
243 |
-
*
|
244 |
-
* @param string $start_type Start types are 'runnow', 'runnowalt', 'cronrun', 'runext', 'runcli'
|
245 |
-
* @param array|int $job_id The id of job of a job to start
|
246 |
-
*/
|
247 |
-
private function create( $start_type, $job_id = 0 ) {
|
248 |
-
global $wpdb;
|
249 |
-
/* @var wpdb $wpdb */
|
250 |
-
|
251 |
-
//check startype
|
252 |
-
if ( ! in_array( $start_type, array( 'runnow', 'runnowalt', 'cronrun', 'runext', 'runcli' ), true ) ) {
|
253 |
-
return;
|
254 |
-
}
|
255 |
-
|
256 |
-
if ( $job_id ) {
|
257 |
-
$this->job = BackWPup_Option::get_job( $job_id );
|
258 |
-
} else {
|
259 |
-
return;
|
260 |
-
}
|
261 |
-
|
262 |
-
$this->start_time = current_time( 'timestamp' );
|
263 |
-
$this->lastmsg = __( 'Starting job', 'backwpup' );
|
264 |
-
//set Logfile
|
265 |
-
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
266 |
-
$log_folder = BackWPup_File::get_absolute_path( $log_folder );
|
267 |
-
$this->logfile = $log_folder . 'backwpup_log_' . BackWPup::get_plugin_data( 'hash' ) . '_' . date( 'Y-m-d_H-i-s', current_time( 'timestamp' ) ) . '.html';
|
268 |
-
//write settings to job
|
269 |
-
BackWPup_Option::update( $this->job['jobid'], 'lastrun', $this->start_time );
|
270 |
-
BackWPup_Option::update( $this->job['jobid'], 'logfile', $this->logfile ); //Set current logfile
|
271 |
-
BackWPup_Option::update( $this->job['jobid'], 'lastbackupdownloadurl', '' );
|
272 |
-
//Set needed job values
|
273 |
-
$this->timestamp_last_update = microtime( true );
|
274 |
-
$this->exclude_from_backup = explode( ',', trim( $this->job['fileexclude'] ) );
|
275 |
-
$this->exclude_from_backup = array_unique( $this->exclude_from_backup );
|
276 |
-
//setup job steps
|
277 |
-
$this->steps_data['CREATE']['CALLBACK'] = '';
|
278 |
-
$this->steps_data['CREATE']['NAME'] = __( 'Job Start', 'backwpup' );
|
279 |
-
$this->steps_data['CREATE']['STEP_TRY'] = 0;
|
280 |
-
//ADD Job types file
|
281 |
-
/* @var $job_type_class BackWPup_JobTypes */
|
282 |
-
$job_need_dest = false;
|
283 |
-
if ( $job_types = BackWPup::get_job_types() ) {
|
284 |
-
foreach ( $job_types as $id => $job_type_class ) {
|
285 |
-
if ( in_array( $id, $this->job['type'], true ) && $job_type_class->creates_file() ) {
|
286 |
-
$this->steps_todo[] = 'JOB_' . $id;
|
287 |
-
$this->steps_data[ 'JOB_' . $id ]['NAME'] = $job_type_class->info['description'];
|
288 |
-
$this->steps_data[ 'JOB_' . $id ]['STEP_TRY'] = 0;
|
289 |
-
$this->steps_data[ 'JOB_' . $id ]['SAVE_STEP_TRY'] = 0;
|
290 |
-
$job_need_dest = true;
|
291 |
-
}
|
292 |
-
}
|
293 |
-
}
|
294 |
-
//add destinations and create archive if a job where files to backup
|
295 |
-
if ( $job_need_dest ) {
|
296 |
-
//Create manifest file
|
297 |
-
$this->steps_todo[] = 'CREATE_MANIFEST';
|
298 |
-
$this->steps_data['CREATE_MANIFEST']['NAME'] = __( 'Creates manifest file', 'backwpup' );
|
299 |
-
$this->steps_data['CREATE_MANIFEST']['STEP_TRY'] = 0;
|
300 |
-
$this->steps_data['CREATE_MANIFEST']['SAVE_STEP_TRY'] = 0;
|
301 |
-
//Add archive creation and backup filename on backup type archive
|
302 |
-
if ( $this->job['backuptype'] == 'archive' ) {
|
303 |
-
//get Backup folder if destination folder set
|
304 |
-
if ( in_array( 'FOLDER', $this->job['destinations'], true ) ) {
|
305 |
-
$this->backup_folder = $this->job['backupdir'];
|
306 |
-
//check backup folder
|
307 |
-
if ( ! empty( $this->backup_folder ) ) {
|
308 |
-
$this->backup_folder = BackWPup_File::get_absolute_path( $this->backup_folder );
|
309 |
-
$this->job['backupdir'] = $this->backup_folder;
|
310 |
-
}
|
311 |
-
}
|
312 |
-
//set temp folder to backup folder if not set because we need one
|
313 |
-
if ( ! $this->backup_folder || $this->backup_folder == '/' ) {
|
314 |
-
$this->backup_folder = BackWPup::get_plugin_data( 'TEMP' );
|
315 |
-
}
|
316 |
-
//Create backup archive full file name
|
317 |
-
$this->backup_file = $this->generate_filename( $this->job['archivename'], $this->job['archiveformat'] );
|
318 |
-
//add archive create
|
319 |
-
$this->steps_todo[] = 'CREATE_ARCHIVE';
|
320 |
-
$this->steps_data['CREATE_ARCHIVE']['NAME'] = __( 'Creates archive', 'backwpup' );
|
321 |
-
$this->steps_data['CREATE_ARCHIVE']['STEP_TRY'] = 0;
|
322 |
-
$this->steps_data['CREATE_ARCHIVE']['SAVE_STEP_TRY'] = 0;
|
323 |
-
}
|
324 |
-
//ADD Destinations
|
325 |
-
/* @var BackWPup_Destinations $dest_class */
|
326 |
-
foreach ( BackWPup::get_registered_destinations() as $id => $dest ) {
|
327 |
-
if ( ! in_array( $id, $this->job['destinations'], true ) || empty( $dest['class'] ) ) {
|
328 |
-
continue;
|
329 |
-
}
|
330 |
-
$dest_class = BackWPup::get_destination( $id );
|
331 |
-
if ( $dest_class->can_run( $this->job ) ) {
|
332 |
-
if ( $this->job['backuptype'] == 'sync' ) {
|
333 |
-
if ( $dest['can_sync'] ) {
|
334 |
-
$this->steps_todo[] = 'DEST_SYNC_' . $id;
|
335 |
-
$this->steps_data[ 'DEST_SYNC_' . $id ]['NAME'] = $dest['info']['description'];
|
336 |
-
$this->steps_data[ 'DEST_SYNC_' . $id ]['STEP_TRY'] = 0;
|
337 |
-
$this->steps_data[ 'DEST_SYNC_' . $id ]['SAVE_STEP_TRY'] = 0;
|
338 |
-
}
|
339 |
-
} else {
|
340 |
-
$this->steps_todo[] = 'DEST_' . $id;
|
341 |
-
$this->steps_data[ 'DEST_' . $id ]['NAME'] = $dest['info']['description'];
|
342 |
-
$this->steps_data[ 'DEST_' . $id ]['STEP_TRY'] = 0;
|
343 |
-
$this->steps_data[ 'DEST_' . $id ]['SAVE_STEP_TRY'] = 0;
|
344 |
-
}
|
345 |
-
}
|
346 |
-
}
|
347 |
-
}
|
348 |
-
//ADD Job type no file
|
349 |
-
if ( $job_types = BackWPup::get_job_types() ) {
|
350 |
-
foreach ( $job_types as $id => $job_type_class ) {
|
351 |
-
if ( in_array( $id, $this->job['type'], true ) && ! $job_type_class->creates_file() ) {
|
352 |
-
$this->steps_todo[] = 'JOB_' . $id;
|
353 |
-
$this->steps_data[ 'JOB_' . $id ]['NAME'] = $job_type_class->info['description'];
|
354 |
-
$this->steps_data[ 'JOB_' . $id ]['STEP_TRY'] = 0;
|
355 |
-
$this->steps_data[ 'JOB_' . $id ]['SAVE_STEP_TRY'] = 0;
|
356 |
-
}
|
357 |
-
}
|
358 |
-
}
|
359 |
-
$this->steps_todo[] = 'END';
|
360 |
-
$this->steps_data['END']['NAME'] = __( 'End of Job', 'backwpup' );
|
361 |
-
$this->steps_data['END']['STEP_TRY'] = 1;
|
362 |
-
//must write working data
|
363 |
-
$this->write_running_file();
|
364 |
-
|
365 |
-
//set log level
|
366 |
-
$this->log_level = get_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
367 |
-
if ( ! in_array( $this->log_level, array( 'normal_translated', 'normal', 'debug_translated', 'debug' ), true ) ) {
|
368 |
-
$this->log_level = 'normal_translated';
|
369 |
-
}
|
370 |
-
//create log file
|
371 |
-
$head = '';
|
372 |
-
$info = '';
|
373 |
-
$head .= "<!DOCTYPE html>" . PHP_EOL;
|
374 |
-
$head .= "<html lang=\"" . str_replace( '_', '-', get_locale() ) . "\">" . PHP_EOL;
|
375 |
-
$head .= "<head>" . PHP_EOL;
|
376 |
-
$head .= "<meta charset=\"" . get_bloginfo( 'charset' ) . "\" />" . PHP_EOL;
|
377 |
-
$head .= "<title>" . sprintf( __( 'BackWPup log for %1$s from %2$s at %3$s', 'backwpup' ), $this->job['name'], date_i18n( get_option( 'date_format' ) ), date_i18n( get_option( 'time_format' ) ) ) . "</title>" . PHP_EOL;
|
378 |
-
$head .= "<meta name=\"robots\" content=\"noindex, nofollow\" />" . PHP_EOL;
|
379 |
-
$head .= "<meta name=\"copyright\" content=\"Copyright © 2012 - " . date( 'Y' ) . " Inpsyde GmbH\" />" . PHP_EOL;
|
380 |
-
$head .= "<meta name=\"author\" content=\"Inpsyde GmbH\" />" . PHP_EOL;
|
381 |
-
$head .= "<meta name=\"generator\" content=\"BackWPup " . BackWPup::get_plugin_data( 'Version' ) . "\" />" . PHP_EOL;
|
382 |
-
$head .= "<meta http-equiv=\"cache-control\" content=\"no-cache\" />" . PHP_EOL;
|
383 |
-
$head .= "<meta http-equiv=\"pragma\" content=\"no-cache\" />" . PHP_EOL;
|
384 |
-
$head .= "<meta name=\"date\" content=\"" . date( 'c' ) . "\" />" . PHP_EOL;
|
385 |
-
$head .= str_pad( '<meta name="backwpup_errors" content="0" />', 100 ) . PHP_EOL;
|
386 |
-
$head .= str_pad( '<meta name="backwpup_warnings" content="0" />', 100 ) . PHP_EOL;
|
387 |
-
$head .= "<meta name=\"backwpup_jobid\" content=\"" . $this->job['jobid'] . "\" />" . PHP_EOL;
|
388 |
-
$head .= "<meta name=\"backwpup_jobname\" content=\"" . esc_attr( $this->job['name'] ) . "\" />" . PHP_EOL;
|
389 |
-
$head .= "<meta name=\"backwpup_jobtype\" content=\"" . implode( '+', $this->job['type'] ) . "\" />" . PHP_EOL;
|
390 |
-
$head .= str_pad( '<meta name="backwpup_backupfilesize" content="0" />', 100 ) . PHP_EOL;
|
391 |
-
$head .= str_pad( '<meta name="backwpup_jobruntime" content="0" />', 100 ) . PHP_EOL;
|
392 |
-
$head .= '</head>' . PHP_EOL;
|
393 |
-
$head .= '<body style="margin:0;padding:3px;font-family:monospace;font-size:12px;line-height:15px;background-color:black;color:#c0c0c0;white-space:nowrap;">' . PHP_EOL;
|
394 |
-
$info .= sprintf( _x( '[INFO] %1$s %2$s; A project of Inpsyde GmbH', 'Plugin name; Plugin Version; plugin url', 'backwpup' ), BackWPup::get_plugin_data( 'name' ), BackWPup::get_plugin_data( 'Version' ), __( 'http://backwpup.com', 'backwpup' ) ) . '<br />' . PHP_EOL;
|
395 |
-
$info .= sprintf( _x( '[INFO] WordPress %1$s on %2$s', 'WordPress Version; Blog url', 'backwpup' ), BackWPup::get_plugin_data( 'wp_version' ), esc_attr( site_url( '/' ) ) ) . '<br />' . PHP_EOL;
|
396 |
-
$level = __( 'Normal', 'backwpup' );
|
397 |
-
$translated = '';
|
398 |
-
if ( $this->is_debug() ) {
|
399 |
-
$level = __( 'Debug', 'backwpup' );
|
400 |
-
}
|
401 |
-
if ( is_textdomain_loaded( 'backwpup' ) ) {
|
402 |
-
$translated = __( '(translated)', 'backwpup' );
|
403 |
-
}
|
404 |
-
$info .= sprintf( __( '[INFO] Log Level: %1$s %2$s', 'backwpup' ), $level, $translated ) . '<br />' . PHP_EOL;
|
405 |
-
$job_name = esc_attr( $this->job['name'] );
|
406 |
-
if ( $this->is_debug() ) {
|
407 |
-
$job_name .= '; ' . implode( '+', $this->job['type'] );
|
408 |
-
}
|
409 |
-
$info .= sprintf( __( '[INFO] BackWPup job: %1$s', 'backwpup' ), $job_name ) . '<br />' . PHP_EOL;
|
410 |
-
if ( $this->is_debug() ) {
|
411 |
-
$current_user = wp_get_current_user();
|
412 |
-
$info .= sprintf( __( '[INFO] Runs with user: %1$s (%2$d) ', 'backwpup' ), $current_user->user_login, $current_user->ID ) . '<br />' . PHP_EOL;
|
413 |
-
}
|
414 |
-
if ( $this->job['activetype'] === 'wpcron' ) {
|
415 |
-
//check next run
|
416 |
-
$cron_next = wp_next_scheduled( 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
417 |
-
if ( ! $cron_next || $cron_next < time() ) {
|
418 |
-
wp_unschedule_event( $cron_next, 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
419 |
-
$cron_next = BackWPup_Cron::cron_next( $this->job['cron'] );
|
420 |
-
wp_schedule_single_event( $cron_next, 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
421 |
-
$cron_next = wp_next_scheduled( 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
422 |
-
}
|
423 |
-
//output scheduling
|
424 |
-
if ( $this->is_debug() ) {
|
425 |
-
if ( ! $cron_next ) {
|
426 |
-
$cron_next = __( 'Not scheduled!', 'backwpup' );
|
427 |
-
} else {
|
428 |
-
$cron_next = date_i18n( 'D, j M Y @ H:i', $cron_next + ( get_option( 'gmt_offset' ) * 3600 ), true );
|
429 |
-
}
|
430 |
-
$info .= sprintf( __( '[INFO] Cron: %s; Next: %s ', 'backwpup' ), $this->job['cron'], $cron_next ) . '<br />' . PHP_EOL;
|
431 |
-
}
|
432 |
-
} elseif ( $this->job['activetype'] == 'link' && $this->is_debug() ) {
|
433 |
-
$info .= __( '[INFO] BackWPup job start with link is active', 'backwpup' ) . '<br />' . PHP_EOL;
|
434 |
-
} elseif ( $this->job['activetype'] == 'easycron' && $this->is_debug() ) {
|
435 |
-
$info .= __( '[INFO] BackWPup job start with EasyCron.com', 'backwpup' ) . '<br />' . PHP_EOL;
|
436 |
-
//output scheduling
|
437 |
-
if ( $this->is_debug() ) {
|
438 |
-
$cron_next = BackWPup_Cron::cron_next( $this->job['cron'] );
|
439 |
-
$cron_next = date_i18n( 'D, j M Y @ H:i', $cron_next + ( get_option( 'gmt_offset' ) * 3600 ), true );
|
440 |
-
$info .= sprintf( __( '[INFO] Cron: %s; Next: %s ', 'backwpup' ), $this->job['cron'], $cron_next ) . '<br />' . PHP_EOL;
|
441 |
-
}
|
442 |
-
} elseif ( $this->is_debug() ) {
|
443 |
-
$info .= __( '[INFO] BackWPup no automatic job start configured', 'backwpup' ) . '<br />' . PHP_EOL;
|
444 |
-
}
|
445 |
-
if ( $this->is_debug() ) {
|
446 |
-
if ( $start_type == 'cronrun' ) {
|
447 |
-
$info .= __( '[INFO] BackWPup job started from wp-cron', 'backwpup' ) . '<br />' . PHP_EOL;
|
448 |
-
} elseif ( $start_type == 'runnow' || $start_type == 'runnowalt' ) {
|
449 |
-
$info .= __( '[INFO] BackWPup job started manually', 'backwpup' ) . '<br />' . PHP_EOL;
|
450 |
-
} elseif ( $start_type == 'runext' ) {
|
451 |
-
$info .= __( '[INFO] BackWPup job started from external url', 'backwpup' ) . '<br />' . PHP_EOL;
|
452 |
-
} elseif ( $start_type == 'runcli' ) {
|
453 |
-
$info .= __( '[INFO] BackWPup job started form commandline interface', 'backwpup' ) . '<br />' . PHP_EOL;
|
454 |
-
}
|
455 |
-
$bit = '';
|
456 |
-
if ( PHP_INT_SIZE === 4 ) {
|
457 |
-
$bit = ' (32bit)';
|
458 |
-
}
|
459 |
-
if ( PHP_INT_SIZE === 8 ) {
|
460 |
-
$bit = ' (64bit)';
|
461 |
-
}
|
462 |
-
$info .= __( '[INFO] PHP ver.:', 'backwpup' ) . ' ' . PHP_VERSION . $bit . '; ' . PHP_SAPI . '; ' . PHP_OS . '<br />' . PHP_EOL;
|
463 |
-
$info .= sprintf( __( '[INFO] Maximum PHP script execution time is %1$d seconds', 'backwpup' ), ini_get( 'max_execution_time' ) ) . '<br />' . PHP_EOL;
|
464 |
-
if ( php_sapi_name() != 'cli' ) {
|
465 |
-
$job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
|
466 |
-
if ( ! empty( $job_max_execution_time ) ) {
|
467 |
-
$info .= sprintf( __( '[INFO] Script restart time is configured to %1$d seconds', 'backwpup' ), $job_max_execution_time ) . '<br />' . PHP_EOL;
|
468 |
-
}
|
469 |
-
}
|
470 |
-
$info .= sprintf( __( '[INFO] MySQL ver.: %s', 'backwpup' ), $wpdb->get_var( "SELECT VERSION() AS version" ) ) . '<br />' . PHP_EOL;
|
471 |
-
if ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
|
472 |
-
$info .= sprintf( __( '[INFO] Web Server: %s', 'backwpup' ), $_SERVER['SERVER_SOFTWARE'] ) . '<br />' . PHP_EOL;
|
473 |
-
}
|
474 |
-
if ( function_exists( 'curl_init' ) ) {
|
475 |
-
$curlversion = curl_version();
|
476 |
-
$info .= sprintf( __( '[INFO] curl ver.: %1$s; %2$s', 'backwpup' ), $curlversion['version'], $curlversion['ssl_version'] ) . '<br />' . PHP_EOL;
|
477 |
-
}
|
478 |
-
$info .= sprintf( __( '[INFO] Temp folder is: %s', 'backwpup' ), BackWPup::get_plugin_data( 'TEMP' ) ) . '<br />' . PHP_EOL;
|
479 |
-
}
|
480 |
-
if ( $this->is_debug() ) {
|
481 |
-
$logfile = $this->logfile;
|
482 |
-
} else {
|
483 |
-
$logfile = basename( $this->logfile );
|
484 |
-
}
|
485 |
-
$info .= sprintf( __( '[INFO] Logfile is: %s', 'backwpup' ), $logfile ) . '<br />' . PHP_EOL;
|
486 |
-
if ( ! empty( $this->backup_file ) && $this->job['backuptype'] === 'archive' ) {
|
487 |
-
if ( $this->is_debug() ) {
|
488 |
-
$backupfile = $this->backup_folder . $this->backup_file;
|
489 |
-
} else {
|
490 |
-
$backupfile = $this->backup_file;
|
491 |
-
}
|
492 |
-
$info .= sprintf( __( '[INFO] Backup file is: %s', 'backwpup' ), $backupfile ) . '<br />' . PHP_EOL;
|
493 |
-
} else {
|
494 |
-
$info .= sprintf( __( '[INFO] Backup type is: %s', 'backwpup' ), $this->job['backuptype'] ) . '<br />' . PHP_EOL;
|
495 |
-
}
|
496 |
-
//output info on cli
|
497 |
-
if ( php_sapi_name() == 'cli' && defined( 'STDOUT' ) ) {
|
498 |
-
fwrite( STDOUT, strip_tags( $info ) );
|
499 |
-
}
|
500 |
-
if ( ! file_put_contents( $this->logfile, $head . $info, FILE_APPEND ) ) {
|
501 |
-
$this->logfile = '';
|
502 |
-
$this->log( __( 'Could not write log file', 'backwpup' ), E_USER_ERROR );
|
503 |
-
}
|
504 |
-
//test for destinations
|
505 |
-
if ( $job_need_dest ) {
|
506 |
-
$desttest = false;
|
507 |
-
foreach ( $this->steps_todo as $deststeptest ) {
|
508 |
-
if ( substr( $deststeptest, 0, 5 ) == 'DEST_' ) {
|
509 |
-
$desttest = true;
|
510 |
-
break;
|
511 |
-
}
|
512 |
-
}
|
513 |
-
if ( ! $desttest ) {
|
514 |
-
$this->log( __( 'No destination correctly defined for backup! Please correct job settings.', 'backwpup' ), E_USER_ERROR );
|
515 |
-
$this->steps_todo = array( 'END' );
|
516 |
-
}
|
517 |
-
}
|
518 |
-
//test backup folder
|
519 |
-
if ( ! empty( $this->backup_folder ) ) {
|
520 |
-
$folder_message = BackWPup_File::check_folder( $this->backup_folder, true );
|
521 |
-
if ( ! empty( $folder_message ) ) {
|
522 |
-
$this->log( $folder_message, E_USER_ERROR );
|
523 |
-
$this->steps_todo = array( 'END' );
|
524 |
-
}
|
525 |
-
}
|
526 |
-
|
527 |
-
//Set start as done
|
528 |
-
$this->steps_done[] = 'CREATE';
|
529 |
-
}
|
530 |
-
|
531 |
-
/**
|
532 |
-
* @param $name
|
533 |
-
* @param string $suffix
|
534 |
-
* @param bool $delete_temp_file
|
535 |
-
*
|
536 |
-
* @return string
|
537 |
-
*/
|
538 |
-
public function generate_filename( $name, $suffix = '', $delete_temp_file = true ) {
|
539 |
-
|
540 |
-
$local_time = current_time( 'timestamp' );
|
541 |
-
|
542 |
-
$datevars = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
|
543 |
-
$datevalues = array(
|
544 |
-
date( 'd', $local_time ),
|
545 |
-
date( 'j', $local_time ),
|
546 |
-
date( 'm', $local_time ),
|
547 |
-
date( 'n', $local_time ),
|
548 |
-
date( 'Y', $local_time ),
|
549 |
-
date( 'y', $local_time ),
|
550 |
-
date( 'a', $local_time ),
|
551 |
-
date( 'A', $local_time ),
|
552 |
-
date( 'B', $local_time ),
|
553 |
-
date( 'g', $local_time ),
|
554 |
-
date( 'G', $local_time ),
|
555 |
-
date( 'h', $local_time ),
|
556 |
-
date( 'H', $local_time ),
|
557 |
-
date( 'i', $local_time ),
|
558 |
-
date( 's', $local_time )
|
559 |
-
);
|
560 |
-
|
561 |
-
if ( $suffix ) {
|
562 |
-
$suffix = '.' . trim( $suffix, '. ' );
|
563 |
-
}
|
564 |
-
|
565 |
-
$name = str_replace( $datevars, $datevalues, self::sanitize_file_name( $name ) );
|
566 |
-
$name .= $suffix;
|
567 |
-
if ( $delete_temp_file && is_writeable( BackWPup::get_plugin_data( 'TEMP' ) . $name ) && ! is_dir( BackWPup::get_plugin_data( 'TEMP' ) . $name ) && ! is_link( BackWPup::get_plugin_data( 'TEMP' ) . $name ) ) {
|
568 |
-
unlink( BackWPup::get_plugin_data( 'TEMP' ) . $name );
|
569 |
-
}
|
570 |
-
|
571 |
-
return $name;
|
572 |
-
}
|
573 |
-
|
574 |
-
/**
|
575 |
-
* Sanitizes a filename, replacing whitespace with underscores.
|
576 |
-
*
|
577 |
-
* @param $filename
|
578 |
-
*
|
579 |
-
* @return mixed
|
580 |
-
*/
|
581 |
-
public static function sanitize_file_name( $filename ) {
|
582 |
-
|
583 |
-
$filename = trim( $filename );
|
584 |
-
|
585 |
-
$special_chars = array(
|
586 |
-
"?",
|
587 |
-
"[",
|
588 |
-
"]",
|
589 |
-
"/",
|
590 |
-
"\\",
|
591 |
-
"=",
|
592 |
-
"<",
|
593 |
-
">",
|
594 |
-
":",
|
595 |
-
";",
|
596 |
-
",",
|
597 |
-
"'",
|
598 |
-
"\"",
|
599 |
-
"&",
|
600 |
-
"$",
|
601 |
-
"#",
|
602 |
-
"*",
|
603 |
-
"(",
|
604 |
-
")",
|
605 |
-
"|",
|
606 |
-
"~",
|
607 |
-
"`",
|
608 |
-
"!",
|
609 |
-
"{",
|
610 |
-
"}",
|
611 |
-
chr( 0 )
|
612 |
-
);
|
613 |
-
|
614 |
-
$filename = str_replace( $special_chars, '', $filename );
|
615 |
-
|
616 |
-
$filename = str_replace( array( ' ', '%20', '+' ), '_', $filename );
|
617 |
-
$filename = str_replace( array( "\n", "\t", "\r" ), '-', $filename );
|
618 |
-
$filename = trim( $filename, '.-_' );
|
619 |
-
|
620 |
-
return $filename;
|
621 |
-
}
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
}
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
$
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
case
|
708 |
-
case
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
$message = __( '
|
717 |
-
break;
|
718 |
-
case
|
719 |
-
|
720 |
-
|
721 |
-
case
|
722 |
-
|
723 |
-
$
|
724 |
-
$
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
$output_message = '
|
761 |
-
|
762 |
-
}
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
//
|
772 |
-
if ( $
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
*
|
824 |
-
*
|
825 |
-
* @return
|
826 |
-
*/
|
827 |
-
public function
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
}
|
903 |
-
|
904 |
-
//check
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
}
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
-
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
) );
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
$query_args['
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
$query_args['_nonce']
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
$
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
$
|
1276 |
-
}
|
1277 |
-
|
1278 |
-
$
|
1279 |
-
'
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
'
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
$
|
1300 |
-
|
1301 |
-
|
1302 |
-
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
|
1307 |
-
|
1308 |
-
|
1309 |
-
|
1310 |
-
|
1311 |
-
|
1312 |
-
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
1325 |
-
|
1326 |
-
|
1327 |
-
if (
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
//
|
1344 |
-
$
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
$
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
1391 |
-
|
1392 |
-
|
1393 |
-
'
|
1394 |
-
|
1395 |
-
'
|
1396 |
-
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
|
1402 |
-
|
1403 |
-
|
1404 |
-
'
|
1405 |
-
|
1406 |
-
|
1407 |
-
|
1408 |
-
//'
|
1409 |
-
'
|
1410 |
-
'
|
1411 |
-
|
1412 |
-
|
1413 |
-
|
1414 |
-
|
1415 |
-
|
1416 |
-
|
1417 |
-
|
1418 |
-
|
1419 |
-
|
1420 |
-
|
1421 |
-
|
1422 |
-
|
1423 |
-
|
1424 |
-
|
1425 |
-
|
1426 |
-
|
1427 |
-
|
1428 |
-
|
1429 |
-
|
1430 |
-
|
1431 |
-
|
1432 |
-
|
1433 |
-
|
1434 |
-
|
1435 |
-
|
1436 |
-
|
1437 |
-
|
1438 |
-
|
1439 |
-
|
1440 |
-
|
1441 |
-
$this
|
1442 |
-
|
1443 |
-
|
1444 |
-
|
1445 |
-
|
1446 |
-
|
1447 |
-
|
1448 |
-
|
1449 |
-
|
1450 |
-
|
1451 |
-
|
1452 |
-
|
1453 |
-
|
1454 |
-
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
-
|
1461 |
-
|
1462 |
-
$
|
1463 |
-
|
1464 |
-
$
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
|
1469 |
-
|
1470 |
-
|
1471 |
-
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
1478 |
-
|
1479 |
-
|
1480 |
-
|
1481 |
-
|
1482 |
-
|
1483 |
-
|
1484 |
-
|
1485 |
-
|
1486 |
-
|
1487 |
-
|
1488 |
-
|
1489 |
-
|
1490 |
-
|
1491 |
-
|
1492 |
-
|
1493 |
-
|
1494 |
-
|
1495 |
-
|
1496 |
-
|
1497 |
-
|
1498 |
-
|
1499 |
-
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
-
|
1504 |
-
|
1505 |
-
|
1506 |
-
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
-
|
1512 |
-
|
1513 |
-
|
1514 |
-
|
1515 |
-
|
1516 |
-
|
1517 |
-
|
1518 |
-
|
1519 |
-
|
1520 |
-
|
1521 |
-
|
1522 |
-
|
1523 |
-
|
1524 |
-
|
1525 |
-
|
1526 |
-
|
1527 |
-
|
1528 |
-
|
1529 |
-
|
1530 |
-
|
1531 |
-
|
1532 |
-
|
1533 |
-
|
1534 |
-
|
1535 |
-
|
1536 |
-
|
1537 |
-
|
1538 |
-
|
1539 |
-
|
1540 |
-
|
1541 |
-
|
1542 |
-
|
1543 |
-
|
1544 |
-
|
1545 |
-
|
1546 |
-
|
1547 |
-
|
1548 |
-
|
1549 |
-
|
1550 |
-
|
1551 |
-
|
1552 |
-
|
1553 |
-
|
1554 |
-
|
1555 |
-
|
1556 |
-
|
1557 |
-
|
1558 |
-
|
1559 |
-
|
1560 |
-
|
1561 |
-
|
1562 |
-
|
1563 |
-
|
1564 |
-
|
1565 |
-
|
1566 |
-
|
1567 |
-
|
1568 |
-
|
1569 |
-
|
1570 |
-
|
1571 |
-
|
1572 |
-
|
1573 |
-
|
1574 |
-
|
1575 |
-
|
1576 |
-
|
1577 |
-
|
1578 |
-
|
1579 |
-
|
1580 |
-
|
1581 |
-
|
1582 |
-
|
1583 |
-
$
|
1584 |
-
|
1585 |
-
|
1586 |
-
|
1587 |
-
|
1588 |
-
|
1589 |
-
|
1590 |
-
|
1591 |
-
|
1592 |
-
|
1593 |
-
|
1594 |
-
|
1595 |
-
|
1596 |
-
|
1597 |
-
|
1598 |
-
|
1599 |
-
|
1600 |
-
|
1601 |
-
|
1602 |
-
|
1603 |
-
|
1604 |
-
|
1605 |
-
|
1606 |
-
|
1607 |
-
|
1608 |
-
|
1609 |
-
|
1610 |
-
|
1611 |
-
|
1612 |
-
|
1613 |
-
|
1614 |
-
|
1615 |
-
|
1616 |
-
|
1617 |
-
|
1618 |
-
|
1619 |
-
|
1620 |
-
|
1621 |
-
|
1622 |
-
|
1623 |
-
|
1624 |
-
|
1625 |
-
|
1626 |
-
|
1627 |
-
|
1628 |
-
|
1629 |
-
|
1630 |
-
|
1631 |
-
|
1632 |
-
|
1633 |
-
|
1634 |
-
|
1635 |
-
|
1636 |
-
|
1637 |
-
$
|
1638 |
-
|
1639 |
-
|
1640 |
-
|
1641 |
-
|
1642 |
-
|
1643 |
-
|
1644 |
-
|
1645 |
-
|
1646 |
-
|
1647 |
-
|
1648 |
-
|
1649 |
-
|
1650 |
-
|
1651 |
-
|
1652 |
-
|
1653 |
-
|
1654 |
-
|
1655 |
-
|
1656 |
-
|
1657 |
-
|
1658 |
-
|
1659 |
-
|
1660 |
-
|
1661 |
-
|
1662 |
-
|
1663 |
-
|
1664 |
-
|
1665 |
-
|
1666 |
-
|
1667 |
-
|
1668 |
-
|
1669 |
-
|
1670 |
-
|
1671 |
-
|
1672 |
-
|
1673 |
-
|
1674 |
-
|
1675 |
-
|
1676 |
-
|
1677 |
-
|
1678 |
-
|
1679 |
-
|
1680 |
-
|
1681 |
-
|
1682 |
-
|
1683 |
-
|
1684 |
-
|
1685 |
-
|
1686 |
-
|
1687 |
-
|
1688 |
-
|
1689 |
-
|
1690 |
-
|
1691 |
-
|
1692 |
-
|
1693 |
-
|
1694 |
-
|
1695 |
-
|
1696 |
-
|
1697 |
-
|
1698 |
-
|
1699 |
-
|
1700 |
-
|
1701 |
-
|
1702 |
-
|
1703 |
-
|
1704 |
-
|
1705 |
-
|
1706 |
-
|
1707 |
-
|
1708 |
-
|
1709 |
-
|
1710 |
-
|
1711 |
-
|
1712 |
-
|
1713 |
-
|
1714 |
-
|
1715 |
-
|
1716 |
-
|
1717 |
-
|
1718 |
-
|
1719 |
-
|
1720 |
-
|
1721 |
-
|
1722 |
-
|
1723 |
-
|
1724 |
-
|
1725 |
-
|
1726 |
-
|
1727 |
-
|
1728 |
-
|
1729 |
-
|
1730 |
-
|
1731 |
-
|
1732 |
-
|
1733 |
-
|
1734 |
-
|
1735 |
-
|
1736 |
-
|
1737 |
-
|
1738 |
-
|
1739 |
-
|
1740 |
-
|
1741 |
-
|
1742 |
-
|
1743 |
-
|
1744 |
-
|
1745 |
-
|
1746 |
-
|
1747 |
-
|
1748 |
-
|
1749 |
-
|
1750 |
-
|
1751 |
-
|
1752 |
-
|
1753 |
-
|
1754 |
-
|
1755 |
-
|
1756 |
-
|
1757 |
-
|
1758 |
-
|
1759 |
-
|
1760 |
-
|
1761 |
-
|
1762 |
-
|
1763 |
-
|
1764 |
-
|
1765 |
-
|
1766 |
-
|
1767 |
-
|
1768 |
-
|
1769 |
-
|
1770 |
-
|
1771 |
-
|
1772 |
-
|
1773 |
-
|
1774 |
-
|
1775 |
-
|
1776 |
-
|
1777 |
-
|
1778 |
-
|
1779 |
-
|
1780 |
-
|
1781 |
-
|
1782 |
-
|
1783 |
-
|
1784 |
-
|
1785 |
-
|
1786 |
-
|
1787 |
-
|
1788 |
-
|
1789 |
-
|
1790 |
-
|
1791 |
-
|
1792 |
-
|
1793 |
-
|
1794 |
-
$
|
1795 |
-
|
1796 |
-
|
1797 |
-
$
|
1798 |
-
|
1799 |
-
|
1800 |
-
|
1801 |
-
|
1802 |
-
|
1803 |
-
$
|
1804 |
-
|
1805 |
-
|
1806 |
-
|
1807 |
-
|
1808 |
-
|
1809 |
-
|
1810 |
-
|
1811 |
-
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
1815 |
-
|
1816 |
-
|
1817 |
-
|
1818 |
-
|
1819 |
-
|
1820 |
-
|
1821 |
-
|
1822 |
-
|
1823 |
-
|
1824 |
-
|
1825 |
-
|
1826 |
-
|
1827 |
-
|
1828 |
-
|
1829 |
-
|
1830 |
-
|
1831 |
-
|
1832 |
-
|
1833 |
-
|
1834 |
-
|
1835 |
-
|
1836 |
-
|
1837 |
-
|
1838 |
-
|
1839 |
-
$
|
1840 |
-
|
1841 |
-
|
1842 |
-
|
1843 |
-
|
1844 |
-
|
1845 |
-
|
1846 |
-
|
1847 |
-
|
1848 |
-
|
1849 |
-
|
1850 |
-
|
1851 |
-
|
1852 |
-
|
1853 |
-
$this->
|
1854 |
-
|
1855 |
-
|
1856 |
-
|
1857 |
-
|
1858 |
-
|
1859 |
-
|
1860 |
-
|
1861 |
-
|
1862 |
-
|
1863 |
-
|
1864 |
-
|
1865 |
-
|
1866 |
-
|
1867 |
-
|
1868 |
-
|
1869 |
-
|
1870 |
-
|
1871 |
-
|
1872 |
-
|
1873 |
-
|
1874 |
-
|
1875 |
-
|
1876 |
-
$
|
1877 |
-
|
1878 |
-
|
1879 |
-
|
1880 |
-
|
1881 |
-
$
|
1882 |
-
|
1883 |
-
|
1884 |
-
$
|
1885 |
-
|
1886 |
-
|
1887 |
-
|
1888 |
-
|
1889 |
-
|
1890 |
-
|
1891 |
-
|
1892 |
-
|
1893 |
-
|
1894 |
-
|
1895 |
-
|
1896 |
-
|
1897 |
-
|
1898 |
-
|
1899 |
-
|
1900 |
-
|
1901 |
-
|
1902 |
-
|
1903 |
-
|
1904 |
-
|
1905 |
-
if (
|
1906 |
-
|
1907 |
-
}
|
1908 |
-
|
1909 |
-
|
1910 |
-
|
1911 |
-
|
1912 |
-
$
|
1913 |
-
|
1914 |
-
|
1915 |
-
|
1916 |
-
|
1917 |
-
|
1918 |
-
|
1919 |
-
|
1920 |
-
|
1921 |
-
|
1922 |
-
|
1923 |
-
|
1924 |
-
|
1925 |
-
if ( !
|
1926 |
-
|
1927 |
-
}
|
1928 |
-
|
1929 |
-
|
1930 |
-
|
1931 |
-
|
1932 |
-
|
1933 |
-
|
1934 |
-
|
1935 |
-
|
1936 |
-
|
1937 |
-
|
1938 |
-
|
1939 |
-
|
1940 |
-
|
1941 |
-
|
1942 |
-
|
1943 |
-
|
1944 |
-
|
1945 |
-
|
1946 |
-
|
1947 |
-
|
1948 |
-
|
1949 |
-
|
1950 |
-
|
1951 |
-
|
1952 |
-
|
1953 |
-
)
|
1954 |
-
|
1955 |
-
|
1956 |
-
|
1957 |
-
|
1958 |
-
|
1959 |
-
|
1960 |
-
|
1961 |
-
|
1962 |
-
|
1963 |
-
|
1964 |
-
|
1965 |
-
|
1966 |
-
|
1967 |
-
|
1968 |
-
|
1969 |
-
|
1970 |
-
|
1971 |
-
|
1972 |
-
|
1973 |
-
|
1974 |
-
|
1975 |
-
|
1976 |
-
|
1977 |
-
|
1978 |
-
|
1979 |
-
|
1980 |
-
|
1981 |
-
|
1982 |
-
|
1983 |
-
|
1984 |
-
|
1985 |
-
|
1986 |
-
|
1987 |
-
|
1988 |
-
|
1989 |
-
|
1990 |
-
|
1991 |
-
|
1992 |
-
|
1993 |
-
|
1994 |
-
|
1995 |
-
|
1996 |
-
|
1997 |
-
|
1998 |
-
|
1999 |
-
|
2000 |
-
|
2001 |
-
|
2002 |
-
|
2003 |
-
|
2004 |
-
|
2005 |
-
|
2006 |
-
|
2007 |
-
|
2008 |
-
|
2009 |
-
|
2010 |
-
|
2011 |
-
|
2012 |
-
|
2013 |
-
|
2014 |
-
|
2015 |
-
public static function
|
2016 |
-
|
2017 |
-
|
2018 |
-
|
2019 |
-
|
2020 |
-
|
2021 |
-
|
2022 |
-
|
2023 |
-
|
2024 |
-
|
2025 |
-
|
2026 |
-
|
2027 |
-
|
2028 |
-
|
2029 |
-
|
2030 |
-
|
2031 |
-
|
2032 |
-
|
2033 |
-
|
2034 |
-
|
2035 |
-
|
2036 |
-
|
2037 |
-
|
2038 |
-
|
2039 |
-
|
2040 |
-
|
2041 |
-
|
2042 |
-
|
2043 |
-
|
2044 |
-
|
2045 |
-
|
2046 |
-
|
2047 |
-
|
2048 |
-
|
2049 |
-
|
2050 |
-
'
|
2051 |
-
'
|
2052 |
-
'
|
2053 |
-
'
|
2054 |
-
'
|
2055 |
-
'
|
2056 |
-
'
|
2057 |
-
'
|
2058 |
-
'
|
2059 |
-
'
|
2060 |
-
'
|
2061 |
-
'
|
2062 |
-
'
|
2063 |
-
'
|
2064 |
-
'
|
2065 |
-
'
|
2066 |
-
'
|
2067 |
-
'
|
2068 |
-
'
|
2069 |
-
'
|
2070 |
-
'
|
2071 |
-
'
|
2072 |
-
'
|
2073 |
-
'
|
2074 |
-
'
|
2075 |
-
'
|
2076 |
-
'
|
2077 |
-
'
|
2078 |
-
'
|
2079 |
-
'
|
2080 |
-
'
|
2081 |
-
'
|
2082 |
-
'
|
2083 |
-
'
|
2084 |
-
'
|
2085 |
-
'
|
2086 |
-
'
|
2087 |
-
'
|
2088 |
-
'
|
2089 |
-
'
|
2090 |
-
'
|
2091 |
-
'
|
2092 |
-
'
|
2093 |
-
'
|
2094 |
-
'
|
2095 |
-
'
|
2096 |
-
'
|
2097 |
-
'
|
2098 |
-
'
|
2099 |
-
'
|
2100 |
-
'
|
2101 |
-
'
|
2102 |
-
'
|
2103 |
-
'
|
2104 |
-
'
|
2105 |
-
'
|
2106 |
-
'
|
2107 |
-
'
|
2108 |
-
'
|
2109 |
-
'
|
2110 |
-
'
|
2111 |
-
'
|
2112 |
-
'
|
2113 |
-
'
|
2114 |
-
'
|
2115 |
-
'
|
2116 |
-
'
|
2117 |
-
'
|
2118 |
-
'
|
2119 |
-
'
|
2120 |
-
'
|
2121 |
-
'
|
2122 |
-
'
|
2123 |
-
'
|
2124 |
-
'
|
2125 |
-
'
|
2126 |
-
'
|
2127 |
-
'
|
2128 |
-
'
|
2129 |
-
'
|
2130 |
-
'
|
2131 |
-
'
|
2132 |
-
'
|
2133 |
-
'
|
2134 |
-
'
|
2135 |
-
'
|
2136 |
-
'
|
2137 |
-
'
|
2138 |
-
'
|
2139 |
-
'
|
2140 |
-
'
|
2141 |
-
'
|
2142 |
-
'
|
2143 |
-
'
|
2144 |
-
'
|
2145 |
-
'
|
2146 |
-
'
|
2147 |
-
'
|
2148 |
-
'
|
2149 |
-
'
|
2150 |
-
'
|
2151 |
-
'
|
2152 |
-
'
|
2153 |
-
'
|
2154 |
-
'
|
2155 |
-
'
|
2156 |
-
'
|
2157 |
-
'
|
2158 |
-
'
|
2159 |
-
'
|
2160 |
-
'
|
2161 |
-
'
|
2162 |
-
'
|
2163 |
-
'
|
2164 |
-
'
|
2165 |
-
'
|
2166 |
-
'
|
2167 |
-
'
|
2168 |
-
'
|
2169 |
-
'
|
2170 |
-
'
|
2171 |
-
'
|
2172 |
-
'
|
2173 |
-
'
|
2174 |
-
'
|
2175 |
-
'
|
2176 |
-
'
|
2177 |
-
'
|
2178 |
-
'
|
2179 |
-
'
|
2180 |
-
'
|
2181 |
-
'
|
2182 |
-
'
|
2183 |
-
'
|
2184 |
-
'
|
2185 |
-
'
|
2186 |
-
'
|
2187 |
-
'
|
2188 |
-
'
|
2189 |
-
'
|
2190 |
-
'
|
2191 |
-
'
|
2192 |
-
'
|
2193 |
-
'
|
2194 |
-
'
|
2195 |
-
'
|
2196 |
-
'
|
2197 |
-
'
|
2198 |
-
'
|
2199 |
-
|
2200 |
-
|
2201 |
-
|
2202 |
-
|
2203 |
-
|
2204 |
-
|
2205 |
-
|
2206 |
-
|
2207 |
-
|
2208 |
-
|
2209 |
-
|
2210 |
-
|
2211 |
-
|
2212 |
-
|
2213 |
-
|
2214 |
-
|
2215 |
-
|
2216 |
-
|
2217 |
-
|
2218 |
-
|
2219 |
-
|
2220 |
-
|
2221 |
-
|
2222 |
-
|
2223 |
-
|
2224 |
-
|
2225 |
-
|
2226 |
-
|
2227 |
-
|
2228 |
-
|
2229 |
-
|
2230 |
-
|
2231 |
-
|
2232 |
-
|
2233 |
-
|
2234 |
-
|
2235 |
-
|
2236 |
-
|
2237 |
-
|
2238 |
-
|
2239 |
-
|
2240 |
-
|
2241 |
-
|
2242 |
-
|
2243 |
-
|
2244 |
-
|
2245 |
-
|
2246 |
-
|
2247 |
-
|
2248 |
-
if (
|
2249 |
-
return
|
2250 |
-
}
|
2251 |
-
|
2252 |
-
return
|
2253 |
-
|
2254 |
-
|
2255 |
-
|
2256 |
-
|
2257 |
-
*
|
2258 |
-
|
2259 |
-
|
2260 |
-
|
2261 |
-
|
2262 |
-
|
2263 |
-
|
2264 |
-
|
2265 |
-
|
2266 |
-
|
2267 |
-
|
2268 |
-
|
2269 |
-
|
2270 |
-
|
2271 |
-
|
2272 |
-
|
2273 |
-
|
2274 |
-
|
2275 |
-
|
2276 |
-
|
2277 |
-
|
2278 |
-
|
2279 |
-
|
2280 |
-
|
2281 |
-
|
2282 |
-
|
2283 |
-
|
2284 |
-
|
2285 |
-
|
2286 |
-
|
2287 |
-
|
2288 |
-
|
2289 |
-
|
2290 |
-
|
2291 |
-
|
2292 |
-
|
2293 |
-
|
2294 |
-
|
2295 |
-
|
2296 |
-
|
2297 |
-
|
2298 |
-
|
2299 |
-
|
2300 |
-
|
2301 |
-
'
|
2302 |
-
'description' => _x( '
|
2303 |
-
'error' => E_USER_ERROR
|
2304 |
-
),
|
2305 |
-
'
|
2306 |
-
'description' => _x( '
|
2307 |
-
'error' =>
|
2308 |
-
),
|
2309 |
-
'
|
2310 |
-
'description' => _x( '
|
2311 |
-
'error' => E_USER_ERROR
|
2312 |
-
),
|
2313 |
-
'
|
2314 |
-
'description' => _x( '
|
2315 |
-
'error' =>
|
2316 |
-
),
|
2317 |
-
'
|
2318 |
-
'description' => _x( '
|
2319 |
-
'error' => E_USER_NOTICE
|
2320 |
-
),
|
2321 |
-
'
|
2322 |
-
'description' => _x( '
|
2323 |
-
'error' =>
|
2324 |
-
),
|
2325 |
-
'
|
2326 |
-
'description' => _x( '
|
2327 |
-
'error' => E_USER_ERROR
|
2328 |
-
),
|
2329 |
-
'
|
2330 |
-
'description' => _x( '
|
2331 |
-
'error' => E_USER_ERROR
|
2332 |
-
),
|
2333 |
-
'
|
2334 |
-
'description' => _x( '
|
2335 |
-
'error' =>
|
2336 |
-
),
|
2337 |
-
'
|
2338 |
-
'description' => _x( '
|
2339 |
-
'error' => E_USER_ERROR
|
2340 |
-
),
|
2341 |
-
|
2342 |
-
|
2343 |
-
|
2344 |
-
|
2345 |
-
|
2346 |
-
|
2347 |
-
|
2348 |
-
|
2349 |
-
|
2350 |
-
|
2351 |
-
|
2352 |
-
|
2353 |
-
|
2354 |
-
|
2355 |
-
|
2356 |
-
|
2357 |
-
|
2358 |
-
|
2359 |
-
|
2360 |
-
|
2361 |
-
|
2362 |
-
|
2363 |
-
|
2364 |
-
|
2365 |
-
|
2366 |
-
|
2367 |
-
|
2368 |
-
|
2369 |
-
|
2370 |
-
|
2371 |
-
|
2372 |
-
if (
|
2373 |
-
$
|
2374 |
-
|
2375 |
-
|
2376 |
-
|
2377 |
-
|
2378 |
-
|
2379 |
-
|
2380 |
-
|
2381 |
-
|
2382 |
-
|
2383 |
-
|
2384 |
-
|
2385 |
-
|
2386 |
-
|
2387 |
-
|
2388 |
-
|
2389 |
-
|
2390 |
-
|
2391 |
-
|
2392 |
-
|
2393 |
-
|
2394 |
-
|
2395 |
-
|
2396 |
-
|
2397 |
-
|
2398 |
-
|
2399 |
-
|
2400 |
-
|
2401 |
-
|
2402 |
-
|
2403 |
-
|
2404 |
-
|
2405 |
-
|
2406 |
-
|
2407 |
-
|
2408 |
-
|
2409 |
-
|
2410 |
-
|
2411 |
-
|
2412 |
-
|
2413 |
-
|
2414 |
-
|
2415 |
-
|
2416 |
-
|
2417 |
-
|
2418 |
-
|
2419 |
-
|
2420 |
-
|
2421 |
-
|
2422 |
-
|
2423 |
-
|
2424 |
-
$
|
2425 |
-
|
2426 |
-
|
2427 |
-
|
2428 |
-
|
2429 |
-
|
2430 |
-
|
2431 |
-
|
2432 |
-
|
2433 |
-
|
2434 |
-
|
2435 |
-
$this->
|
2436 |
-
|
2437 |
-
|
2438 |
-
|
2439 |
-
|
2440 |
-
|
2441 |
-
*
|
2442 |
-
*
|
2443 |
-
* @
|
2444 |
-
|
2445 |
-
|
2446 |
-
|
2447 |
-
|
2448 |
-
|
2449 |
-
|
2450 |
-
|
2451 |
-
|
2452 |
-
|
2453 |
-
|
2454 |
-
|
2455 |
-
|
2456 |
-
|
2457 |
-
|
2458 |
-
|
2459 |
-
|
2460 |
-
|
2461 |
-
|
2462 |
-
|
2463 |
-
|
2464 |
-
|
2465 |
-
|
2466 |
-
|
2467 |
-
|
2468 |
-
|
2469 |
-
|
2470 |
-
|
2471 |
-
|
2472 |
-
|
2473 |
-
|
2474 |
-
|
2475 |
-
|
2476 |
-
'
|
2477 |
-
'
|
2478 |
-
'
|
2479 |
-
'
|
2480 |
-
|
2481 |
-
|
2482 |
-
|
2483 |
-
|
2484 |
-
|
2485 |
-
|
2486 |
-
|
2487 |
-
|
2488 |
-
|
2489 |
-
|
2490 |
-
|
2491 |
-
|
2492 |
-
|
2493 |
-
|
2494 |
-
|
2495 |
-
|
2496 |
-
|
2497 |
-
|
2498 |
-
|
2499 |
-
|
2500 |
-
|
2501 |
-
|
2502 |
-
|
2503 |
-
|
2504 |
-
|
2505 |
-
|
2506 |
-
|
2507 |
-
|
2508 |
-
|
2509 |
-
|
2510 |
-
|
2511 |
-
|
2512 |
-
|
2513 |
-
|
2514 |
-
|
2515 |
-
|
2516 |
-
|
2517 |
-
|
2518 |
-
|
2519 |
-
}
|
2520 |
-
|
2521 |
-
return
|
2522 |
-
}
|
2523 |
-
|
2524 |
-
/**
|
2525 |
-
*
|
2526 |
-
*
|
2527 |
-
* @param
|
2528 |
-
* @param
|
2529 |
-
|
2530 |
-
|
2531 |
-
|
2532 |
-
|
2533 |
-
|
2534 |
-
|
2535 |
-
|
2536 |
-
|
2537 |
-
|
2538 |
-
|
2539 |
-
|
2540 |
-
|
2541 |
-
|
2542 |
-
$
|
2543 |
-
|
2544 |
-
|
2545 |
-
|
2546 |
-
|
2547 |
-
|
2548 |
-
|
2549 |
-
|
2550 |
-
}
|
2551 |
-
|
2552 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class in that the BackWPup job runs
|
5 |
+
*/
|
6 |
+
final class BackWPup_Job {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @var array of the job settings
|
10 |
+
*/
|
11 |
+
public $job = array();
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var int The timestamp when the job starts
|
15 |
+
*/
|
16 |
+
public $start_time = 0;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var string the logfile
|
20 |
+
*/
|
21 |
+
public $logfile = '';
|
22 |
+
/**
|
23 |
+
* @var array for temp values
|
24 |
+
*/
|
25 |
+
public $temp = array();
|
26 |
+
/**
|
27 |
+
* @var string Folder where is Backup files in
|
28 |
+
*/
|
29 |
+
public $backup_folder = '';
|
30 |
+
/**
|
31 |
+
* @var string the name of the Backup archive file
|
32 |
+
*/
|
33 |
+
public $backup_file = '';
|
34 |
+
/**
|
35 |
+
* @var int The size of the Backup archive file
|
36 |
+
*/
|
37 |
+
public $backup_filesize = 0;
|
38 |
+
/**
|
39 |
+
* @var int PID of script
|
40 |
+
*/
|
41 |
+
public $pid = 0;
|
42 |
+
/**
|
43 |
+
* @var float Timestamp of last update off .running file
|
44 |
+
*/
|
45 |
+
public $timestamp_last_update = 0;
|
46 |
+
/**
|
47 |
+
* @var int Number of warnings
|
48 |
+
*/
|
49 |
+
public $warnings = 0;
|
50 |
+
/**
|
51 |
+
* @var int Number of errors
|
52 |
+
*/
|
53 |
+
public $errors = 0;
|
54 |
+
/**
|
55 |
+
* @var string the last log notice message
|
56 |
+
*/
|
57 |
+
public $lastmsg = '';
|
58 |
+
/**
|
59 |
+
* @var string the last log error/waring message
|
60 |
+
*/
|
61 |
+
public $lasterrormsg = '';
|
62 |
+
/**
|
63 |
+
* @var array of steps to do
|
64 |
+
*/
|
65 |
+
public $steps_todo = array( 'CREATE' );
|
66 |
+
/**
|
67 |
+
* @var array of done steps
|
68 |
+
*/
|
69 |
+
public $steps_done = array();
|
70 |
+
/**
|
71 |
+
* @var array of steps data
|
72 |
+
*/
|
73 |
+
public $steps_data = array();
|
74 |
+
/**
|
75 |
+
* @var string working on step
|
76 |
+
*/
|
77 |
+
public $step_working = 'CREATE';
|
78 |
+
/**
|
79 |
+
* @var int Number of sub steps must do in step
|
80 |
+
*/
|
81 |
+
public $substeps_todo = 0;
|
82 |
+
/**
|
83 |
+
* @var int Number of sub steps done in step
|
84 |
+
*/
|
85 |
+
public $substeps_done = 0;
|
86 |
+
/**
|
87 |
+
* @var int Percent of steps done
|
88 |
+
*/
|
89 |
+
public $step_percent = 1;
|
90 |
+
/**
|
91 |
+
* @var int Percent of sub steps done
|
92 |
+
*/
|
93 |
+
public $substep_percent = 1;
|
94 |
+
/**
|
95 |
+
* @var array of files to additional to backup
|
96 |
+
*/
|
97 |
+
public $additional_files_to_backup = array();
|
98 |
+
/**
|
99 |
+
* @var array of files/folder to exclude from backup
|
100 |
+
*/
|
101 |
+
public $exclude_from_backup = array();
|
102 |
+
/**
|
103 |
+
* @var int count of affected files
|
104 |
+
*/
|
105 |
+
public $count_files = 0;
|
106 |
+
/**
|
107 |
+
* @var int count of affected file sizes
|
108 |
+
*/
|
109 |
+
public $count_files_size = 0;
|
110 |
+
/**
|
111 |
+
* @var int count of affected folders
|
112 |
+
*/
|
113 |
+
public $count_folder = 0;
|
114 |
+
/**
|
115 |
+
* If job aborted from user
|
116 |
+
* @var bool
|
117 |
+
*/
|
118 |
+
public $user_abort = false;
|
119 |
+
/**
|
120 |
+
* A uniqid ID uniqid('', true); to identify process
|
121 |
+
* @var string
|
122 |
+
*/
|
123 |
+
public $uniqid = '';
|
124 |
+
/**
|
125 |
+
* @var float Timestamp of script start
|
126 |
+
*/
|
127 |
+
private $timestamp_script_start = 0;
|
128 |
+
/**
|
129 |
+
* Stores data that will only used in a single run
|
130 |
+
* @var array
|
131 |
+
*/
|
132 |
+
private $run = array();
|
133 |
+
/**
|
134 |
+
* @var string logging level (normal|normal_untranslated|debug|debug_untranslated)
|
135 |
+
*/
|
136 |
+
private $log_level = 'normal';
|
137 |
+
|
138 |
+
/**
|
139 |
+
* @var int Signal of signal handler
|
140 |
+
*/
|
141 |
+
private $signal = 0;
|
142 |
+
|
143 |
+
/**
|
144 |
+
*
|
145 |
+
*/
|
146 |
+
public static function start_http( $starttype, $jobid = 0 ) {
|
147 |
+
|
148 |
+
//load text domain
|
149 |
+
$log_level = get_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
150 |
+
if ( strstr( $log_level, 'translated' ) ) {
|
151 |
+
BackWPup::load_text_domain();
|
152 |
+
} else {
|
153 |
+
add_filter( 'override_load_textdomain', '__return_true' );
|
154 |
+
$GLOBALS['l10n'] = array();
|
155 |
+
}
|
156 |
+
|
157 |
+
if ( $starttype !== 'restart' ) {
|
158 |
+
|
159 |
+
//check job id exists
|
160 |
+
if ( $jobid !== BackWPup_Option::get( $jobid, 'jobid' ) ) {
|
161 |
+
return false;
|
162 |
+
}
|
163 |
+
|
164 |
+
//check folders
|
165 |
+
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
166 |
+
$folder_message_log = BackWPup_File::check_folder( BackWPup_File::get_absolute_path( $log_folder ) );
|
167 |
+
$folder_message_temp = BackWPup_File::check_folder( BackWPup::get_plugin_data( 'TEMP' ), true );
|
168 |
+
if ( ! empty( $folder_message_log ) || ! empty( $folder_message_temp ) ) {
|
169 |
+
BackWPup_Admin::message( $folder_message_log, true );
|
170 |
+
BackWPup_Admin::message( $folder_message_temp, true );
|
171 |
+
return false;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
// redirect
|
176 |
+
if ( $starttype === 'runnowalt' ) {
|
177 |
+
ob_start();
|
178 |
+
wp_redirect( add_query_arg( array( 'page' => 'backwpupjobs' ), network_admin_url( 'admin.php' ) ) );
|
179 |
+
echo ' ';
|
180 |
+
flush();
|
181 |
+
if ( $level = ob_get_level() ) {
|
182 |
+
for ( $i = 0; $i < $level; $i ++ ) {
|
183 |
+
ob_end_clean();
|
184 |
+
}
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
// Should be preventing doubled running job's on http requests
|
189 |
+
$random = mt_rand( 10, 90 ) * 10000;
|
190 |
+
usleep( $random );
|
191 |
+
|
192 |
+
//check running job
|
193 |
+
$backwpup_job_object = self::get_working_data();
|
194 |
+
//start class
|
195 |
+
if ( ! $backwpup_job_object && in_array( $starttype, array( 'runnow', 'runnowalt', 'runext', 'cronrun' ), true ) && $jobid ) {
|
196 |
+
//schedule restart event
|
197 |
+
wp_schedule_single_event( time() + 60, 'backwpup_cron', array( 'id' => 'restart' ) );
|
198 |
+
//start job
|
199 |
+
$backwpup_job_object = new self();
|
200 |
+
$backwpup_job_object->create( $starttype, $jobid );
|
201 |
+
}
|
202 |
+
if ( $backwpup_job_object ) {
|
203 |
+
$backwpup_job_object->run();
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
*
|
209 |
+
* Get data off a working job
|
210 |
+
*
|
211 |
+
* @return bool|object BackWPup_Job Object or Bool if file not exits
|
212 |
+
*/
|
213 |
+
public static function get_working_data() {
|
214 |
+
|
215 |
+
if ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
|
216 |
+
clearstatcache( true, BackWPup::get_plugin_data( 'running_file' ) );
|
217 |
+
} else {
|
218 |
+
clearstatcache();
|
219 |
+
}
|
220 |
+
|
221 |
+
if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
|
222 |
+
return false;
|
223 |
+
}
|
224 |
+
|
225 |
+
$file_data = file_get_contents( BackWPup::get_plugin_data( 'running_file' ), false, null, 8 );
|
226 |
+
if ( empty( $file_data ) ) {
|
227 |
+
return false;
|
228 |
+
}
|
229 |
+
|
230 |
+
if ( $job_object = unserialize( $file_data ) ) {
|
231 |
+
if ( $job_object instanceof BackWPup_Job ) {
|
232 |
+
return $job_object;
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
+
return false;
|
237 |
+
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
*
|
242 |
+
* This starts or restarts the job working
|
243 |
+
*
|
244 |
+
* @param string $start_type Start types are 'runnow', 'runnowalt', 'cronrun', 'runext', 'runcli'
|
245 |
+
* @param array|int $job_id The id of job of a job to start
|
246 |
+
*/
|
247 |
+
private function create( $start_type, $job_id = 0 ) {
|
248 |
+
global $wpdb;
|
249 |
+
/* @var wpdb $wpdb */
|
250 |
+
|
251 |
+
//check startype
|
252 |
+
if ( ! in_array( $start_type, array( 'runnow', 'runnowalt', 'cronrun', 'runext', 'runcli' ), true ) ) {
|
253 |
+
return;
|
254 |
+
}
|
255 |
+
|
256 |
+
if ( $job_id ) {
|
257 |
+
$this->job = BackWPup_Option::get_job( $job_id );
|
258 |
+
} else {
|
259 |
+
return;
|
260 |
+
}
|
261 |
+
|
262 |
+
$this->start_time = current_time( 'timestamp' );
|
263 |
+
$this->lastmsg = __( 'Starting job', 'backwpup' );
|
264 |
+
//set Logfile
|
265 |
+
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
266 |
+
$log_folder = BackWPup_File::get_absolute_path( $log_folder );
|
267 |
+
$this->logfile = $log_folder . 'backwpup_log_' . BackWPup::get_plugin_data( 'hash' ) . '_' . date( 'Y-m-d_H-i-s', current_time( 'timestamp' ) ) . '.html';
|
268 |
+
//write settings to job
|
269 |
+
BackWPup_Option::update( $this->job['jobid'], 'lastrun', $this->start_time );
|
270 |
+
BackWPup_Option::update( $this->job['jobid'], 'logfile', $this->logfile ); //Set current logfile
|
271 |
+
BackWPup_Option::update( $this->job['jobid'], 'lastbackupdownloadurl', '' );
|
272 |
+
//Set needed job values
|
273 |
+
$this->timestamp_last_update = microtime( true );
|
274 |
+
$this->exclude_from_backup = explode( ',', trim( $this->job['fileexclude'] ) );
|
275 |
+
$this->exclude_from_backup = array_unique( $this->exclude_from_backup );
|
276 |
+
//setup job steps
|
277 |
+
$this->steps_data['CREATE']['CALLBACK'] = '';
|
278 |
+
$this->steps_data['CREATE']['NAME'] = __( 'Job Start', 'backwpup' );
|
279 |
+
$this->steps_data['CREATE']['STEP_TRY'] = 0;
|
280 |
+
//ADD Job types file
|
281 |
+
/* @var $job_type_class BackWPup_JobTypes */
|
282 |
+
$job_need_dest = false;
|
283 |
+
if ( $job_types = BackWPup::get_job_types() ) {
|
284 |
+
foreach ( $job_types as $id => $job_type_class ) {
|
285 |
+
if ( in_array( $id, $this->job['type'], true ) && $job_type_class->creates_file() ) {
|
286 |
+
$this->steps_todo[] = 'JOB_' . $id;
|
287 |
+
$this->steps_data[ 'JOB_' . $id ]['NAME'] = $job_type_class->info['description'];
|
288 |
+
$this->steps_data[ 'JOB_' . $id ]['STEP_TRY'] = 0;
|
289 |
+
$this->steps_data[ 'JOB_' . $id ]['SAVE_STEP_TRY'] = 0;
|
290 |
+
$job_need_dest = true;
|
291 |
+
}
|
292 |
+
}
|
293 |
+
}
|
294 |
+
//add destinations and create archive if a job where files to backup
|
295 |
+
if ( $job_need_dest ) {
|
296 |
+
//Create manifest file
|
297 |
+
$this->steps_todo[] = 'CREATE_MANIFEST';
|
298 |
+
$this->steps_data['CREATE_MANIFEST']['NAME'] = __( 'Creates manifest file', 'backwpup' );
|
299 |
+
$this->steps_data['CREATE_MANIFEST']['STEP_TRY'] = 0;
|
300 |
+
$this->steps_data['CREATE_MANIFEST']['SAVE_STEP_TRY'] = 0;
|
301 |
+
//Add archive creation and backup filename on backup type archive
|
302 |
+
if ( $this->job['backuptype'] == 'archive' ) {
|
303 |
+
//get Backup folder if destination folder set
|
304 |
+
if ( in_array( 'FOLDER', $this->job['destinations'], true ) ) {
|
305 |
+
$this->backup_folder = $this->job['backupdir'];
|
306 |
+
//check backup folder
|
307 |
+
if ( ! empty( $this->backup_folder ) ) {
|
308 |
+
$this->backup_folder = BackWPup_File::get_absolute_path( $this->backup_folder );
|
309 |
+
$this->job['backupdir'] = $this->backup_folder;
|
310 |
+
}
|
311 |
+
}
|
312 |
+
//set temp folder to backup folder if not set because we need one
|
313 |
+
if ( ! $this->backup_folder || $this->backup_folder == '/' ) {
|
314 |
+
$this->backup_folder = BackWPup::get_plugin_data( 'TEMP' );
|
315 |
+
}
|
316 |
+
//Create backup archive full file name
|
317 |
+
$this->backup_file = $this->generate_filename( $this->job['archivename'], $this->job['archiveformat'] );
|
318 |
+
//add archive create
|
319 |
+
$this->steps_todo[] = 'CREATE_ARCHIVE';
|
320 |
+
$this->steps_data['CREATE_ARCHIVE']['NAME'] = __( 'Creates archive', 'backwpup' );
|
321 |
+
$this->steps_data['CREATE_ARCHIVE']['STEP_TRY'] = 0;
|
322 |
+
$this->steps_data['CREATE_ARCHIVE']['SAVE_STEP_TRY'] = 0;
|
323 |
+
}
|
324 |
+
//ADD Destinations
|
325 |
+
/* @var BackWPup_Destinations $dest_class */
|
326 |
+
foreach ( BackWPup::get_registered_destinations() as $id => $dest ) {
|
327 |
+
if ( ! in_array( $id, $this->job['destinations'], true ) || empty( $dest['class'] ) ) {
|
328 |
+
continue;
|
329 |
+
}
|
330 |
+
$dest_class = BackWPup::get_destination( $id );
|
331 |
+
if ( $dest_class->can_run( $this->job ) ) {
|
332 |
+
if ( $this->job['backuptype'] == 'sync' ) {
|
333 |
+
if ( $dest['can_sync'] ) {
|
334 |
+
$this->steps_todo[] = 'DEST_SYNC_' . $id;
|
335 |
+
$this->steps_data[ 'DEST_SYNC_' . $id ]['NAME'] = $dest['info']['description'];
|
336 |
+
$this->steps_data[ 'DEST_SYNC_' . $id ]['STEP_TRY'] = 0;
|
337 |
+
$this->steps_data[ 'DEST_SYNC_' . $id ]['SAVE_STEP_TRY'] = 0;
|
338 |
+
}
|
339 |
+
} else {
|
340 |
+
$this->steps_todo[] = 'DEST_' . $id;
|
341 |
+
$this->steps_data[ 'DEST_' . $id ]['NAME'] = $dest['info']['description'];
|
342 |
+
$this->steps_data[ 'DEST_' . $id ]['STEP_TRY'] = 0;
|
343 |
+
$this->steps_data[ 'DEST_' . $id ]['SAVE_STEP_TRY'] = 0;
|
344 |
+
}
|
345 |
+
}
|
346 |
+
}
|
347 |
+
}
|
348 |
+
//ADD Job type no file
|
349 |
+
if ( $job_types = BackWPup::get_job_types() ) {
|
350 |
+
foreach ( $job_types as $id => $job_type_class ) {
|
351 |
+
if ( in_array( $id, $this->job['type'], true ) && ! $job_type_class->creates_file() ) {
|
352 |
+
$this->steps_todo[] = 'JOB_' . $id;
|
353 |
+
$this->steps_data[ 'JOB_' . $id ]['NAME'] = $job_type_class->info['description'];
|
354 |
+
$this->steps_data[ 'JOB_' . $id ]['STEP_TRY'] = 0;
|
355 |
+
$this->steps_data[ 'JOB_' . $id ]['SAVE_STEP_TRY'] = 0;
|
356 |
+
}
|
357 |
+
}
|
358 |
+
}
|
359 |
+
$this->steps_todo[] = 'END';
|
360 |
+
$this->steps_data['END']['NAME'] = __( 'End of Job', 'backwpup' );
|
361 |
+
$this->steps_data['END']['STEP_TRY'] = 1;
|
362 |
+
//must write working data
|
363 |
+
$this->write_running_file();
|
364 |
+
|
365 |
+
//set log level
|
366 |
+
$this->log_level = get_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
367 |
+
if ( ! in_array( $this->log_level, array( 'normal_translated', 'normal', 'debug_translated', 'debug' ), true ) ) {
|
368 |
+
$this->log_level = 'normal_translated';
|
369 |
+
}
|
370 |
+
//create log file
|
371 |
+
$head = '';
|
372 |
+
$info = '';
|
373 |
+
$head .= "<!DOCTYPE html>" . PHP_EOL;
|
374 |
+
$head .= "<html lang=\"" . str_replace( '_', '-', get_locale() ) . "\">" . PHP_EOL;
|
375 |
+
$head .= "<head>" . PHP_EOL;
|
376 |
+
$head .= "<meta charset=\"" . get_bloginfo( 'charset' ) . "\" />" . PHP_EOL;
|
377 |
+
$head .= "<title>" . sprintf( __( 'BackWPup log for %1$s from %2$s at %3$s', 'backwpup' ), $this->job['name'], date_i18n( get_option( 'date_format' ) ), date_i18n( get_option( 'time_format' ) ) ) . "</title>" . PHP_EOL;
|
378 |
+
$head .= "<meta name=\"robots\" content=\"noindex, nofollow\" />" . PHP_EOL;
|
379 |
+
$head .= "<meta name=\"copyright\" content=\"Copyright © 2012 - " . date( 'Y' ) . " Inpsyde GmbH\" />" . PHP_EOL;
|
380 |
+
$head .= "<meta name=\"author\" content=\"Inpsyde GmbH\" />" . PHP_EOL;
|
381 |
+
$head .= "<meta name=\"generator\" content=\"BackWPup " . BackWPup::get_plugin_data( 'Version' ) . "\" />" . PHP_EOL;
|
382 |
+
$head .= "<meta http-equiv=\"cache-control\" content=\"no-cache\" />" . PHP_EOL;
|
383 |
+
$head .= "<meta http-equiv=\"pragma\" content=\"no-cache\" />" . PHP_EOL;
|
384 |
+
$head .= "<meta name=\"date\" content=\"" . date( 'c' ) . "\" />" . PHP_EOL;
|
385 |
+
$head .= str_pad( '<meta name="backwpup_errors" content="0" />', 100 ) . PHP_EOL;
|
386 |
+
$head .= str_pad( '<meta name="backwpup_warnings" content="0" />', 100 ) . PHP_EOL;
|
387 |
+
$head .= "<meta name=\"backwpup_jobid\" content=\"" . $this->job['jobid'] . "\" />" . PHP_EOL;
|
388 |
+
$head .= "<meta name=\"backwpup_jobname\" content=\"" . esc_attr( $this->job['name'] ) . "\" />" . PHP_EOL;
|
389 |
+
$head .= "<meta name=\"backwpup_jobtype\" content=\"" . implode( '+', $this->job['type'] ) . "\" />" . PHP_EOL;
|
390 |
+
$head .= str_pad( '<meta name="backwpup_backupfilesize" content="0" />', 100 ) . PHP_EOL;
|
391 |
+
$head .= str_pad( '<meta name="backwpup_jobruntime" content="0" />', 100 ) . PHP_EOL;
|
392 |
+
$head .= '</head>' . PHP_EOL;
|
393 |
+
$head .= '<body style="margin:0;padding:3px;font-family:monospace;font-size:12px;line-height:15px;background-color:black;color:#c0c0c0;white-space:nowrap;">' . PHP_EOL;
|
394 |
+
$info .= sprintf( _x( '[INFO] %1$s %2$s; A project of Inpsyde GmbH', 'Plugin name; Plugin Version; plugin url', 'backwpup' ), BackWPup::get_plugin_data( 'name' ), BackWPup::get_plugin_data( 'Version' ), __( 'http://backwpup.com', 'backwpup' ) ) . '<br />' . PHP_EOL;
|
395 |
+
$info .= sprintf( _x( '[INFO] WordPress %1$s on %2$s', 'WordPress Version; Blog url', 'backwpup' ), BackWPup::get_plugin_data( 'wp_version' ), esc_attr( site_url( '/' ) ) ) . '<br />' . PHP_EOL;
|
396 |
+
$level = __( 'Normal', 'backwpup' );
|
397 |
+
$translated = '';
|
398 |
+
if ( $this->is_debug() ) {
|
399 |
+
$level = __( 'Debug', 'backwpup' );
|
400 |
+
}
|
401 |
+
if ( is_textdomain_loaded( 'backwpup' ) ) {
|
402 |
+
$translated = __( '(translated)', 'backwpup' );
|
403 |
+
}
|
404 |
+
$info .= sprintf( __( '[INFO] Log Level: %1$s %2$s', 'backwpup' ), $level, $translated ) . '<br />' . PHP_EOL;
|
405 |
+
$job_name = esc_attr( $this->job['name'] );
|
406 |
+
if ( $this->is_debug() ) {
|
407 |
+
$job_name .= '; ' . implode( '+', $this->job['type'] );
|
408 |
+
}
|
409 |
+
$info .= sprintf( __( '[INFO] BackWPup job: %1$s', 'backwpup' ), $job_name ) . '<br />' . PHP_EOL;
|
410 |
+
if ( $this->is_debug() ) {
|
411 |
+
$current_user = wp_get_current_user();
|
412 |
+
$info .= sprintf( __( '[INFO] Runs with user: %1$s (%2$d) ', 'backwpup' ), $current_user->user_login, $current_user->ID ) . '<br />' . PHP_EOL;
|
413 |
+
}
|
414 |
+
if ( $this->job['activetype'] === 'wpcron' ) {
|
415 |
+
//check next run
|
416 |
+
$cron_next = wp_next_scheduled( 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
417 |
+
if ( ! $cron_next || $cron_next < time() ) {
|
418 |
+
wp_unschedule_event( $cron_next, 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
419 |
+
$cron_next = BackWPup_Cron::cron_next( $this->job['cron'] );
|
420 |
+
wp_schedule_single_event( $cron_next, 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
421 |
+
$cron_next = wp_next_scheduled( 'backwpup_cron', array( 'id' => $this->job['jobid'] ) );
|
422 |
+
}
|
423 |
+
//output scheduling
|
424 |
+
if ( $this->is_debug() ) {
|
425 |
+
if ( ! $cron_next ) {
|
426 |
+
$cron_next = __( 'Not scheduled!', 'backwpup' );
|
427 |
+
} else {
|
428 |
+
$cron_next = date_i18n( 'D, j M Y @ H:i', $cron_next + ( get_option( 'gmt_offset' ) * 3600 ), true );
|
429 |
+
}
|
430 |
+
$info .= sprintf( __( '[INFO] Cron: %s; Next: %s ', 'backwpup' ), $this->job['cron'], $cron_next ) . '<br />' . PHP_EOL;
|
431 |
+
}
|
432 |
+
} elseif ( $this->job['activetype'] == 'link' && $this->is_debug() ) {
|
433 |
+
$info .= __( '[INFO] BackWPup job start with link is active', 'backwpup' ) . '<br />' . PHP_EOL;
|
434 |
+
} elseif ( $this->job['activetype'] == 'easycron' && $this->is_debug() ) {
|
435 |
+
$info .= __( '[INFO] BackWPup job start with EasyCron.com', 'backwpup' ) . '<br />' . PHP_EOL;
|
436 |
+
//output scheduling
|
437 |
+
if ( $this->is_debug() ) {
|
438 |
+
$cron_next = BackWPup_Cron::cron_next( $this->job['cron'] );
|
439 |
+
$cron_next = date_i18n( 'D, j M Y @ H:i', $cron_next + ( get_option( 'gmt_offset' ) * 3600 ), true );
|
440 |
+
$info .= sprintf( __( '[INFO] Cron: %s; Next: %s ', 'backwpup' ), $this->job['cron'], $cron_next ) . '<br />' . PHP_EOL;
|
441 |
+
}
|
442 |
+
} elseif ( $this->is_debug() ) {
|
443 |
+
$info .= __( '[INFO] BackWPup no automatic job start configured', 'backwpup' ) . '<br />' . PHP_EOL;
|
444 |
+
}
|
445 |
+
if ( $this->is_debug() ) {
|
446 |
+
if ( $start_type == 'cronrun' ) {
|
447 |
+
$info .= __( '[INFO] BackWPup job started from wp-cron', 'backwpup' ) . '<br />' . PHP_EOL;
|
448 |
+
} elseif ( $start_type == 'runnow' || $start_type == 'runnowalt' ) {
|
449 |
+
$info .= __( '[INFO] BackWPup job started manually', 'backwpup' ) . '<br />' . PHP_EOL;
|
450 |
+
} elseif ( $start_type == 'runext' ) {
|
451 |
+
$info .= __( '[INFO] BackWPup job started from external url', 'backwpup' ) . '<br />' . PHP_EOL;
|
452 |
+
} elseif ( $start_type == 'runcli' ) {
|
453 |
+
$info .= __( '[INFO] BackWPup job started form commandline interface', 'backwpup' ) . '<br />' . PHP_EOL;
|
454 |
+
}
|
455 |
+
$bit = '';
|
456 |
+
if ( PHP_INT_SIZE === 4 ) {
|
457 |
+
$bit = ' (32bit)';
|
458 |
+
}
|
459 |
+
if ( PHP_INT_SIZE === 8 ) {
|
460 |
+
$bit = ' (64bit)';
|
461 |
+
}
|
462 |
+
$info .= __( '[INFO] PHP ver.:', 'backwpup' ) . ' ' . PHP_VERSION . $bit . '; ' . PHP_SAPI . '; ' . PHP_OS . '<br />' . PHP_EOL;
|
463 |
+
$info .= sprintf( __( '[INFO] Maximum PHP script execution time is %1$d seconds', 'backwpup' ), ini_get( 'max_execution_time' ) ) . '<br />' . PHP_EOL;
|
464 |
+
if ( php_sapi_name() != 'cli' ) {
|
465 |
+
$job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
|
466 |
+
if ( ! empty( $job_max_execution_time ) ) {
|
467 |
+
$info .= sprintf( __( '[INFO] Script restart time is configured to %1$d seconds', 'backwpup' ), $job_max_execution_time ) . '<br />' . PHP_EOL;
|
468 |
+
}
|
469 |
+
}
|
470 |
+
$info .= sprintf( __( '[INFO] MySQL ver.: %s', 'backwpup' ), $wpdb->get_var( "SELECT VERSION() AS version" ) ) . '<br />' . PHP_EOL;
|
471 |
+
if ( isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
|
472 |
+
$info .= sprintf( __( '[INFO] Web Server: %s', 'backwpup' ), $_SERVER['SERVER_SOFTWARE'] ) . '<br />' . PHP_EOL;
|
473 |
+
}
|
474 |
+
if ( function_exists( 'curl_init' ) ) {
|
475 |
+
$curlversion = curl_version();
|
476 |
+
$info .= sprintf( __( '[INFO] curl ver.: %1$s; %2$s', 'backwpup' ), $curlversion['version'], $curlversion['ssl_version'] ) . '<br />' . PHP_EOL;
|
477 |
+
}
|
478 |
+
$info .= sprintf( __( '[INFO] Temp folder is: %s', 'backwpup' ), BackWPup::get_plugin_data( 'TEMP' ) ) . '<br />' . PHP_EOL;
|
479 |
+
}
|
480 |
+
if ( $this->is_debug() ) {
|
481 |
+
$logfile = $this->logfile;
|
482 |
+
} else {
|
483 |
+
$logfile = basename( $this->logfile );
|
484 |
+
}
|
485 |
+
$info .= sprintf( __( '[INFO] Logfile is: %s', 'backwpup' ), $logfile ) . '<br />' . PHP_EOL;
|
486 |
+
if ( ! empty( $this->backup_file ) && $this->job['backuptype'] === 'archive' ) {
|
487 |
+
if ( $this->is_debug() ) {
|
488 |
+
$backupfile = $this->backup_folder . $this->backup_file;
|
489 |
+
} else {
|
490 |
+
$backupfile = $this->backup_file;
|
491 |
+
}
|
492 |
+
$info .= sprintf( __( '[INFO] Backup file is: %s', 'backwpup' ), $backupfile ) . '<br />' . PHP_EOL;
|
493 |
+
} else {
|
494 |
+
$info .= sprintf( __( '[INFO] Backup type is: %s', 'backwpup' ), $this->job['backuptype'] ) . '<br />' . PHP_EOL;
|
495 |
+
}
|
496 |
+
//output info on cli
|
497 |
+
if ( php_sapi_name() == 'cli' && defined( 'STDOUT' ) ) {
|
498 |
+
fwrite( STDOUT, strip_tags( $info ) );
|
499 |
+
}
|
500 |
+
if ( ! file_put_contents( $this->logfile, $head . $info, FILE_APPEND ) ) {
|
501 |
+
$this->logfile = '';
|
502 |
+
$this->log( __( 'Could not write log file', 'backwpup' ), E_USER_ERROR );
|
503 |
+
}
|
504 |
+
//test for destinations
|
505 |
+
if ( $job_need_dest ) {
|
506 |
+
$desttest = false;
|
507 |
+
foreach ( $this->steps_todo as $deststeptest ) {
|
508 |
+
if ( substr( $deststeptest, 0, 5 ) == 'DEST_' ) {
|
509 |
+
$desttest = true;
|
510 |
+
break;
|
511 |
+
}
|
512 |
+
}
|
513 |
+
if ( ! $desttest ) {
|
514 |
+
$this->log( __( 'No destination correctly defined for backup! Please correct job settings.', 'backwpup' ), E_USER_ERROR );
|
515 |
+
$this->steps_todo = array( 'END' );
|
516 |
+
}
|
517 |
+
}
|
518 |
+
//test backup folder
|
519 |
+
if ( ! empty( $this->backup_folder ) ) {
|
520 |
+
$folder_message = BackWPup_File::check_folder( $this->backup_folder, true );
|
521 |
+
if ( ! empty( $folder_message ) ) {
|
522 |
+
$this->log( $folder_message, E_USER_ERROR );
|
523 |
+
$this->steps_todo = array( 'END' );
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
+
//Set start as done
|
528 |
+
$this->steps_done[] = 'CREATE';
|
529 |
+
}
|
530 |
+
|
531 |
+
/**
|
532 |
+
* @param $name
|
533 |
+
* @param string $suffix
|
534 |
+
* @param bool $delete_temp_file
|
535 |
+
*
|
536 |
+
* @return string
|
537 |
+
*/
|
538 |
+
public function generate_filename( $name, $suffix = '', $delete_temp_file = true ) {
|
539 |
+
|
540 |
+
$local_time = current_time( 'timestamp' );
|
541 |
+
|
542 |
+
$datevars = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
|
543 |
+
$datevalues = array(
|
544 |
+
date( 'd', $local_time ),
|
545 |
+
date( 'j', $local_time ),
|
546 |
+
date( 'm', $local_time ),
|
547 |
+
date( 'n', $local_time ),
|
548 |
+
date( 'Y', $local_time ),
|
549 |
+
date( 'y', $local_time ),
|
550 |
+
date( 'a', $local_time ),
|
551 |
+
date( 'A', $local_time ),
|
552 |
+
date( 'B', $local_time ),
|
553 |
+
date( 'g', $local_time ),
|
554 |
+
date( 'G', $local_time ),
|
555 |
+
date( 'h', $local_time ),
|
556 |
+
date( 'H', $local_time ),
|
557 |
+
date( 'i', $local_time ),
|
558 |
+
date( 's', $local_time )
|
559 |
+
);
|
560 |
+
|
561 |
+
if ( $suffix ) {
|
562 |
+
$suffix = '.' . trim( $suffix, '. ' );
|
563 |
+
}
|
564 |
+
|
565 |
+
$name = str_replace( $datevars, $datevalues, self::sanitize_file_name( $name ) );
|
566 |
+
$name .= $suffix;
|
567 |
+
if ( $delete_temp_file && is_writeable( BackWPup::get_plugin_data( 'TEMP' ) . $name ) && ! is_dir( BackWPup::get_plugin_data( 'TEMP' ) . $name ) && ! is_link( BackWPup::get_plugin_data( 'TEMP' ) . $name ) ) {
|
568 |
+
unlink( BackWPup::get_plugin_data( 'TEMP' ) . $name );
|
569 |
+
}
|
570 |
+
|
571 |
+
return BackWPup_Option::normalize_archive_name( $name, $this->job['jobid'] );
|
572 |
+
}
|
573 |
+
|
574 |
+
/**
|
575 |
+
* Sanitizes a filename, replacing whitespace with underscores.
|
576 |
+
*
|
577 |
+
* @param $filename
|
578 |
+
*
|
579 |
+
* @return mixed
|
580 |
+
*/
|
581 |
+
public static function sanitize_file_name( $filename ) {
|
582 |
+
|
583 |
+
$filename = trim( $filename );
|
584 |
+
|
585 |
+
$special_chars = array(
|
586 |
+
"?",
|
587 |
+
"[",
|
588 |
+
"]",
|
589 |
+
"/",
|
590 |
+
"\\",
|
591 |
+
"=",
|
592 |
+
"<",
|
593 |
+
">",
|
594 |
+
":",
|
595 |
+
";",
|
596 |
+
",",
|
597 |
+
"'",
|
598 |
+
"\"",
|
599 |
+
"&",
|
600 |
+
"$",
|
601 |
+
"#",
|
602 |
+
"*",
|
603 |
+
"(",
|
604 |
+
")",
|
605 |
+
"|",
|
606 |
+
"~",
|
607 |
+
"`",
|
608 |
+
"!",
|
609 |
+
"{",
|
610 |
+
"}",
|
611 |
+
chr( 0 )
|
612 |
+
);
|
613 |
+
|
614 |
+
$filename = str_replace( $special_chars, '', $filename );
|
615 |
+
|
616 |
+
$filename = str_replace( array( ' ', '%20', '+' ), '_', $filename );
|
617 |
+
$filename = str_replace( array( "\n", "\t", "\r" ), '-', $filename );
|
618 |
+
$filename = trim( $filename, '.-_' );
|
619 |
+
|
620 |
+
return $filename;
|
621 |
+
}
|
622 |
+
|
623 |
+
/**
|
624 |
+
* Checks if the given archive belongs to this job.
|
625 |
+
*
|
626 |
+
* @param string $file
|
627 |
+
*
|
628 |
+
* @return bool
|
629 |
+
*/
|
630 |
+
public function owns_backup_archive( $file ) {
|
631 |
+
$prefix = BackWPup_Option::get_archive_name_prefix( $this->job['jobid'] );
|
632 |
+
return substr( basename( $file ), 0, strlen( $prefix ) ) == $prefix;
|
633 |
+
}
|
634 |
+
|
635 |
+
|
636 |
+
private function write_running_file() {
|
637 |
+
|
638 |
+
$clone = clone $this;
|
639 |
+
$data = '<?php //' . serialize( $clone );
|
640 |
+
|
641 |
+
$write = file_put_contents( BackWPup::get_plugin_data( 'running_file' ), $data );
|
642 |
+
if ( ! $write || $write < strlen( $data ) ) {
|
643 |
+
unlink( BackWPup::get_plugin_data( 'running_file' ) );
|
644 |
+
$this->log( __( 'Cannot write progress to working file. Job will be aborted.', 'backwpup' ), E_USER_ERROR );
|
645 |
+
}
|
646 |
+
}
|
647 |
+
|
648 |
+
/**
|
649 |
+
* Write messages to log file
|
650 |
+
*
|
651 |
+
* @param string $message the error message
|
652 |
+
* @param int $type the error number (E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE, ...)
|
653 |
+
* @param string $file the full path of file with error (__FILE__)
|
654 |
+
* @param int $line the line in that is the error (__LINE__)
|
655 |
+
*
|
656 |
+
* @return bool true
|
657 |
+
*/
|
658 |
+
public function log( $message, $type = E_USER_NOTICE, $file = '', $line = 0 ) {
|
659 |
+
|
660 |
+
// if error has been suppressed with an @
|
661 |
+
if ( error_reporting() == 0 ) {
|
662 |
+
return true;
|
663 |
+
}
|
664 |
+
|
665 |
+
//if first the type an second the message switch it on user errors
|
666 |
+
if ( ! is_int( $type ) && is_int( $message ) && in_array( $message, array(
|
667 |
+
1,
|
668 |
+
2,
|
669 |
+
4,
|
670 |
+
8,
|
671 |
+
16,
|
672 |
+
32,
|
673 |
+
64,
|
674 |
+
128,
|
675 |
+
256,
|
676 |
+
512,
|
677 |
+
1024,
|
678 |
+
2048,
|
679 |
+
4096,
|
680 |
+
8192,
|
681 |
+
16384
|
682 |
+
), true )
|
683 |
+
) {
|
684 |
+
$temp = $message;
|
685 |
+
$message = $type;
|
686 |
+
$type = $temp;
|
687 |
+
}
|
688 |
+
|
689 |
+
//json message if array or object
|
690 |
+
if ( is_array( $message ) || is_object( $message ) ) {
|
691 |
+
$message = json_encode( $message );
|
692 |
+
}
|
693 |
+
|
694 |
+
//if not set line and file get it
|
695 |
+
if ( $this->is_debug() ) {
|
696 |
+
if ( empty( $file ) || empty( $line ) ) {
|
697 |
+
$debug_info = debug_backtrace();
|
698 |
+
$file = $debug_info[0]['file'];
|
699 |
+
$line = $debug_info[0]['line'];
|
700 |
+
}
|
701 |
+
}
|
702 |
+
|
703 |
+
$error = false;
|
704 |
+
$warning = false;
|
705 |
+
|
706 |
+
switch ( $type ) {
|
707 |
+
case E_NOTICE:
|
708 |
+
case E_USER_NOTICE:
|
709 |
+
break;
|
710 |
+
case E_WARNING:
|
711 |
+
case E_CORE_WARNING:
|
712 |
+
case E_COMPILE_WARNING:
|
713 |
+
case E_USER_WARNING:
|
714 |
+
$this->warnings ++;
|
715 |
+
$warning = true;
|
716 |
+
$message = __( 'WARNING:', 'backwpup' ) . ' ' . $message;
|
717 |
+
break;
|
718 |
+
case E_ERROR:
|
719 |
+
case E_PARSE:
|
720 |
+
case E_CORE_ERROR:
|
721 |
+
case E_COMPILE_ERROR:
|
722 |
+
case E_USER_ERROR:
|
723 |
+
$this->errors ++;
|
724 |
+
$error = true;
|
725 |
+
$message = __( 'ERROR:', 'backwpup' ) . ' ' . $message;
|
726 |
+
break;
|
727 |
+
case 8192: //E_DEPRECATED comes with php 5.3
|
728 |
+
case 16384: //E_USER_DEPRECATED comes with php 5.3
|
729 |
+
$message = __( 'DEPRECATED:', 'backwpup' ) . ' ' . $message;
|
730 |
+
break;
|
731 |
+
case E_STRICT:
|
732 |
+
$message = __( 'STRICT NOTICE:', 'backwpup' ) . ' ' . $message;
|
733 |
+
break;
|
734 |
+
case E_RECOVERABLE_ERROR:
|
735 |
+
$this->errors ++;
|
736 |
+
$error = true;
|
737 |
+
$message = __( 'RECOVERABLE ERROR:', 'backwpup' ) . ' ' . $message;
|
738 |
+
break;
|
739 |
+
default:
|
740 |
+
$message = $type . ': ' . $message;
|
741 |
+
break;
|
742 |
+
}
|
743 |
+
|
744 |
+
$in_file = $this->get_destination_path_replacement( $file );
|
745 |
+
|
746 |
+
//print message to cli
|
747 |
+
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
748 |
+
$output_message = str_replace( array( '…', ' ' ), array( '...', ' ' ), esc_html( $message ) );
|
749 |
+
if ( ! call_user_func( array( '\cli\Shell', 'isPiped' ) ) ) {
|
750 |
+
if ( $error ) {
|
751 |
+
$output_message = '%r' . $output_message . '%n';
|
752 |
+
}
|
753 |
+
if ( $warning ) {
|
754 |
+
$output_message = '%y' . $output_message . '%n';
|
755 |
+
}
|
756 |
+
$output_message = call_user_func( array( '\cli\Colors', 'colorize' ), $output_message, true );
|
757 |
+
}
|
758 |
+
WP_CLI::line( $output_message );
|
759 |
+
} elseif ( php_sapi_name() == 'cli' && defined( 'STDOUT' ) ) {
|
760 |
+
$output_message = str_replace( array( '…', ' ' ), array( '...', ' ' ), esc_html( $message ) ) . PHP_EOL;
|
761 |
+
fwrite( STDOUT, $output_message );
|
762 |
+
}
|
763 |
+
|
764 |
+
//timestamp for log file
|
765 |
+
$debug_info = '';
|
766 |
+
if ( $this->is_debug() ) {
|
767 |
+
$debug_info = ' title="[Type: ' . $type . '|Line: ' . $line . '|File: ' . $in_file . '|Mem: ' . size_format( @memory_get_usage( true ), 2 ) . '|Mem Max: ' . size_format( @memory_get_peak_usage( true ), 2 ) . '|Mem Limit: ' . ini_get( 'memory_limit' ) . '|PID: ' . self::get_pid() . ' | UniqID: ' . $this->uniqid . '|Queries: ' . get_num_queries() . ']"';
|
768 |
+
}
|
769 |
+
$timestamp = '<span datetime="' . date( 'c' ) . '" ' . $debug_info . '>[' . date( 'd-M-Y H:i:s', current_time( 'timestamp' ) ) . ']</span> ';
|
770 |
+
|
771 |
+
//set last Message
|
772 |
+
if ( $error ) {
|
773 |
+
$output_message = '<span style="background-color:#ff6766;color:black;padding:0 2px;">' . esc_html( $message ) . '</span>';
|
774 |
+
$this->lasterrormsg = $output_message;
|
775 |
+
}
|
776 |
+
elseif ( $warning ) {
|
777 |
+
$output_message = '<span style="background-color:#ffc766;color:black;padding:0 2px;">' . esc_html( $message ) . '</span>';
|
778 |
+
$this->lasterrormsg = $output_message;
|
779 |
+
}
|
780 |
+
else {
|
781 |
+
$output_message = esc_html( $message );
|
782 |
+
$this->lastmsg = $output_message;
|
783 |
+
}
|
784 |
+
//write log file
|
785 |
+
if ( $this->logfile ) {
|
786 |
+
if ( ! file_put_contents( $this->logfile, $timestamp . $output_message . '<br />' . PHP_EOL, FILE_APPEND ) ) {
|
787 |
+
$this->logfile = '';
|
788 |
+
restore_error_handler();
|
789 |
+
trigger_error( esc_html( $message ), $type );
|
790 |
+
}
|
791 |
+
|
792 |
+
//write new log header
|
793 |
+
if ( ( $error || $warning ) && $this->logfile ) {
|
794 |
+
if ( $fd = fopen( $this->logfile, 'r+' ) ) {
|
795 |
+
$file_pos = ftell( $fd );
|
796 |
+
while ( ! feof( $fd ) ) {
|
797 |
+
$line = fgets( $fd );
|
798 |
+
if ( $error && stripos( $line, '<meta name="backwpup_errors" content="' ) !== false ) {
|
799 |
+
fseek( $fd, $file_pos );
|
800 |
+
fwrite( $fd, str_pad( '<meta name="backwpup_errors" content="' . $this->errors . '" />', 100 ) . PHP_EOL );
|
801 |
+
break;
|
802 |
+
}
|
803 |
+
if ( $warning && stripos( $line, '<meta name="backwpup_warnings" content="' ) !== false ) {
|
804 |
+
fseek( $fd, $file_pos );
|
805 |
+
fwrite( $fd, str_pad( '<meta name="backwpup_warnings" content="' . $this->warnings . '" />', 100 ) . PHP_EOL );
|
806 |
+
break;
|
807 |
+
}
|
808 |
+
$file_pos = ftell( $fd );
|
809 |
+
}
|
810 |
+
fclose( $fd );
|
811 |
+
}
|
812 |
+
}
|
813 |
+
}
|
814 |
+
|
815 |
+
//write working data
|
816 |
+
$this->update_working_data( $error || $warning );
|
817 |
+
|
818 |
+
//true for no more php error handling.
|
819 |
+
return true;
|
820 |
+
}
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Is debug log active
|
824 |
+
*
|
825 |
+
* @return bool
|
826 |
+
*/
|
827 |
+
public function is_debug() {
|
828 |
+
|
829 |
+
return strstr( $this->log_level, 'debug' ) ? true : false;
|
830 |
+
}
|
831 |
+
|
832 |
+
/**
|
833 |
+
* Change path of a given path
|
834 |
+
* for better storing in archives or on sync destinations
|
835 |
+
*
|
836 |
+
* @param $path string path to change to wp default path
|
837 |
+
*
|
838 |
+
* @return string
|
839 |
+
*/
|
840 |
+
public function get_destination_path_replacement( $path ) {
|
841 |
+
|
842 |
+
$path = str_replace( '\\', '/', $path );
|
843 |
+
|
844 |
+
$abs_path = realpath( BackWPup_Path_Fixer::fix_path( ABSPATH ) );
|
845 |
+
if ( $this->job['backupabsfolderup'] ) {
|
846 |
+
$abs_path = dirname( $abs_path );
|
847 |
+
}
|
848 |
+
|
849 |
+
$abs_path = trailingslashit( str_replace( '\\', '/', $abs_path ) );
|
850 |
+
|
851 |
+
$path = str_replace( $abs_path, '/', $path );
|
852 |
+
|
853 |
+
return $path;
|
854 |
+
}
|
855 |
+
|
856 |
+
/**
|
857 |
+
* Get the Process id of working script
|
858 |
+
*
|
859 |
+
* @return int
|
860 |
+
*/
|
861 |
+
private static function get_pid() {
|
862 |
+
|
863 |
+
if ( function_exists( 'posix_getpid' ) ) {
|
864 |
+
|
865 |
+
return posix_getpid();
|
866 |
+
} elseif ( function_exists( 'getmypid' ) ) {
|
867 |
+
|
868 |
+
return getmypid();
|
869 |
+
}
|
870 |
+
|
871 |
+
return - 1;
|
872 |
+
}
|
873 |
+
|
874 |
+
/**
|
875 |
+
*
|
876 |
+
* Write the Working data to display the process or that i can executes again
|
877 |
+
* The write will only done every second
|
878 |
+
*
|
879 |
+
* @param bool $must
|
880 |
+
*/
|
881 |
+
public function update_working_data( $must = false ) {
|
882 |
+
global $wpdb;
|
883 |
+
|
884 |
+
//to reduce server load
|
885 |
+
if ( get_site_option( 'backwpup_cfg_jobwaittimems' ) > 0 && get_site_option( 'backwpup_cfg_jobwaittimems' ) <= 500000 ) {
|
886 |
+
usleep( get_site_option( 'backwpup_cfg_jobwaittimems' ) );
|
887 |
+
}
|
888 |
+
|
889 |
+
//check free memory
|
890 |
+
$this->need_free_memory( '10M' );
|
891 |
+
|
892 |
+
//only run every 1 sec.
|
893 |
+
$time_to_update = microtime( true ) - $this->timestamp_last_update;
|
894 |
+
if ( $time_to_update < 1 && ! $must ) {
|
895 |
+
return;
|
896 |
+
}
|
897 |
+
|
898 |
+
//FCGI must have a permanent output so that it not broke
|
899 |
+
if ( get_site_option( 'backwpup_cfg_jobdooutput' ) && ! defined( 'STDOUT' ) ) {
|
900 |
+
echo str_repeat( ' ', 12 );
|
901 |
+
flush();
|
902 |
+
}
|
903 |
+
|
904 |
+
// check WPDB connection. WP will do it after a query that will cause messages.
|
905 |
+
$wpdb->check_connection( false );
|
906 |
+
|
907 |
+
//set execution time again for 5 min
|
908 |
+
@set_time_limit( 300 );
|
909 |
+
|
910 |
+
//calc sub step percent
|
911 |
+
if ( $this->substeps_todo > 0 && $this->substeps_done > 0 ) {
|
912 |
+
$this->substep_percent = round( $this->substeps_done / $this->substeps_todo * 100 );
|
913 |
+
} else {
|
914 |
+
$this->substep_percent = 1;
|
915 |
+
}
|
916 |
+
|
917 |
+
//check if job aborted
|
918 |
+
if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
|
919 |
+
if ( $this->step_working !== 'END' ) {
|
920 |
+
$this->end();
|
921 |
+
}
|
922 |
+
} else {
|
923 |
+
$this->timestamp_last_update = microtime( true ); //last update of working file
|
924 |
+
$this->write_running_file();
|
925 |
+
}
|
926 |
+
|
927 |
+
if ( $this->signal !== 0 ) {
|
928 |
+
$this->do_restart();
|
929 |
+
}
|
930 |
+
}
|
931 |
+
|
932 |
+
/**
|
933 |
+
*
|
934 |
+
* Increase automatically the memory that is needed
|
935 |
+
*
|
936 |
+
* @param int|string $memneed of the needed memory
|
937 |
+
*/
|
938 |
+
public function need_free_memory( $memneed ) {
|
939 |
+
|
940 |
+
//need memory
|
941 |
+
$needmemory = @memory_get_usage( true ) + self::convert_hr_to_bytes( $memneed );
|
942 |
+
// increase Memory
|
943 |
+
if ( $needmemory > self::convert_hr_to_bytes( ini_get( 'memory_limit' ) ) ) {
|
944 |
+
$newmemory = round( $needmemory / 1024 / 1024 ) + 1 . 'M';
|
945 |
+
if ( $needmemory >= 1073741824 ) {
|
946 |
+
$newmemory = round( $needmemory / 1024 / 1024 / 1024 ) . 'G';
|
947 |
+
}
|
948 |
+
@ini_set( 'memory_limit', $newmemory );
|
949 |
+
}
|
950 |
+
}
|
951 |
+
|
952 |
+
/**
|
953 |
+
*
|
954 |
+
* Converts hr to bytes
|
955 |
+
*
|
956 |
+
* @param $size
|
957 |
+
*
|
958 |
+
* @return int
|
959 |
+
*/
|
960 |
+
public static function convert_hr_to_bytes( $size ) {
|
961 |
+
$size = strtolower( $size );
|
962 |
+
$bytes = (int) $size;
|
963 |
+
if ( strpos( $size, 'k' ) !== false ) {
|
964 |
+
$bytes = intval( $size ) * 1024;
|
965 |
+
} elseif ( strpos( $size, 'm' ) !== false ) {
|
966 |
+
$bytes = intval( $size ) * 1024 * 1024;
|
967 |
+
} elseif ( strpos( $size, 'g' ) !== false ) {
|
968 |
+
$bytes = intval( $size ) * 1024 * 1024 * 1024;
|
969 |
+
}
|
970 |
+
|
971 |
+
return $bytes;
|
972 |
+
}
|
973 |
+
|
974 |
+
/**
|
975 |
+
*
|
976 |
+
* Called on job stop makes cleanup and terminates the script
|
977 |
+
*
|
978 |
+
*/
|
979 |
+
private function end() {
|
980 |
+
|
981 |
+
$this->step_working = 'END';
|
982 |
+
$this->substeps_todo = 1;
|
983 |
+
|
984 |
+
if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
|
985 |
+
$this->log( __( 'Aborted by user!', 'backwpup' ), E_USER_ERROR );
|
986 |
+
}
|
987 |
+
|
988 |
+
//delete old logs
|
989 |
+
if ( get_site_option( 'backwpup_cfg_maxlogs' ) ) {
|
990 |
+
$log_file_list = array();
|
991 |
+
$log_folder = trailingslashit( dirname( $this->logfile ) );
|
992 |
+
if ( is_readable( $log_folder ) ) { //make file list
|
993 |
+
try {
|
994 |
+
$dir = new BackWPup_Directory( $log_folder );
|
995 |
+
|
996 |
+
foreach ( $dir as $file ) {
|
997 |
+
if ( ! $file->isDot() && strpos( $file->getFilename(), 'backwpup_log_' ) === 0 && strpos( $file->getFilename(), '.html' ) !== false ) {
|
998 |
+
$log_file_list[ $file->getMTime() ] = clone $file;
|
999 |
+
}
|
1000 |
+
}
|
1001 |
+
}
|
1002 |
+
catch ( UnexpectedValueException $e ) {
|
1003 |
+
$this->log( sprintf( __( "Could not open path: %s" ), $e->getMessage() ), E_USER_WARNING );
|
1004 |
+
}
|
1005 |
+
}
|
1006 |
+
if ( count( $log_file_list ) > 0 ) {
|
1007 |
+
krsort( $log_file_list, SORT_NUMERIC );
|
1008 |
+
$num_delete_files = 0;
|
1009 |
+
$i = - 1;
|
1010 |
+
foreach ( $log_file_list as $log_file ) {
|
1011 |
+
$i ++;
|
1012 |
+
if ( $i < get_site_option( 'backwpup_cfg_maxlogs' ) ) {
|
1013 |
+
continue;
|
1014 |
+
}
|
1015 |
+
unlink( $log_file->getPathname() );
|
1016 |
+
$num_delete_files ++;
|
1017 |
+
}
|
1018 |
+
if ( $num_delete_files > 0 ) {
|
1019 |
+
$this->log( sprintf( _n( 'One old log deleted', '%d old logs deleted', $num_delete_files, 'backwpup' ), $num_delete_files ) );
|
1020 |
+
}
|
1021 |
+
}
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
//Display job working time
|
1025 |
+
if ( $this->errors > 0 ) {
|
1026 |
+
$this->log( sprintf( __( 'Job has ended with errors in %s seconds. You must resolve the errors for correct execution.', 'backwpup' ), current_time( 'timestamp' ) - $this->start_time ), E_USER_ERROR );
|
1027 |
+
} elseif ( $this->warnings > 0 ) {
|
1028 |
+
$this->log( sprintf( __( 'Job finished with warnings in %s seconds. Please resolve them for correct execution.', 'backwpup' ), current_time( 'timestamp' ) - $this->start_time ), E_USER_WARNING );
|
1029 |
+
} else {
|
1030 |
+
$this->log( sprintf( __( 'Job done in %s seconds.', 'backwpup' ), current_time( 'timestamp' ) - $this->start_time ) );
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
//Update job options
|
1034 |
+
$this->job['lastruntime'] = current_time( 'timestamp' ) - $this->start_time;
|
1035 |
+
BackWPup_Option::update( $this->job['jobid'], 'lastruntime', $this->job['lastruntime'] );
|
1036 |
+
|
1037 |
+
|
1038 |
+
//write header info
|
1039 |
+
if ( ! empty( $this->logfile ) ) {
|
1040 |
+
|
1041 |
+
if ( $fd = fopen( $this->logfile, 'r+' ) ) {
|
1042 |
+
$filepos = ftell( $fd );
|
1043 |
+
$found = 0;
|
1044 |
+
while ( ! feof( $fd ) ) {
|
1045 |
+
$line = fgets( $fd );
|
1046 |
+
if ( stripos( $line, '<meta name="backwpup_jobruntime"' ) !== false ) {
|
1047 |
+
fseek( $fd, $filepos );
|
1048 |
+
fwrite( $fd, str_pad( '<meta name="backwpup_jobruntime" content="' . $this->job['lastruntime'] . '" />', 100 ) . PHP_EOL );
|
1049 |
+
$found ++;
|
1050 |
+
}
|
1051 |
+
if ( stripos( $line, '<meta name="backwpup_backupfilesize"' ) !== false ) {
|
1052 |
+
fseek( $fd, $filepos );
|
1053 |
+
fwrite( $fd, str_pad( '<meta name="backwpup_backupfilesize" content="' . $this->backup_filesize . '" />', 100 ) . PHP_EOL );
|
1054 |
+
$found ++;
|
1055 |
+
}
|
1056 |
+
if ( $found >= 2 ) {
|
1057 |
+
break;
|
1058 |
+
}
|
1059 |
+
$filepos = ftell( $fd );
|
1060 |
+
}
|
1061 |
+
fclose( $fd );
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
//Send mail with log
|
1065 |
+
$sendmail = false;
|
1066 |
+
if ( $this->job['mailaddresslog'] ) {
|
1067 |
+
$sendmail = true;
|
1068 |
+
}
|
1069 |
+
if ( $this->errors === 0 && $this->job['mailerroronly'] ) {
|
1070 |
+
$sendmail = false;
|
1071 |
+
}
|
1072 |
+
if ( $sendmail ) {
|
1073 |
+
//special subject
|
1074 |
+
$status = __( 'SUCCESSFUL', 'backwpup' );
|
1075 |
+
if ( $this->warnings > 0 ) {
|
1076 |
+
$status = __( 'WARNING', 'backwpup' );
|
1077 |
+
}
|
1078 |
+
if ( $this->errors > 0 ) {
|
1079 |
+
$status = __( 'ERROR', 'backwpup' );
|
1080 |
+
}
|
1081 |
+
|
1082 |
+
$subject = sprintf( __( '[%3$s] BackWPup log %1$s: %2$s', 'backwpup' ), date_i18n( 'd-M-Y H:i', $this->start_time, true ), esc_attr( $this->job['name'] ), $status );
|
1083 |
+
$headers = array();
|
1084 |
+
$headers[] = 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' );
|
1085 |
+
if ( $this->job['mailaddresssenderlog'] ) {
|
1086 |
+
$this->job['mailaddresssenderlog'] = str_replace( array( '<', '>' ), array( '<', '>' ), $this->job['mailaddresssenderlog'] );
|
1087 |
+
|
1088 |
+
$bracket_pos = strpos( $this->job['mailaddresssenderlog'], '<' );
|
1089 |
+
$at_pos = strpos( $this->job['mailaddresssenderlog'], '@' );
|
1090 |
+
if ( $bracket_pos === false || $at_pos === false ) {
|
1091 |
+
$this->job['mailaddresssenderlog'] = str_replace( array( '<', '>' ), '', $this->job['mailaddresssenderlog'] ) . ' <' . get_bloginfo( 'admin_email' ) . '>';
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
$headers[] = 'From: ' . $this->job['mailaddresssenderlog'];
|
1095 |
+
}
|
1096 |
+
wp_mail( $this->job['mailaddresslog'], $subject, file_get_contents( $this->logfile ), $headers );
|
1097 |
+
}
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
//set done
|
1101 |
+
$this->substeps_done = 1;
|
1102 |
+
$this->steps_done[] = 'END';
|
1103 |
+
|
1104 |
+
//clean up temp
|
1105 |
+
self::clean_temp_folder();
|
1106 |
+
|
1107 |
+
//remove shutdown action
|
1108 |
+
remove_action( 'shutdown', array( $this, 'shutdown' ) );
|
1109 |
+
restore_exception_handler();
|
1110 |
+
restore_error_handler();
|
1111 |
+
|
1112 |
+
//logfile end
|
1113 |
+
file_put_contents( $this->logfile, "</body>" . PHP_EOL . "</html>", FILE_APPEND );
|
1114 |
+
|
1115 |
+
BackWPup_Cron::check_cleanup();
|
1116 |
+
|
1117 |
+
exit();
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
/**
|
1121 |
+
* Cleanup Temp Folder
|
1122 |
+
*/
|
1123 |
+
public static function clean_temp_folder() {
|
1124 |
+
|
1125 |
+
$temp_dir = BackWPup::get_plugin_data( 'TEMP' );
|
1126 |
+
$do_not_delete_files = array( '.htaccess', 'nginx.conf', 'index.php', '.', '..', '.donotbackup' );
|
1127 |
+
|
1128 |
+
if ( is_writable( $temp_dir ) ) {
|
1129 |
+
try {
|
1130 |
+
$dir = new BackWPup_Directory( $temp_dir );
|
1131 |
+
foreach ( $dir as $file ) {
|
1132 |
+
if ( in_array( $file->getFilename(), $do_not_delete_files, true ) || $file->isDir() || $file->isLink() ) {
|
1133 |
+
continue;
|
1134 |
+
}
|
1135 |
+
if ( $file->isWritable() ) {
|
1136 |
+
unlink( $file->getPathname() );
|
1137 |
+
}
|
1138 |
+
}
|
1139 |
+
}
|
1140 |
+
catch ( UnexpectedValueException $e ) {
|
1141 |
+
$this->log( sprintf( __( "Could not open path: %s" ), $e->getMessage() ), E_USER_WARNING );
|
1142 |
+
}
|
1143 |
+
}
|
1144 |
+
}
|
1145 |
+
|
1146 |
+
/**
|
1147 |
+
* Do a job restart
|
1148 |
+
*
|
1149 |
+
* @param bool $must Restart must done
|
1150 |
+
*/
|
1151 |
+
public function do_restart( $must = false ) {
|
1152 |
+
|
1153 |
+
//restart must done if signal
|
1154 |
+
if ( $this->signal !== 0 ) {
|
1155 |
+
$must = true;
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
//no restart if in end step
|
1159 |
+
if ( $this->step_working === 'END' || ( count( $this->steps_done ) + 1 ) >= count( $this->steps_todo ) ) {
|
1160 |
+
return;
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
//no restart on cli usage
|
1164 |
+
if ( php_sapi_name() == 'cli' ) {
|
1165 |
+
return;
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
//no restart if no restart time configured
|
1169 |
+
$job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
|
1170 |
+
if ( ! $must && empty( $job_max_execution_time ) ) {
|
1171 |
+
return;
|
1172 |
+
}
|
1173 |
+
|
1174 |
+
//no restart when restart was 3 Seconds before
|
1175 |
+
$execution_time = microtime( true ) - $this->timestamp_script_start;
|
1176 |
+
if ( ! $must && $execution_time < 3 ) {
|
1177 |
+
return;
|
1178 |
+
}
|
1179 |
+
|
1180 |
+
//no restart if no working job
|
1181 |
+
if ( ! file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
|
1182 |
+
return;
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
//print message
|
1186 |
+
if ( $this->is_debug() ) {
|
1187 |
+
if ( $execution_time !== 0 ) {
|
1188 |
+
$this->log( sprintf( __( 'Restart after %1$d seconds.', 'backwpup' ), ceil( $execution_time ) ) );
|
1189 |
+
} elseif ( $this->signal !== 0 ) {
|
1190 |
+
$this->log( __( 'Restart after getting signal.', 'backwpup' ) );
|
1191 |
+
}
|
1192 |
+
}
|
1193 |
+
|
1194 |
+
//do things for a clean restart
|
1195 |
+
$this->pid = 0;
|
1196 |
+
$this->uniqid = '';
|
1197 |
+
$this->write_running_file();
|
1198 |
+
remove_action( 'shutdown', array( $this, 'shutdown' ) );
|
1199 |
+
//do restart
|
1200 |
+
wp_clear_scheduled_hook( 'backwpup_cron', array( 'id' => 'restart' ) );
|
1201 |
+
wp_schedule_single_event( time() + 5, 'backwpup_cron', array( 'id' => 'restart' ) );
|
1202 |
+
self::get_jobrun_url( 'restart' );
|
1203 |
+
|
1204 |
+
exit();
|
1205 |
+
}
|
1206 |
+
|
1207 |
+
/**
|
1208 |
+
*
|
1209 |
+
* Get a url to run a job of BackWPup
|
1210 |
+
*
|
1211 |
+
* @param string $starttype Start types are 'runnow', 'runnowlink', 'cronrun', 'runext', 'restart', 'restartalt', 'test'
|
1212 |
+
* @param int $jobid The id of job to start else 0
|
1213 |
+
*
|
1214 |
+
* @return array|object [url] is the job url [header] for auth header or object form wp_remote_get()
|
1215 |
+
*/
|
1216 |
+
public static function get_jobrun_url( $starttype, $jobid = 0 ) {
|
1217 |
+
|
1218 |
+
$authentication = get_site_option( 'backwpup_cfg_authentication', array(
|
1219 |
+
'method' => '',
|
1220 |
+
'basic_user' => '',
|
1221 |
+
'basic_password' => '',
|
1222 |
+
'user_id' => 0,
|
1223 |
+
'query_arg' => ''
|
1224 |
+
) );
|
1225 |
+
$url = site_url( 'wp-cron.php' );
|
1226 |
+
$header = array( 'Cache-Control' => 'no-cache' );
|
1227 |
+
$authurl = '';
|
1228 |
+
$query_args = array(
|
1229 |
+
'_nonce' => substr( wp_hash( wp_nonce_tick() . 'backwpup_job_run-' . $starttype, 'nonce' ), - 12, 10 ),
|
1230 |
+
'doing_wp_cron' => sprintf( '%.22F', microtime( true ) )
|
1231 |
+
);
|
1232 |
+
|
1233 |
+
if ( in_array( $starttype, array( 'restart', 'runnow', 'cronrun', 'runext', 'test' ), true ) ) {
|
1234 |
+
$query_args['backwpup_run'] = $starttype;
|
1235 |
+
}
|
1236 |
+
|
1237 |
+
if ( in_array( $starttype, array( 'runnowlink', 'runnow', 'cronrun', 'runext' ), true ) && ! empty( $jobid ) ) {
|
1238 |
+
$query_args['jobid'] = $jobid;
|
1239 |
+
}
|
1240 |
+
|
1241 |
+
if ( ! empty( $authentication['basic_user'] ) && ! empty( $authentication['basic_password'] ) && $authentication['method'] == 'basic' ) {
|
1242 |
+
$header['Authorization'] = 'Basic ' . base64_encode( $authentication['basic_user'] . ':' . BackWPup_Encryption::decrypt( $authentication['basic_password'] ) );
|
1243 |
+
$authurl = urlencode( $authentication['basic_user'] ) . ':' . urlencode( BackWPup_Encryption::decrypt( $authentication['basic_password'] ) ) . '@';
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
if ( ! empty( $authentication['query_arg'] ) && $authentication['method'] == 'query_arg' ) {
|
1247 |
+
$url .= '?' . $authentication['query_arg'];
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
if ( $starttype === 'runext' ) {
|
1251 |
+
$query_args['_nonce'] = get_site_option( 'backwpup_cfg_jobrunauthkey' );
|
1252 |
+
$query_args['doing_wp_cron'] = null;
|
1253 |
+
if ( ! empty( $authurl ) ) {
|
1254 |
+
$url = str_replace( 'https://', 'https://' . $authurl, $url );
|
1255 |
+
$url = str_replace( 'http://', 'http://' . $authurl, $url );
|
1256 |
+
}
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
if ( $starttype === 'runnowlink' && ( ! defined( 'ALTERNATE_WP_CRON' ) || ! ALTERNATE_WP_CRON ) ) {
|
1260 |
+
$url = wp_nonce_url( network_admin_url( 'admin.php' ), 'backwpup_job_run-' . $starttype );
|
1261 |
+
$query_args['page'] = 'backwpupjobs';
|
1262 |
+
$query_args['action'] = 'runnow';
|
1263 |
+
$query_args['doing_wp_cron'] = null;
|
1264 |
+
unset( $query_args['_nonce'] );
|
1265 |
+
}
|
1266 |
+
|
1267 |
+
if ( $starttype === 'runnowlink' && defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
|
1268 |
+
$query_args['backwpup_run'] = 'runnowalt';
|
1269 |
+
$query_args['_nonce'] = substr( wp_hash( wp_nonce_tick() . 'backwpup_job_run-runnowalt', 'nonce' ), - 12, 10 );
|
1270 |
+
$query_args['doing_wp_cron'] = null;
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
if ( $starttype === 'restartalt' && defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON ) {
|
1274 |
+
$query_args['backwpup_run'] = 'restart';
|
1275 |
+
$query_args['_nonce'] = null;
|
1276 |
+
}
|
1277 |
+
|
1278 |
+
if ( $starttype === 'restart' || $starttype === 'test' ) {
|
1279 |
+
$query_args['_nonce'] = null;
|
1280 |
+
}
|
1281 |
+
|
1282 |
+
if ( ! empty( $authentication['user_id'] ) && $authentication['method'] === 'user' ) {
|
1283 |
+
//cache cookies for auth some
|
1284 |
+
$cookies = get_site_transient( 'backwpup_cookies' );
|
1285 |
+
if ( empty( $cookies ) ) {
|
1286 |
+
$wp_admin_user = get_users( array( 'role' => 'administrator', 'number' => 1 ) );
|
1287 |
+
if ( empty( $wp_admin_user ) ) {
|
1288 |
+
$wp_admin_user = get_users( array( 'role' => 'backwpup_admin', 'number' => 1 ) );
|
1289 |
+
}
|
1290 |
+
if ( ! empty( $wp_admin_user[0]->ID ) ) {
|
1291 |
+
$expiration = time() + ( 356 * DAY_IN_SECONDS );
|
1292 |
+
$manager = WP_Session_Tokens::get_instance( $wp_admin_user[0]->ID );
|
1293 |
+
$token = $manager->create( $expiration );
|
1294 |
+
$cookies[ LOGGED_IN_COOKIE ] = wp_generate_auth_cookie( $wp_admin_user[0]->ID, $expiration, 'logged_in', $token );
|
1295 |
+
}
|
1296 |
+
set_site_transient( 'backwpup_cookies', $cookies, HOUR_IN_SECONDS - 30 );
|
1297 |
+
}
|
1298 |
+
} else {
|
1299 |
+
$cookies = '';
|
1300 |
+
}
|
1301 |
+
|
1302 |
+
$cron_request = array(
|
1303 |
+
'url' => add_query_arg( $query_args, $url ),
|
1304 |
+
'key' => $query_args['doing_wp_cron'],
|
1305 |
+
'args' => array(
|
1306 |
+
'blocking' => false,
|
1307 |
+
'sslverify' => false,
|
1308 |
+
'timeout' => 0.01,
|
1309 |
+
'headers' => $header,
|
1310 |
+
'user-agent' => BackWPup::get_plugin_data( 'User-Agent' )
|
1311 |
+
)
|
1312 |
+
);
|
1313 |
+
|
1314 |
+
if ( ! empty( $cookies ) ) {
|
1315 |
+
foreach ( $cookies as $name => $value ) {
|
1316 |
+
$cron_request['args']['cookies'][] = new WP_Http_Cookie( array( 'name' => $name, 'value' => $value ) );
|
1317 |
+
}
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
$cron_request = apply_filters( 'cron_request', $cron_request );
|
1321 |
+
|
1322 |
+
if ( $starttype === 'test' ) {
|
1323 |
+
$cron_request['args']['timeout'] = 15;
|
1324 |
+
$cron_request['args']['blocking'] = true;
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
if ( ! in_array( $starttype, array( 'runnowlink', 'runext', 'restartalt' ), true ) ) {
|
1328 |
+
delete_transient( 'doing_cron' );
|
1329 |
+
|
1330 |
+
return wp_remote_post( $cron_request['url'], $cron_request['args'] );
|
1331 |
+
}
|
1332 |
+
|
1333 |
+
return $cron_request;
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
/**
|
1337 |
+
* Run baby run
|
1338 |
+
*/
|
1339 |
+
public function run() {
|
1340 |
+
global $wpdb;
|
1341 |
+
/* @var wpdb $wpdb */
|
1342 |
+
|
1343 |
+
//disable output buffering
|
1344 |
+
if ( $level = ob_get_level() ) {
|
1345 |
+
for ( $i = 0; $i < $level; $i ++ ) {
|
1346 |
+
ob_end_clean();
|
1347 |
+
}
|
1348 |
+
}
|
1349 |
+
|
1350 |
+
// Job can't run it is not created
|
1351 |
+
if ( empty( $this->steps_todo ) || empty( $this->logfile ) ) {
|
1352 |
+
$running_file = BackWPup::get_plugin_data( 'running_file' );
|
1353 |
+
if ( file_exists( $running_file ) ) {
|
1354 |
+
unlink( $running_file );
|
1355 |
+
}
|
1356 |
+
|
1357 |
+
return;
|
1358 |
+
}
|
1359 |
+
|
1360 |
+
//Check double running and inactivity
|
1361 |
+
$last_update = microtime( true ) - $this->timestamp_last_update;
|
1362 |
+
if ( ! empty( $this->pid ) && $last_update > 300 ) {
|
1363 |
+
$this->log( __( 'Job restarts due to inactivity for more than 5 minutes.', 'backwpup' ), E_USER_WARNING );
|
1364 |
+
} elseif ( ! empty( $this->pid ) ) {
|
1365 |
+
return;
|
1366 |
+
}
|
1367 |
+
// set timestamp of script start
|
1368 |
+
$this->timestamp_script_start = microtime( true );
|
1369 |
+
//set Pid
|
1370 |
+
$this->pid = self::get_pid();
|
1371 |
+
$this->uniqid = uniqid( '', true );
|
1372 |
+
//Early write new working file
|
1373 |
+
$this->write_running_file();
|
1374 |
+
if ( $this->is_debug() ) {
|
1375 |
+
@ini_set( 'error_log', $this->logfile );
|
1376 |
+
error_reporting( - 1 );
|
1377 |
+
}
|
1378 |
+
@ini_set( 'display_errors', '0' );
|
1379 |
+
@ini_set( 'log_errors', '1' );
|
1380 |
+
@ini_set( 'html_errors', '0' );
|
1381 |
+
@ini_set( 'report_memleaks', '1' );
|
1382 |
+
@ini_set( 'zlib.output_compression', '0' );
|
1383 |
+
@ini_set( 'implicit_flush', '0' );
|
1384 |
+
@putenv( 'TMPDIR=' . BackWPup::get_plugin_data( 'TEMP' ) );
|
1385 |
+
//Write Wordpress DB errors to log
|
1386 |
+
$wpdb->suppress_errors( false );
|
1387 |
+
$wpdb->hide_errors();
|
1388 |
+
//set wp max memory limit
|
1389 |
+
@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
|
1390 |
+
//set error handler
|
1391 |
+
if ( ! empty( $this->logfile ) ) {
|
1392 |
+
if ( $this->is_debug() ) {
|
1393 |
+
set_error_handler( array( $this, 'log' ) );
|
1394 |
+
} else {
|
1395 |
+
set_error_handler( array( $this, 'log' ), E_ALL ^ E_NOTICE );
|
1396 |
+
}
|
1397 |
+
}
|
1398 |
+
set_exception_handler( array( $this, 'exception_handler' ) );
|
1399 |
+
// execute function on job shutdown register_shutdown_function( array( $this, 'shutdown' ) );
|
1400 |
+
add_action( 'shutdown', array( $this, 'shutdown' ) );
|
1401 |
+
|
1402 |
+
if ( function_exists( 'pcntl_signal' ) ) {
|
1403 |
+
$signals = array(
|
1404 |
+
'SIGHUP', //Term
|
1405 |
+
'SIGINT', //Term
|
1406 |
+
'SIGQUIT', //Core
|
1407 |
+
'SIGILL', //Core
|
1408 |
+
//'SIGTRAP', //Core
|
1409 |
+
'SIGABRT', //Core
|
1410 |
+
'SIGBUS', //Core
|
1411 |
+
'SIGFPE', //Core
|
1412 |
+
//'SIGKILL', //Term
|
1413 |
+
'SIGSEGV', //Core
|
1414 |
+
//'SIGPIPE', Term
|
1415 |
+
//'SIGALRM', Term
|
1416 |
+
'SIGTERM', //Term
|
1417 |
+
'SIGSTKFLT', //Term
|
1418 |
+
'SIGUSR1',//Term
|
1419 |
+
'SIGUSR2', //Term
|
1420 |
+
//'SIGCHLD', //Ign
|
1421 |
+
//'SIGCONT', //Cont
|
1422 |
+
//'SIGSTOP', //Stop
|
1423 |
+
//'SIGTSTP', //Stop
|
1424 |
+
//'SIGTTIN', //Stop
|
1425 |
+
//'SIGTTOU', //Stop
|
1426 |
+
//'SIGURG', //Ign
|
1427 |
+
'SIGXCPU', //Core
|
1428 |
+
'SIGXFSZ', //Core
|
1429 |
+
//'SIGVTALRM', //Term
|
1430 |
+
//'SIGPROF', //Term
|
1431 |
+
//'SIGWINCH', //Ign
|
1432 |
+
//'SIGIO', //Term
|
1433 |
+
'SIGPWR', //Term
|
1434 |
+
'SIGSYS' //Core
|
1435 |
+
);
|
1436 |
+
$signals = apply_filters( 'backwpup_job_signals_to_handel', $signals );
|
1437 |
+
declare( ticks = 1 );
|
1438 |
+
$this->signal = 0;
|
1439 |
+
foreach ( $signals as $signal ) {
|
1440 |
+
if ( defined( $signal ) ) {
|
1441 |
+
pcntl_signal( constant( $signal ), array( $this, 'signal_handler' ), false );
|
1442 |
+
}
|
1443 |
+
}
|
1444 |
+
}
|
1445 |
+
$job_types = BackWPup::get_job_types();
|
1446 |
+
//go step by step
|
1447 |
+
foreach ( $this->steps_todo as $this->step_working ) {
|
1448 |
+
//Check if step already done
|
1449 |
+
if ( in_array( $this->step_working, $this->steps_done, true ) ) {
|
1450 |
+
continue;
|
1451 |
+
}
|
1452 |
+
//calc step percent
|
1453 |
+
if ( count( $this->steps_done ) > 0 ) {
|
1454 |
+
$this->step_percent = round( count( $this->steps_done ) / count( $this->steps_todo ) * 100 );
|
1455 |
+
} else {
|
1456 |
+
$this->step_percent = 1;
|
1457 |
+
}
|
1458 |
+
// do step tries
|
1459 |
+
while ( true ) {
|
1460 |
+
if ( $this->steps_data[ $this->step_working ]['STEP_TRY'] >= get_site_option( 'backwpup_cfg_jobstepretry' ) ) {
|
1461 |
+
$this->log( __( 'Step aborted: too many attempts!', 'backwpup' ), E_USER_ERROR );
|
1462 |
+
$this->temp = array();
|
1463 |
+
$this->steps_done[] = $this->step_working;
|
1464 |
+
$this->substeps_done = 0;
|
1465 |
+
$this->substeps_todo = 0;
|
1466 |
+
$this->do_restart();
|
1467 |
+
break;
|
1468 |
+
}
|
1469 |
+
|
1470 |
+
$this->steps_data[ $this->step_working ]['STEP_TRY'] ++;
|
1471 |
+
$done = false;
|
1472 |
+
|
1473 |
+
//executes the methods of job process
|
1474 |
+
if ( $this->step_working == 'CREATE_ARCHIVE' ) {
|
1475 |
+
$done = $this->create_archive();
|
1476 |
+
} elseif ( $this->step_working == 'CREATE_MANIFEST' ) {
|
1477 |
+
$done = $this->create_manifest();
|
1478 |
+
} elseif ( $this->step_working == 'END' ) {
|
1479 |
+
$this->end();
|
1480 |
+
break 2;
|
1481 |
+
} elseif ( strstr( $this->step_working, 'JOB_' ) ) {
|
1482 |
+
$done = $job_types[ str_replace( 'JOB_', '', $this->step_working ) ]->job_run( $this );
|
1483 |
+
} elseif ( strstr( $this->step_working, 'DEST_SYNC_' ) ) {
|
1484 |
+
$done = BackWPup::get_destination( str_replace( 'DEST_SYNC_', '', $this->step_working ) )->job_run_sync( $this );
|
1485 |
+
} elseif ( strstr( $this->step_working, 'DEST_' ) ) {
|
1486 |
+
$done = BackWPup::get_destination( str_replace( 'DEST_', '', $this->step_working ) )->job_run_archive( $this );
|
1487 |
+
} elseif ( ! empty( $this->steps_data[ $this->step_working ]['CALLBACK'] ) ) {
|
1488 |
+
$done = $this->steps_data[ $this->step_working ]['CALLBACK']( $this );
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
// set step as done
|
1492 |
+
if ( $done === true ) {
|
1493 |
+
$this->temp = array();
|
1494 |
+
$this->steps_done[] = $this->step_working;
|
1495 |
+
$this->substeps_done = 0;
|
1496 |
+
$this->substeps_todo = 0;
|
1497 |
+
$this->update_working_data( true );
|
1498 |
+
}
|
1499 |
+
if ( count( $this->steps_done ) < count( $this->steps_todo ) - 1 ) {
|
1500 |
+
$this->do_restart();
|
1501 |
+
}
|
1502 |
+
if ( $done === true ) {
|
1503 |
+
break;
|
1504 |
+
}
|
1505 |
+
}
|
1506 |
+
}
|
1507 |
+
}
|
1508 |
+
|
1509 |
+
/**
|
1510 |
+
* Creates the backup archive
|
1511 |
+
*/
|
1512 |
+
private function create_archive() {
|
1513 |
+
|
1514 |
+
//load folders to backup
|
1515 |
+
$folders_to_backup = $this->get_folders_to_backup();
|
1516 |
+
|
1517 |
+
$this->substeps_todo = $this->count_folder + 1;
|
1518 |
+
|
1519 |
+
//initial settings for restarts in archiving
|
1520 |
+
if ( ! isset( $this->steps_data[ $this->step_working ]['on_file'] ) ) {
|
1521 |
+
$this->steps_data[ $this->step_working ]['on_file'] = '';
|
1522 |
+
}
|
1523 |
+
if ( ! isset( $this->steps_data[ $this->step_working ]['on_folder'] ) ) {
|
1524 |
+
$this->steps_data[ $this->step_working ]['on_folder'] = '';
|
1525 |
+
}
|
1526 |
+
|
1527 |
+
if ( $this->steps_data[ $this->step_working ]['on_folder'] == '' && $this->steps_data[ $this->step_working ]['on_file'] == '' && is_file( $this->backup_folder . $this->backup_file ) ) {
|
1528 |
+
unlink( $this->backup_folder . $this->backup_file );
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
if ( $this->steps_data[ $this->step_working ]['SAVE_STEP_TRY'] != $this->steps_data[ $this->step_working ]['STEP_TRY'] ) {
|
1532 |
+
$this->log( sprintf( __( '%d. Trying to create backup archive …', 'backwpup' ), $this->steps_data[ $this->step_working ]['STEP_TRY'] ), E_USER_NOTICE );
|
1533 |
+
}
|
1534 |
+
|
1535 |
+
try {
|
1536 |
+
$backup_archive = new BackWPup_Create_Archive( $this->backup_folder . $this->backup_file );
|
1537 |
+
|
1538 |
+
//show method for creation
|
1539 |
+
if ( $this->substeps_done == 0 ) {
|
1540 |
+
$this->log( sprintf( _x( 'Compressing files as %s. Please be patient, this may take a moment.', 'Archive compression method', 'backwpup' ), $backup_archive->get_method() ) );
|
1541 |
+
}
|
1542 |
+
|
1543 |
+
//add extra files
|
1544 |
+
if ( $this->substeps_done == 0 ) {
|
1545 |
+
if ( ! empty( $this->additional_files_to_backup ) && $this->substeps_done == 0 ) {
|
1546 |
+
if ( $this->is_debug() ) {
|
1547 |
+
$this->log( __( 'Adding Extra files to Archive', 'backwpup' ) );
|
1548 |
+
}
|
1549 |
+
foreach ( $this->additional_files_to_backup as $file ) {
|
1550 |
+
if ( $backup_archive->add_file( $file, basename( $file ) ) ) {
|
1551 |
+
;
|
1552 |
+
$this->count_files ++;
|
1553 |
+
$this->count_files_size = $this->count_files_size + filesize( $file );
|
1554 |
+
$this->update_working_data();
|
1555 |
+
} else {
|
1556 |
+
$backup_archive->close();
|
1557 |
+
$this->steps_data[ $this->step_working ]['on_file'] = '';
|
1558 |
+
$this->steps_data[ $this->step_working ]['on_folder'] = '';
|
1559 |
+
$this->log( __( 'Cannot create backup archive correctly. Aborting creation.', 'backwpup' ), E_USER_ERROR );
|
1560 |
+
|
1561 |
+
return false;
|
1562 |
+
}
|
1563 |
+
}
|
1564 |
+
}
|
1565 |
+
$this->substeps_done ++;
|
1566 |
+
}
|
1567 |
+
|
1568 |
+
//add normal files
|
1569 |
+
while ( $folder = array_shift( $folders_to_backup ) ) {
|
1570 |
+
//jump over already done folders
|
1571 |
+
if ( in_array( $this->steps_data[ $this->step_working ]['on_folder'], $folders_to_backup, true ) ) {
|
1572 |
+
continue;
|
1573 |
+
}
|
1574 |
+
if ( $this->is_debug() ) {
|
1575 |
+
$this->log( sprintf( __( 'Archiving Folder: %s', 'backwpup' ), $folder ) );
|
1576 |
+
}
|
1577 |
+
$this->steps_data[ $this->step_working ]['on_folder'] = $folder;
|
1578 |
+
$files_in_folder = $this->get_files_in_folder( $folder );
|
1579 |
+
//add empty folders
|
1580 |
+
if ( empty( $files_in_folder ) ) {
|
1581 |
+
$folder_name_in_archive = trim( ltrim( $this->get_destination_path_replacement( $folder ), '/' ) );
|
1582 |
+
if ( ! empty ( $folder_name_in_archive ) ) {
|
1583 |
+
$backup_archive->add_empty_folder( $folder, $folder_name_in_archive );
|
1584 |
+
}
|
1585 |
+
continue;
|
1586 |
+
}
|
1587 |
+
//add files
|
1588 |
+
while ( $file = array_shift( $files_in_folder ) ) {
|
1589 |
+
//jump over already done files
|
1590 |
+
if ( in_array( $this->steps_data[ $this->step_working ]['on_file'], $files_in_folder, true ) ) {
|
1591 |
+
continue;
|
1592 |
+
}
|
1593 |
+
$this->steps_data[ $this->step_working ]['on_file'] = $file;
|
1594 |
+
//restart if needed
|
1595 |
+
$restart_time = $this->get_restart_time();
|
1596 |
+
if ( $restart_time <= 0 ) {
|
1597 |
+
unset( $backup_archive );
|
1598 |
+
$this->do_restart_time( true );
|
1599 |
+
|
1600 |
+
return false;
|
1601 |
+
}
|
1602 |
+
//generate filename in archive
|
1603 |
+
$in_archive_filename = ltrim( $this->get_destination_path_replacement( $file ), '/' );
|
1604 |
+
//add file to archive
|
1605 |
+
if ( $backup_archive->add_file( $file, $in_archive_filename ) ) {
|
1606 |
+
$this->count_files ++;
|
1607 |
+
$this->count_files_size = $this->count_files_size + filesize( $file );
|
1608 |
+
$this->update_working_data();
|
1609 |
+
} else {
|
1610 |
+
$backup_archive->close();
|
1611 |
+
unset( $backup_archive );
|
1612 |
+
$this->steps_data[ $this->step_working ]['on_file'] = '';
|
1613 |
+
$this->steps_data[ $this->step_working ]['on_folder'] = '';
|
1614 |
+
$this->substeps_done = 0;
|
1615 |
+
$this->backup_filesize = filesize( $this->backup_folder . $this->backup_file );
|
1616 |
+
if ( $this->backup_filesize === false ) {
|
1617 |
+
$this->backup_filesize = PHP_INT_MAX;
|
1618 |
+
}
|
1619 |
+
$this->log( __( 'Cannot create backup archive correctly. Aborting creation.', 'backwpup' ), E_USER_ERROR );
|
1620 |
+
|
1621 |
+
return false;
|
1622 |
+
}
|
1623 |
+
}
|
1624 |
+
$this->steps_data[ $this->step_working ]['on_file'] = '';
|
1625 |
+
$this->substeps_done ++;
|
1626 |
+
}
|
1627 |
+
$backup_archive->close();
|
1628 |
+
unset( $backup_archive );
|
1629 |
+
$this->log( __( 'Backup archive created.', 'backwpup' ), E_USER_NOTICE );
|
1630 |
+
} catch ( Exception $e ) {
|
1631 |
+
$this->log( $e->getMessage(), E_USER_ERROR, $e->getFile(), $e->getLine() );
|
1632 |
+
unset( $backup_archive );
|
1633 |
+
|
1634 |
+
return false;
|
1635 |
+
}
|
1636 |
+
|
1637 |
+
$this->backup_filesize = filesize( $this->backup_folder . $this->backup_file );
|
1638 |
+
if ( $this->backup_filesize === false ) {
|
1639 |
+
$this->backup_filesize = PHP_INT_MAX;
|
1640 |
+
}
|
1641 |
+
|
1642 |
+
if ( $this->backup_filesize >= PHP_INT_MAX ) {
|
1643 |
+
$this->log( __( 'The Backup archive will be too large for file operations with this PHP Version. You might want to consider splitting the backup job in multiple jobs with less files each.', 'backwpup' ), E_USER_ERROR );
|
1644 |
+
$this->end();
|
1645 |
+
} else {
|
1646 |
+
$this->log( sprintf( __( 'Archive size is %s.', 'backwpup' ), size_format( $this->backup_filesize, 2 ) ), E_USER_NOTICE );
|
1647 |
+
}
|
1648 |
+
|
1649 |
+
$this->log( sprintf( __( '%1$d Files with %2$s in Archive.', 'backwpup' ), $this->count_files, size_format( $this->count_files_size, 2 ) ), E_USER_NOTICE );
|
1650 |
+
|
1651 |
+
return true;
|
1652 |
+
}
|
1653 |
+
|
1654 |
+
/**
|
1655 |
+
* Get list of Folder for backup
|
1656 |
+
*
|
1657 |
+
* @return array folder list
|
1658 |
+
*/
|
1659 |
+
public function get_folders_to_backup() {
|
1660 |
+
|
1661 |
+
$file = BackWPup::get_plugin_data( 'temp' ) . 'backwpup-' . BackWPup::get_plugin_data( 'hash' ) . '-folder.php';
|
1662 |
+
|
1663 |
+
if ( ! file_exists( $file ) ) {
|
1664 |
+
return array();
|
1665 |
+
}
|
1666 |
+
|
1667 |
+
$folders = array();
|
1668 |
+
|
1669 |
+
$file_data = file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
|
1670 |
+
|
1671 |
+
foreach ( $file_data as $folder ) {
|
1672 |
+
$folder = trim( str_replace( array( '<?php', '//' ), '', $folder ) );
|
1673 |
+
if ( ! empty( $folder ) && is_dir( $folder ) ) {
|
1674 |
+
$folders[] = $folder;
|
1675 |
+
}
|
1676 |
+
}
|
1677 |
+
$folders = array_unique( $folders );
|
1678 |
+
sort( $folders );
|
1679 |
+
$this->count_folder = count( $folders );
|
1680 |
+
|
1681 |
+
return $folders;
|
1682 |
+
}
|
1683 |
+
|
1684 |
+
/**
|
1685 |
+
*
|
1686 |
+
* Get back a array of files to backup in the selected folder
|
1687 |
+
*
|
1688 |
+
* @param string $folder the folder to get the files from
|
1689 |
+
*
|
1690 |
+
* @return array files to backup
|
1691 |
+
*/
|
1692 |
+
public function get_files_in_folder( $folder ) {
|
1693 |
+
|
1694 |
+
$files = array();
|
1695 |
+
$folder = trailingslashit( $folder );
|
1696 |
+
|
1697 |
+
if ( ! is_dir( $folder ) ) {
|
1698 |
+
$this->log( sprintf( _x( 'Folder %s does not exist', 'Folder name', 'backwpup' ), $folder ), E_USER_WARNING );
|
1699 |
+
return $files;
|
1700 |
+
}
|
1701 |
+
|
1702 |
+
if ( ! is_readable( $folder ) ) {
|
1703 |
+
$this->log( sprintf( _x( 'Folder %s is not readable', 'Folder name', 'backwpup' ), $folder ), E_USER_WARNING );
|
1704 |
+
return $files;
|
1705 |
+
}
|
1706 |
+
|
1707 |
+
try {
|
1708 |
+
$dir = new BackWPup_Directory( $folder );
|
1709 |
+
|
1710 |
+
foreach ( $dir as $file ) {
|
1711 |
+
if ( $file->isDir() || $file->isDot() ) {
|
1712 |
+
continue;
|
1713 |
+
}
|
1714 |
+
$path = str_replace( '\\', '/', realpath( $file->getPathname() ) );
|
1715 |
+
foreach ( $this->exclude_from_backup as $exclusion ) { //exclude files
|
1716 |
+
$exclusion = trim( $exclusion );
|
1717 |
+
if ( stripos( $path, $exclusion ) !== false && ! empty( $exclusion ) ) {
|
1718 |
+
continue 2;
|
1719 |
+
}
|
1720 |
+
}
|
1721 |
+
if ( $this->job['backupexcludethumbs'] && strpos( $folder, BackWPup_File::get_upload_dir() ) !== false && preg_match( "/\-[0-9]{1,4}x[0-9]{1,4}.+\.(jpg|png|gif)$/i", $file->getFilename() ) ) {
|
1722 |
+
continue;
|
1723 |
+
}
|
1724 |
+
if ( $file->isLink() ) {
|
1725 |
+
$this->log( sprintf( __( 'Link "%s" not following.', 'backwpup' ), $file->getPathname() ), E_USER_WARNING );
|
1726 |
+
} elseif ( ! $file->isReadable() ) {
|
1727 |
+
$this->log( sprintf( __( 'File "%s" is not readable!', 'backwpup' ), $file->getPathname() ), E_USER_WARNING );
|
1728 |
+
} else {
|
1729 |
+
$file_size = $file->getSize();
|
1730 |
+
if ( ! is_int( $file_size ) || $file_size < 0 || $file_size > 2147483647 ) {
|
1731 |
+
$this->log( sprintf( __( 'File size of “%s” cannot be retrieved. File might be too large and will not be added to queue.', 'backwpup' ), $file->getPathname() . ' ' . $file_size ), E_USER_WARNING );
|
1732 |
+
continue;
|
1733 |
+
}
|
1734 |
+
$files[] = $path;
|
1735 |
+
}
|
1736 |
+
}
|
1737 |
+
|
1738 |
+
}
|
1739 |
+
catch ( UnexpectedValueException $e ) {
|
1740 |
+
$this->log( sprintf( __( "Could not open path: %s" ), $e->getMessage() ), E_USER_WARNING );
|
1741 |
+
}
|
1742 |
+
|
1743 |
+
return $files;
|
1744 |
+
}
|
1745 |
+
|
1746 |
+
/**
|
1747 |
+
* Get job restart time
|
1748 |
+
*
|
1749 |
+
* @return int remaining time
|
1750 |
+
*/
|
1751 |
+
public function get_restart_time() {
|
1752 |
+
|
1753 |
+
if ( php_sapi_name() == 'cli' ) {
|
1754 |
+
return 300;
|
1755 |
+
}
|
1756 |
+
|
1757 |
+
$job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
|
1758 |
+
|
1759 |
+
if ( empty( $job_max_execution_time ) ) {
|
1760 |
+
return 300;
|
1761 |
+
}
|
1762 |
+
|
1763 |
+
$execution_time = microtime( true ) - $this->timestamp_script_start;
|
1764 |
+
|
1765 |
+
return $job_max_execution_time - $execution_time - 3;
|
1766 |
+
}
|
1767 |
+
|
1768 |
+
/**
|
1769 |
+
* Do a job restart
|
1770 |
+
*
|
1771 |
+
* @param bool $do_restart_now should time restart now be done
|
1772 |
+
*
|
1773 |
+
* @return int remaining time
|
1774 |
+
*/
|
1775 |
+
public function do_restart_time( $do_restart_now = false ) {
|
1776 |
+
|
1777 |
+
if ( php_sapi_name() == 'cli' ) {
|
1778 |
+
return 300;
|
1779 |
+
}
|
1780 |
+
|
1781 |
+
//do restart after signal is send
|
1782 |
+
if ( $this->signal !== 0 ) {
|
1783 |
+
$this->steps_data[ $this->step_working ]['SAVE_STEP_TRY'] = $this->steps_data[ $this->step_working ]['STEP_TRY'];
|
1784 |
+
$this->steps_data[ $this->step_working ]['STEP_TRY'] -= 1;
|
1785 |
+
$this->do_restart( true );
|
1786 |
+
}
|
1787 |
+
|
1788 |
+
$job_max_execution_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
|
1789 |
+
|
1790 |
+
if ( empty( $job_max_execution_time ) ) {
|
1791 |
+
return 300;
|
1792 |
+
}
|
1793 |
+
|
1794 |
+
$execution_time = microtime( true ) - $this->timestamp_script_start;
|
1795 |
+
|
1796 |
+
// do restart 3 sec. before max. execution time
|
1797 |
+
if ( $do_restart_now || $execution_time >= ( $job_max_execution_time - 3 ) ) {
|
1798 |
+
$this->steps_data[ $this->step_working ]['SAVE_STEP_TRY'] = $this->steps_data[ $this->step_working ]['STEP_TRY'];
|
1799 |
+
$this->steps_data[ $this->step_working ]['STEP_TRY'] -= 1;
|
1800 |
+
$this->do_restart( true );
|
1801 |
+
}
|
1802 |
+
|
1803 |
+
return $job_max_execution_time - $execution_time;
|
1804 |
+
}
|
1805 |
+
|
1806 |
+
/**
|
1807 |
+
* create manifest file
|
1808 |
+
* @return bool
|
1809 |
+
*/
|
1810 |
+
public function create_manifest() {
|
1811 |
+
|
1812 |
+
$this->substeps_todo = 3;
|
1813 |
+
|
1814 |
+
$this->log( sprintf( __( '%d. Trying to generate a manifest file …', 'backwpup' ), $this->steps_data[ $this->step_working ]['STEP_TRY'] ) );
|
1815 |
+
|
1816 |
+
//build manifest
|
1817 |
+
$manifest = array();
|
1818 |
+
// add blog information
|
1819 |
+
$manifest['blog_info']['url'] = home_url();
|
1820 |
+
$manifest['blog_info']['wpurl'] = site_url();
|
1821 |
+
$manifest['blog_info']['prefix'] = $GLOBALS['wpdb']->prefix;
|
1822 |
+
$manifest['blog_info']['description'] = get_option( 'blogdescription' );
|
1823 |
+
$manifest['blog_info']['stylesheet_directory'] = get_template_directory_uri();
|
1824 |
+
$manifest['blog_info']['activate_plugins'] = wp_get_active_and_valid_plugins();
|
1825 |
+
$manifest['blog_info']['activate_theme'] = wp_get_theme()->get( 'Name' );
|
1826 |
+
$manifest['blog_info']['admin_email'] = get_option( 'admin_email' );
|
1827 |
+
$manifest['blog_info']['charset'] = get_bloginfo( 'charset' );
|
1828 |
+
$manifest['blog_info']['version'] = BackWPup::get_plugin_data( 'wp_version' );
|
1829 |
+
$manifest['blog_info']['backwpup_version'] = BackWPup::get_plugin_data( 'version' );
|
1830 |
+
$manifest['blog_info']['language'] = get_bloginfo( 'language' );
|
1831 |
+
$manifest['blog_info']['name'] = get_bloginfo( 'name' );
|
1832 |
+
$manifest['blog_info']['abspath'] = ABSPATH;
|
1833 |
+
$manifest['blog_info']['uploads'] = wp_upload_dir( null, false, true );
|
1834 |
+
$manifest['blog_info']['contents']['basedir'] = WP_CONTENT_DIR;
|
1835 |
+
$manifest['blog_info']['contents']['baseurl'] = WP_CONTENT_URL;
|
1836 |
+
$manifest['blog_info']['plugins']['basedir'] = WP_PLUGIN_DIR;
|
1837 |
+
$manifest['blog_info']['plugins']['baseurl'] = WP_PLUGIN_URL;
|
1838 |
+
$manifest['blog_info']['themes']['basedir'] = get_theme_root();
|
1839 |
+
$manifest['blog_info']['themes']['baseurl'] = get_theme_root_uri();
|
1840 |
+
// add job settings
|
1841 |
+
$manifest['job_settings'] = $this->job;
|
1842 |
+
// add archive info
|
1843 |
+
foreach ( $this->additional_files_to_backup as $file ) {
|
1844 |
+
$manifest['archive']['extra_files'][] = basename( $file );
|
1845 |
+
}
|
1846 |
+
if ( isset( $this->steps_data['JOB_FILE'] ) ) {
|
1847 |
+
if ( $this->job['backuproot'] ) {
|
1848 |
+
$manifest['archive']['abspath'] = trailingslashit( $this->get_destination_path_replacement( ABSPATH ) );
|
1849 |
+
}
|
1850 |
+
if ( $this->job['backupuploads'] ) {
|
1851 |
+
$manifest['archive']['uploads'] = trailingslashit( $this->get_destination_path_replacement( BackWPup_File::get_upload_dir() ) );
|
1852 |
+
}
|
1853 |
+
if ( $this->job['backupcontent'] ) {
|
1854 |
+
$manifest['archive']['contents'] = trailingslashit( $this->get_destination_path_replacement( WP_CONTENT_DIR ) );
|
1855 |
+
}
|
1856 |
+
if ( $this->job['backupplugins'] ) {
|
1857 |
+
$manifest['archive']['plugins'] = trailingslashit( $this->get_destination_path_replacement( WP_PLUGIN_DIR ) );
|
1858 |
+
}
|
1859 |
+
if ( $this->job['backupthemes'] ) {
|
1860 |
+
$manifest['archive']['themes'] = trailingslashit( $this->get_destination_path_replacement( get_theme_root() ) );
|
1861 |
+
}
|
1862 |
+
}
|
1863 |
+
|
1864 |
+
if ( ! file_put_contents( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json', json_encode( $manifest ) ) ) {
|
1865 |
+
return false;
|
1866 |
+
}
|
1867 |
+
$this->substeps_done = 1;
|
1868 |
+
|
1869 |
+
//Create backwpup_readme.txt
|
1870 |
+
$readme_text = __( 'You may have noticed the manifest.json file in this archive.', 'backwpup' ) . PHP_EOL;
|
1871 |
+
$readme_text .= __( 'manifest.json might be needed for later restoring a backup from this archive.', 'backwpup' ) . PHP_EOL;
|
1872 |
+
$readme_text .= __( 'Please leave manifest.json untouched and in place. Otherwise it is safe to be ignored.', 'backwpup' ) . PHP_EOL;
|
1873 |
+
if ( ! file_put_contents( BackWPup::get_plugin_data( 'TEMP' ) . 'backwpup_readme.txt', $readme_text ) ) {
|
1874 |
+
return false;
|
1875 |
+
}
|
1876 |
+
$this->substeps_done = 2;
|
1877 |
+
|
1878 |
+
//add file to backup files
|
1879 |
+
if ( is_readable( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json' ) ) {
|
1880 |
+
$this->additional_files_to_backup[] = BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json';
|
1881 |
+
$this->additional_files_to_backup[] = BackWPup::get_plugin_data( 'TEMP' ) . 'backwpup_readme.txt';
|
1882 |
+
$this->log( sprintf( __( 'Added manifest.json file with %1$s to backup file list.', 'backwpup' ), size_format( filesize( BackWPup::get_plugin_data( 'TEMP' ) . 'manifest.json' ), 2 ) ) );
|
1883 |
+
}
|
1884 |
+
$this->substeps_done = 3;
|
1885 |
+
|
1886 |
+
return true;
|
1887 |
+
}
|
1888 |
+
|
1889 |
+
/**
|
1890 |
+
* @param $jobid
|
1891 |
+
*/
|
1892 |
+
public static function start_cli( $jobid ) {
|
1893 |
+
|
1894 |
+
if ( php_sapi_name() != 'cli' ) {
|
1895 |
+
return;
|
1896 |
+
}
|
1897 |
+
|
1898 |
+
//define DOING_CRON to prevent caching
|
1899 |
+
if ( ! defined( 'DOING_CRON' ) ) {
|
1900 |
+
define( 'DOING_CRON', true );
|
1901 |
+
}
|
1902 |
+
|
1903 |
+
//load text domain
|
1904 |
+
$log_level = get_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
1905 |
+
if ( strstr( $log_level, 'translated' ) ) {
|
1906 |
+
BackWPup::load_text_domain();
|
1907 |
+
} else {
|
1908 |
+
add_filter( 'override_load_textdomain', '__return_true' );
|
1909 |
+
$GLOBALS['l10n'] = array();
|
1910 |
+
}
|
1911 |
+
|
1912 |
+
$jobid = absint( $jobid );
|
1913 |
+
|
1914 |
+
//Logs Folder
|
1915 |
+
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
1916 |
+
$log_folder = BackWPup_File::get_absolute_path( $log_folder );
|
1917 |
+
|
1918 |
+
//check job id exists
|
1919 |
+
$jobids = BackWPup_Option::get_job_ids();
|
1920 |
+
if ( ! in_array( $jobid, $jobids, true ) ) {
|
1921 |
+
die( __( 'Wrong BackWPup JobID', 'backwpup' ) );
|
1922 |
+
}
|
1923 |
+
//check folders
|
1924 |
+
$log_folder_message = BackWPup_File::check_folder( $log_folder );
|
1925 |
+
if ( ! empty( $log_folder_message ) ) {
|
1926 |
+
die( $log_folder_message );
|
1927 |
+
}
|
1928 |
+
$log_folder_message = BackWPup_File::check_folder( BackWPup::get_plugin_data( 'TEMP' ), true );
|
1929 |
+
if ( ! empty( $log_folder_message ) ) {
|
1930 |
+
die( $log_folder_message );
|
1931 |
+
}
|
1932 |
+
//check running job
|
1933 |
+
if ( file_exists( BackWPup::get_plugin_data( 'running_file' ) ) ) {
|
1934 |
+
die( __( 'A BackWPup job is already running', 'backwpup' ) );
|
1935 |
+
}
|
1936 |
+
|
1937 |
+
//start class
|
1938 |
+
$backwpup_job_object = new self();
|
1939 |
+
$backwpup_job_object->create( 'runcli', (int) $jobid );
|
1940 |
+
$backwpup_job_object->run();
|
1941 |
+
}
|
1942 |
+
|
1943 |
+
/**
|
1944 |
+
* disable caches
|
1945 |
+
*/
|
1946 |
+
public static function disable_caches() {
|
1947 |
+
|
1948 |
+
//Special settings
|
1949 |
+
@putenv( 'nokeepalive=1' );
|
1950 |
+
@ini_set( 'zlib.output_compression', 'Off' );
|
1951 |
+
|
1952 |
+
// deactivate caches
|
1953 |
+
if ( ! defined( 'DONOTCACHEDB' ) ) {
|
1954 |
+
define( 'DONOTCACHEDB', true );
|
1955 |
+
}
|
1956 |
+
if ( ! defined( 'DONOTCACHEPAGE' ) ) {
|
1957 |
+
define( 'DONOTCACHEPAGE', true );
|
1958 |
+
}
|
1959 |
+
}
|
1960 |
+
|
1961 |
+
/**
|
1962 |
+
*
|
1963 |
+
* Reads a BackWPup logfile header and gives back a array of information
|
1964 |
+
*
|
1965 |
+
* @param string $logfile full logfile path
|
1966 |
+
*
|
1967 |
+
* @return array|bool
|
1968 |
+
*/
|
1969 |
+
public static function read_logheader( $logfile ) {
|
1970 |
+
|
1971 |
+
$usedmetas = array(
|
1972 |
+
"date" => "logtime",
|
1973 |
+
"backwpup_logtime" => "logtime", //old value of date
|
1974 |
+
"backwpup_errors" => "errors",
|
1975 |
+
"backwpup_warnings" => "warnings",
|
1976 |
+
"backwpup_jobid" => "jobid",
|
1977 |
+
"backwpup_jobname" => "name",
|
1978 |
+
"backwpup_jobtype" => "type",
|
1979 |
+
"backwpup_jobruntime" => "runtime",
|
1980 |
+
"backwpup_backupfilesize" => "backupfilesize"
|
1981 |
+
);
|
1982 |
+
|
1983 |
+
//get metadata of logfile
|
1984 |
+
$metas = array();
|
1985 |
+
if ( is_readable( $logfile ) ) {
|
1986 |
+
if ( '.gz' == substr( $logfile, - 3 ) ) {
|
1987 |
+
$metas = (array) get_meta_tags( 'compress.zlib://' . $logfile );
|
1988 |
+
} else {
|
1989 |
+
$metas = (array) get_meta_tags( $logfile );
|
1990 |
+
}
|
1991 |
+
}
|
1992 |
+
|
1993 |
+
//only output needed data
|
1994 |
+
foreach ( $usedmetas as $keyword => $field ) {
|
1995 |
+
if ( isset( $metas[ $keyword ] ) ) {
|
1996 |
+
$joddata[ $field ] = $metas[ $keyword ];
|
1997 |
+
} else {
|
1998 |
+
$joddata[ $field ] = '';
|
1999 |
+
}
|
2000 |
+
}
|
2001 |
+
|
2002 |
+
//convert date
|
2003 |
+
if ( isset( $metas['date'] ) ) {
|
2004 |
+
$joddata['logtime'] = strtotime( $metas['date'] ) + ( get_option( 'gmt_offset' ) * 3600 );
|
2005 |
+
}
|
2006 |
+
|
2007 |
+
//use file create date if none
|
2008 |
+
if ( empty( $joddata['logtime'] ) ) {
|
2009 |
+
$joddata['logtime'] = filectime( $logfile );
|
2010 |
+
}
|
2011 |
+
|
2012 |
+
return $joddata;
|
2013 |
+
}
|
2014 |
+
|
2015 |
+
public static function user_abort() {
|
2016 |
+
|
2017 |
+
/* @var $job_object BackWPup_Job */
|
2018 |
+
$job_object = BackWPup_Job::get_working_data();
|
2019 |
+
|
2020 |
+
unlink( BackWPup::get_plugin_data( 'running_file' ) );
|
2021 |
+
|
2022 |
+
//if job not working currently abort it this way for message
|
2023 |
+
$not_worked_time = microtime( true ) - $job_object->timestamp_last_update;
|
2024 |
+
$restart_time = get_site_option( 'backwpup_cfg_jobmaxexecutiontime' );
|
2025 |
+
if ( empty( $restart_time ) ) {
|
2026 |
+
$restart_time = 60;
|
2027 |
+
}
|
2028 |
+
if ( empty( $job_object->pid ) || $not_worked_time > $restart_time ) {
|
2029 |
+
$job_object->user_abort = true;
|
2030 |
+
$job_object->update_working_data();
|
2031 |
+
}
|
2032 |
+
|
2033 |
+
}
|
2034 |
+
|
2035 |
+
/**
|
2036 |
+
*
|
2037 |
+
* Get the mime type of a file
|
2038 |
+
*
|
2039 |
+
* @param string $file The full file name
|
2040 |
+
*
|
2041 |
+
* @return bool|string the mime type or false
|
2042 |
+
*/
|
2043 |
+
public static function get_mime_type( $file ) {
|
2044 |
+
|
2045 |
+
if ( is_dir( $file ) || is_link( $file ) ) {
|
2046 |
+
return 'application/octet-stream';
|
2047 |
+
}
|
2048 |
+
|
2049 |
+
$mime_types = array(
|
2050 |
+
'zip' => 'application/zip',
|
2051 |
+
'gz' => 'application/gzip',
|
2052 |
+
'bz2' => 'application/x-bzip',
|
2053 |
+
'tar' => 'application/x-tar',
|
2054 |
+
'3gp' => 'video/3gpp',
|
2055 |
+
'ai' => 'application/postscript',
|
2056 |
+
'aif' => 'audio/x-aiff',
|
2057 |
+
'aifc' => 'audio/x-aiff',
|
2058 |
+
'aiff' => 'audio/x-aiff',
|
2059 |
+
'asc' => 'text/plain',
|
2060 |
+
'atom' => 'application/atom+xml',
|
2061 |
+
'au' => 'audio/basic',
|
2062 |
+
'avi' => 'video/x-msvideo',
|
2063 |
+
'bcpio' => 'application/x-bcpio',
|
2064 |
+
'bin' => 'application/octet-stream',
|
2065 |
+
'bmp' => 'image/bmp',
|
2066 |
+
'cdf' => 'application/x-netcdf',
|
2067 |
+
'cgm' => 'image/cgm',
|
2068 |
+
'class' => 'application/octet-stream',
|
2069 |
+
'cpio' => 'application/x-cpio',
|
2070 |
+
'cpt' => 'application/mac-compactpro',
|
2071 |
+
'csh' => 'application/x-csh',
|
2072 |
+
'css' => 'text/css',
|
2073 |
+
'dcr' => 'application/x-director',
|
2074 |
+
'dif' => 'video/x-dv',
|
2075 |
+
'dir' => 'application/x-director',
|
2076 |
+
'djv' => 'image/vnd.djvu',
|
2077 |
+
'djvu' => 'image/vnd.djvu',
|
2078 |
+
'dll' => 'application/octet-stream',
|
2079 |
+
'dmg' => 'application/octet-stream',
|
2080 |
+
'dms' => 'application/octet-stream',
|
2081 |
+
'doc' => 'application/msword',
|
2082 |
+
'dtd' => 'application/xml-dtd',
|
2083 |
+
'dv' => 'video/x-dv',
|
2084 |
+
'dvi' => 'application/x-dvi',
|
2085 |
+
'dxr' => 'application/x-director',
|
2086 |
+
'eps' => 'application/postscript',
|
2087 |
+
'etx' => 'text/x-setext',
|
2088 |
+
'exe' => 'application/octet-stream',
|
2089 |
+
'ez' => 'application/andrew-inset',
|
2090 |
+
'flv' => 'video/x-flv',
|
2091 |
+
'gif' => 'image/gif',
|
2092 |
+
'gram' => 'application/srgs',
|
2093 |
+
'grxml' => 'application/srgs+xml',
|
2094 |
+
'gtar' => 'application/x-gtar',
|
2095 |
+
'hdf' => 'application/x-hdf',
|
2096 |
+
'hqx' => 'application/mac-binhex40',
|
2097 |
+
'htm' => 'text/html',
|
2098 |
+
'html' => 'text/html',
|
2099 |
+
'ice' => 'x-conference/x-cooltalk',
|
2100 |
+
'ico' => 'image/x-icon',
|
2101 |
+
'ics' => 'text/calendar',
|
2102 |
+
'ief' => 'image/ief',
|
2103 |
+
'ifb' => 'text/calendar',
|
2104 |
+
'iges' => 'model/iges',
|
2105 |
+
'igs' => 'model/iges',
|
2106 |
+
'jnlp' => 'application/x-java-jnlp-file',
|
2107 |
+
'jp2' => 'image/jp2',
|
2108 |
+
'jpe' => 'image/jpeg',
|
2109 |
+
'jpeg' => 'image/jpeg',
|
2110 |
+
'jpg' => 'image/jpeg',
|
2111 |
+
'js' => 'application/x-javascript',
|
2112 |
+
'kar' => 'audio/midi',
|
2113 |
+
'latex' => 'application/x-latex',
|
2114 |
+
'lha' => 'application/octet-stream',
|
2115 |
+
'lzh' => 'application/octet-stream',
|
2116 |
+
'm3u' => 'audio/x-mpegurl',
|
2117 |
+
'm4a' => 'audio/mp4a-latm',
|
2118 |
+
'm4p' => 'audio/mp4a-latm',
|
2119 |
+
'm4u' => 'video/vnd.mpegurl',
|
2120 |
+
'm4v' => 'video/x-m4v',
|
2121 |
+
'mac' => 'image/x-macpaint',
|
2122 |
+
'man' => 'application/x-troff-man',
|
2123 |
+
'mathml' => 'application/mathml+xml',
|
2124 |
+
'me' => 'application/x-troff-me',
|
2125 |
+
'mesh' => 'model/mesh',
|
2126 |
+
'mid' => 'audio/midi',
|
2127 |
+
'midi' => 'audio/midi',
|
2128 |
+
'mif' => 'application/vnd.mif',
|
2129 |
+
'mov' => 'video/quicktime',
|
2130 |
+
'movie' => 'video/x-sgi-movie',
|
2131 |
+
'mp2' => 'audio/mpeg',
|
2132 |
+
'mp3' => 'audio/mpeg',
|
2133 |
+
'mp4' => 'video/mp4',
|
2134 |
+
'mpe' => 'video/mpeg',
|
2135 |
+
'mpeg' => 'video/mpeg',
|
2136 |
+
'mpg' => 'video/mpeg',
|
2137 |
+
'mpga' => 'audio/mpeg',
|
2138 |
+
'ms' => 'application/x-troff-ms',
|
2139 |
+
'msh' => 'model/mesh',
|
2140 |
+
'mxu' => 'video/vnd.mpegurl',
|
2141 |
+
'nc' => 'application/x-netcdf',
|
2142 |
+
'oda' => 'application/oda',
|
2143 |
+
'ogg' => 'application/ogg',
|
2144 |
+
'ogv' => 'video/ogv',
|
2145 |
+
'pbm' => 'image/x-portable-bitmap',
|
2146 |
+
'pct' => 'image/pict',
|
2147 |
+
'pdb' => 'chemical/x-pdb',
|
2148 |
+
'pdf' => 'application/pdf',
|
2149 |
+
'pgm' => 'image/x-portable-graymap',
|
2150 |
+
'pgn' => 'application/x-chess-pgn',
|
2151 |
+
'pic' => 'image/pict',
|
2152 |
+
'pict' => 'image/pict',
|
2153 |
+
'png' => 'image/png',
|
2154 |
+
'pnm' => 'image/x-portable-anymap',
|
2155 |
+
'pnt' => 'image/x-macpaint',
|
2156 |
+
'pntg' => 'image/x-macpaint',
|
2157 |
+
'ppm' => 'image/x-portable-pixmap',
|
2158 |
+
'ppt' => 'application/vnd.ms-powerpoint',
|
2159 |
+
'ps' => 'application/postscript',
|
2160 |
+
'qt' => 'video/quicktime',
|
2161 |
+
'qti' => 'image/x-quicktime',
|
2162 |
+
'qtif' => 'image/x-quicktime',
|
2163 |
+
'ra' => 'audio/x-pn-realaudio',
|
2164 |
+
'ram' => 'audio/x-pn-realaudio',
|
2165 |
+
'ras' => 'image/x-cmu-raster',
|
2166 |
+
'rdf' => 'application/rdf+xml',
|
2167 |
+
'rgb' => 'image/x-rgb',
|
2168 |
+
'rm' => 'application/vnd.rn-realmedia',
|
2169 |
+
'roff' => 'application/x-troff',
|
2170 |
+
'rtf' => 'text/rtf',
|
2171 |
+
'rtx' => 'text/richtext',
|
2172 |
+
'sgm' => 'text/sgml',
|
2173 |
+
'sgml' => 'text/sgml',
|
2174 |
+
'sh' => 'application/x-sh',
|
2175 |
+
'shar' => 'application/x-shar',
|
2176 |
+
'silo' => 'model/mesh',
|
2177 |
+
'sit' => 'application/x-stuffit',
|
2178 |
+
'skd' => 'application/x-koan',
|
2179 |
+
'skm' => 'application/x-koan',
|
2180 |
+
'skp' => 'application/x-koan',
|
2181 |
+
'skt' => 'application/x-koan',
|
2182 |
+
'smi' => 'application/smil',
|
2183 |
+
'smil' => 'application/smil',
|
2184 |
+
'snd' => 'audio/basic',
|
2185 |
+
'so' => 'application/octet-stream',
|
2186 |
+
'spl' => 'application/x-futuresplash',
|
2187 |
+
'src' => 'application/x-wais-source',
|
2188 |
+
'sv4cpio' => 'application/x-sv4cpio',
|
2189 |
+
'sv4crc' => 'application/x-sv4crc',
|
2190 |
+
'svg' => 'image/svg+xml',
|
2191 |
+
'swf' => 'application/x-shockwave-flash',
|
2192 |
+
't' => 'application/x-troff',
|
2193 |
+
'tcl' => 'application/x-tcl',
|
2194 |
+
'tex' => 'application/x-tex',
|
2195 |
+
'texi' => 'application/x-texinfo',
|
2196 |
+
'texinfo' => 'application/x-texinfo',
|
2197 |
+
'tif' => 'image/tiff',
|
2198 |
+
'tiff' => 'image/tiff',
|
2199 |
+
'tr' => 'application/x-troff',
|
2200 |
+
'tsv' => 'text/tab-separated-values',
|
2201 |
+
'txt' => 'text/plain',
|
2202 |
+
'ustar' => 'application/x-ustar',
|
2203 |
+
'vcd' => 'application/x-cdlink',
|
2204 |
+
'vrml' => 'model/vrml',
|
2205 |
+
'vxml' => 'application/voicexml+xml',
|
2206 |
+
'wav' => 'audio/x-wav',
|
2207 |
+
'wbmp' => 'image/vnd.wap.wbmp',
|
2208 |
+
'wbxml' => 'application/vnd.wap.wbxml',
|
2209 |
+
'webm' => 'video/webm',
|
2210 |
+
'wml' => 'text/vnd.wap.wml',
|
2211 |
+
'wmlc' => 'application/vnd.wap.wmlc',
|
2212 |
+
'wmls' => 'text/vnd.wap.wmlscript',
|
2213 |
+
'wmlsc' => 'application/vnd.wap.wmlscriptc',
|
2214 |
+
'wmv' => 'video/x-ms-wmv',
|
2215 |
+
'wrl' => 'model/vrml',
|
2216 |
+
'xbm' => 'image/x-xbitmap',
|
2217 |
+
'xht' => 'application/xhtml+xml',
|
2218 |
+
'xhtml' => 'application/xhtml+xml',
|
2219 |
+
'xls' => 'application/vnd.ms-excel',
|
2220 |
+
'xml' => 'application/xml',
|
2221 |
+
'xpm' => 'image/x-xpixmap',
|
2222 |
+
'xsl' => 'application/xml',
|
2223 |
+
'xslt' => 'application/xslt+xml',
|
2224 |
+
'xul' => 'application/vnd.mozilla.xul+xml',
|
2225 |
+
'xwd' => 'image/x-xwindowdump',
|
2226 |
+
'xyz' => 'chemical/x-xyz',
|
2227 |
+
);
|
2228 |
+
|
2229 |
+
$filesuffix = pathinfo( $file, PATHINFO_EXTENSION );
|
2230 |
+
$suffix = strtolower( $filesuffix );
|
2231 |
+
if ( isset( $mime_types[ $suffix ] ) ) {
|
2232 |
+
return $mime_types[ $suffix ];
|
2233 |
+
}
|
2234 |
+
|
2235 |
+
if ( ! is_readable( $file ) ) {
|
2236 |
+
return 'application/octet-stream';
|
2237 |
+
}
|
2238 |
+
|
2239 |
+
if ( function_exists( 'fileinfo' ) ) {
|
2240 |
+
$finfo = finfo_open( FILEINFO_MIME_TYPE );
|
2241 |
+
$mime = finfo_file( $finfo, $file );
|
2242 |
+
}
|
2243 |
+
|
2244 |
+
if ( empty( $mime ) && function_exists( 'mime_content_type' ) ) {
|
2245 |
+
$mime = mime_content_type( $file );
|
2246 |
+
}
|
2247 |
+
|
2248 |
+
if ( ! empty( $mime ) ) {
|
2249 |
+
return $mime;
|
2250 |
+
}
|
2251 |
+
|
2252 |
+
return 'application/octet-stream';
|
2253 |
+
}
|
2254 |
+
|
2255 |
+
/**
|
2256 |
+
* Check whether exec has been disabled.
|
2257 |
+
*
|
2258 |
+
* @access public
|
2259 |
+
* @static
|
2260 |
+
* @return bool
|
2261 |
+
*/
|
2262 |
+
public static function is_exec() {
|
2263 |
+
|
2264 |
+
// Is function avail
|
2265 |
+
if ( ! function_exists( 'exec' ) ) {
|
2266 |
+
return false;
|
2267 |
+
}
|
2268 |
+
|
2269 |
+
// Is shell_exec disabled?
|
2270 |
+
if ( in_array( 'exec', array_map( 'trim', explode( ',', @ini_get( 'disable_functions' ) ) ), true ) ) {
|
2271 |
+
return false;
|
2272 |
+
}
|
2273 |
+
|
2274 |
+
// Can we issue a simple echo command?
|
2275 |
+
$output = exec( 'echo backwpupechotest' );
|
2276 |
+
if ( $output != 'backwpupechotest' ) {
|
2277 |
+
return false;
|
2278 |
+
}
|
2279 |
+
|
2280 |
+
return true;
|
2281 |
+
|
2282 |
+
}
|
2283 |
+
|
2284 |
+
/**
|
2285 |
+
* Delete some data on cloned objects
|
2286 |
+
*/
|
2287 |
+
public function __clone() {
|
2288 |
+
|
2289 |
+
$this->temp = array();
|
2290 |
+
$this->run = array();
|
2291 |
+
}
|
2292 |
+
|
2293 |
+
/**
|
2294 |
+
* Signal handler
|
2295 |
+
* @param $signal_send
|
2296 |
+
*/
|
2297 |
+
public function signal_handler( $signal_send ) {
|
2298 |
+
|
2299 |
+
//known signals
|
2300 |
+
$signals = array(
|
2301 |
+
'SIGHUP' => array(
|
2302 |
+
'description' => _x( 'Hangup detected on controlling terminal or death of controlling process', 'SIGHUP: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2303 |
+
'error' => E_USER_ERROR
|
2304 |
+
),
|
2305 |
+
'SIGINT' => array(
|
2306 |
+
'description' => _x( 'Interrupt from keyboard', 'SIGINT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2307 |
+
'error' => E_USER_ERROR
|
2308 |
+
),
|
2309 |
+
'SIGQUIT' => array(
|
2310 |
+
'description' => _x( 'Quit from keyboard', 'SIGQUIT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2311 |
+
'error' => E_USER_ERROR
|
2312 |
+
),
|
2313 |
+
'SIGILL' => array(
|
2314 |
+
'description' => _x( 'Illegal Instruction', 'SIGILL: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2315 |
+
'error' => E_USER_ERROR
|
2316 |
+
),
|
2317 |
+
'SIGABRT' => array(
|
2318 |
+
'description' => _x( 'Abort signal from abort(3)', 'SIGABRT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2319 |
+
'error' => E_USER_NOTICE
|
2320 |
+
),
|
2321 |
+
'SIGBUS' => array(
|
2322 |
+
'description' => _x( 'Bus error (bad memory access)', 'SIGBUS: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2323 |
+
'error' => E_USER_ERROR
|
2324 |
+
),
|
2325 |
+
'SIGFPE' => array(
|
2326 |
+
'description' => _x( 'Floating point exception', 'SIGFPE: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2327 |
+
'error' => E_USER_ERROR
|
2328 |
+
),
|
2329 |
+
'SIGSEGV' => array(
|
2330 |
+
'description' => _x( 'Invalid memory reference', 'SIGSEGV: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2331 |
+
'error' => E_USER_ERROR
|
2332 |
+
),
|
2333 |
+
'SIGTERM' => array(
|
2334 |
+
'description' => _x( 'Termination signal', 'SIGTERM: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2335 |
+
'error' => E_USER_WARNING
|
2336 |
+
),
|
2337 |
+
'SIGSTKFLT' => array(
|
2338 |
+
'description' => _x( 'Stack fault on coprocessor', 'SIGSTKFLT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2339 |
+
'error' => E_USER_ERROR
|
2340 |
+
),
|
2341 |
+
'SIGUSR1' => array(
|
2342 |
+
'description' => _x( 'User-defined signal 1', 'SIGUSR1: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2343 |
+
'error' => E_USER_NOTICE
|
2344 |
+
),
|
2345 |
+
'SIGUSR2' => array(
|
2346 |
+
'description' => _x( 'User-defined signal 2', 'SIGUSR2: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2347 |
+
'error' => E_USER_NOTICE
|
2348 |
+
),
|
2349 |
+
'SIGURG' => array(
|
2350 |
+
'description' => _x( 'Urgent condition on socket', 'SIGURG: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2351 |
+
'error' => E_USER_NOTICE
|
2352 |
+
),
|
2353 |
+
'SIGXCPU' => array(
|
2354 |
+
'description' => _x( 'CPU time limit exceeded', 'SIGXCPU: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2355 |
+
'error' => E_USER_ERROR
|
2356 |
+
),
|
2357 |
+
'SIGXFSZ' => array(
|
2358 |
+
'description' => _x( 'File size limit exceeded', 'SIGXFSZ: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2359 |
+
'error' => E_USER_ERROR
|
2360 |
+
),
|
2361 |
+
'SIGPWR' => array(
|
2362 |
+
'description' => _x( 'Power failure', 'SIGPWR: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2363 |
+
'error' => E_USER_ERROR
|
2364 |
+
),
|
2365 |
+
'SIGSYS' => array(
|
2366 |
+
'description' => _x( 'Bad argument to routine', 'SIGSYS: Please see http://man7.org/linux/man-pages/man7/signal.7.html for details', 'backwpup' ),
|
2367 |
+
'error' => E_USER_ERROR
|
2368 |
+
),
|
2369 |
+
);
|
2370 |
+
|
2371 |
+
foreach ( $signals as $signal => $config ) {
|
2372 |
+
if ( defined( $signal ) && $signal_send === constant( $signal ) ) {
|
2373 |
+
$this->log( sprintf( __( 'Signal "%1$s" (%2$s) is sent to script!', 'backwpup' ), $signal, $config['description'] ), $config['error'] );
|
2374 |
+
$this->signal = $signal_send;
|
2375 |
+
break;
|
2376 |
+
}
|
2377 |
+
}
|
2378 |
+
|
2379 |
+
}
|
2380 |
+
|
2381 |
+
/**
|
2382 |
+
*
|
2383 |
+
* Shutdown function is call if script terminates try to make a restart if needed
|
2384 |
+
*
|
2385 |
+
* Prepare the job for start
|
2386 |
+
*
|
2387 |
+
* @internal param int the signal that terminates the job
|
2388 |
+
*/
|
2389 |
+
public function shutdown() {
|
2390 |
+
|
2391 |
+
//Put last error to log if one
|
2392 |
+
$lasterror = error_get_last();
|
2393 |
+
if ( $lasterror['type'] === E_ERROR || $lasterror['type'] === E_PARSE || $lasterror['type'] === E_CORE_ERROR || $lasterror['type'] === E_CORE_WARNING || $lasterror['type'] === E_COMPILE_ERROR || $lasterror['type'] === E_COMPILE_WARNING ) {
|
2394 |
+
$this->log( $lasterror['type'], $lasterror['message'], $lasterror['file'], $lasterror['line'] );
|
2395 |
+
}
|
2396 |
+
|
2397 |
+
$error = false;
|
2398 |
+
if ( function_exists( 'pcntl_get_last_error' ) ) {
|
2399 |
+
$error = pcntl_get_last_error();
|
2400 |
+
if ( ! empty( $error ) ) {
|
2401 |
+
$error_msg = pcntl_strerror( $error );
|
2402 |
+
if ( ! empty( $error_msg ) ) {
|
2403 |
+
$error = '(' . $error . ') ' . $error_msg;
|
2404 |
+
}
|
2405 |
+
}
|
2406 |
+
if ( ! empty( $error ) ) {
|
2407 |
+
$this->log( sprintf( __( 'System: %s', 'backwpup' ), $error ), E_USER_ERROR );
|
2408 |
+
}
|
2409 |
+
}
|
2410 |
+
|
2411 |
+
if ( function_exists( 'posix_get_last_error' ) && ! $error ) {
|
2412 |
+
$error = posix_get_last_error();
|
2413 |
+
if ( ! empty( $error ) ) {
|
2414 |
+
$error_msg = posix_strerror( $error );
|
2415 |
+
if ( ! empty( $error_msg ) ) {
|
2416 |
+
$error = '(' . $error . ') ' . $error_msg;
|
2417 |
+
}
|
2418 |
+
}
|
2419 |
+
if ( ! empty( $error ) ) {
|
2420 |
+
$this->log( sprintf( __( 'System: %s', 'backwpup' ), $error ), E_USER_ERROR );
|
2421 |
+
}
|
2422 |
+
}
|
2423 |
+
|
2424 |
+
$this->do_restart( true );
|
2425 |
+
}
|
2426 |
+
|
2427 |
+
/**
|
2428 |
+
*
|
2429 |
+
* The uncouth exception handler
|
2430 |
+
*
|
2431 |
+
* @param object $exception
|
2432 |
+
*/
|
2433 |
+
public function exception_handler( $exception ) {
|
2434 |
+
|
2435 |
+
$this->log( sprintf( __( 'Exception caught in %1$s: %2$s', 'backwpup' ), get_class( $exception ), $exception->getMessage() ), E_USER_ERROR, $exception->getFile(), $exception->getLine() );
|
2436 |
+
}
|
2437 |
+
|
2438 |
+
/**
|
2439 |
+
*
|
2440 |
+
* Callback for the CURLOPT_READFUNCTION that submit the transferred bytes
|
2441 |
+
* to build the process bar
|
2442 |
+
*
|
2443 |
+
* @param $curl_handle
|
2444 |
+
* @param $file_handle
|
2445 |
+
* @param $read_count
|
2446 |
+
*
|
2447 |
+
* @return string
|
2448 |
+
* @internal param $out
|
2449 |
+
*/
|
2450 |
+
public function curl_read_callback( $curl_handle, $file_handle, $read_count ) {
|
2451 |
+
|
2452 |
+
$data = null;
|
2453 |
+
if ( ! empty( $file_handle ) && is_numeric( $read_count ) ) {
|
2454 |
+
$data = fread( $file_handle, $read_count );
|
2455 |
+
}
|
2456 |
+
|
2457 |
+
if ( $this->job['backuptype'] == 'sync' ) {
|
2458 |
+
return $data;
|
2459 |
+
}
|
2460 |
+
|
2461 |
+
$length = ( is_numeric( $read_count ) ) ? $read_count : strlen( $read_count );
|
2462 |
+
$this->substeps_done = $this->substeps_done + $length;
|
2463 |
+
$this->update_working_data();
|
2464 |
+
|
2465 |
+
return $data;
|
2466 |
+
}
|
2467 |
+
|
2468 |
+
/**
|
2469 |
+
* @param $file
|
2470 |
+
*
|
2471 |
+
* @return bool
|
2472 |
+
*/
|
2473 |
+
public function is_backup_archive( $file ) {
|
2474 |
+
|
2475 |
+
$extensions = array(
|
2476 |
+
'.tar.gz',
|
2477 |
+
'.tar.bz2',
|
2478 |
+
'.tar',
|
2479 |
+
'.zip'
|
2480 |
+
);
|
2481 |
+
|
2482 |
+
$file = trim( basename( $file ) );
|
2483 |
+
$filename = '';
|
2484 |
+
|
2485 |
+
foreach ( $extensions as $extension ) {
|
2486 |
+
if ( substr( $file, ( strlen( $extension ) * - 1 ) ) === $extension ) {
|
2487 |
+
$filename = substr( $file, 0, ( strlen( $extension ) * - 1 ) );
|
2488 |
+
}
|
2489 |
+
}
|
2490 |
+
|
2491 |
+
if ( ! $filename ) {
|
2492 |
+
return false;
|
2493 |
+
}
|
2494 |
+
|
2495 |
+
$datevars = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
|
2496 |
+
$dateregex = array(
|
2497 |
+
'(0[1-9]|[12][0-9]|3[01])',
|
2498 |
+
'([1-9]|[12][0-9]|3[01])',
|
2499 |
+
'(0[1-9]|1[012])',
|
2500 |
+
'([1-9]|1[012])',
|
2501 |
+
'((19|20|21)[0-9]{2})',
|
2502 |
+
'([0-9]{2})',
|
2503 |
+
'(am|pm)',
|
2504 |
+
'(AM|PM)',
|
2505 |
+
'([0-9]{3})',
|
2506 |
+
'([1-9]|1[012])',
|
2507 |
+
'([0-9]|1[0-9]|2[0-3])',
|
2508 |
+
'(0[1-9]|1[012])',
|
2509 |
+
'([01][0-9]|2[0-3])',
|
2510 |
+
'([0-5][0-9])',
|
2511 |
+
'([0-5][0-9])'
|
2512 |
+
);
|
2513 |
+
|
2514 |
+
$regex = "/^" . str_replace( $datevars, $dateregex, preg_quote( self::sanitize_file_name( $this->job['archivename'] ) ) ) . "$/i";
|
2515 |
+
|
2516 |
+
preg_match( $regex, $filename, $matches );
|
2517 |
+
if ( ! empty( $matches[0] ) && $matches[0] === $filename ) {
|
2518 |
+
return true;
|
2519 |
+
}
|
2520 |
+
|
2521 |
+
return false;
|
2522 |
+
}
|
2523 |
+
|
2524 |
+
/**
|
2525 |
+
* For storing and getting data in/from a extra temp file
|
2526 |
+
*
|
2527 |
+
* @param string $storage The name of the storage
|
2528 |
+
* @param array $data data to save in storage
|
2529 |
+
*
|
2530 |
+
* @return array|mixed|null data from storage
|
2531 |
+
*/
|
2532 |
+
public function data_storage( $storage = null, $data = null ) {
|
2533 |
+
|
2534 |
+
if ( empty( $storage ) ) {
|
2535 |
+
return $data;
|
2536 |
+
}
|
2537 |
+
|
2538 |
+
$storage = strtolower( $storage );
|
2539 |
+
|
2540 |
+
$file = BackWPup::get_plugin_data( 'temp' ) . 'backwpup-' . BackWPup::get_plugin_data( 'hash' ) . '-' . $storage . '.json';
|
2541 |
+
|
2542 |
+
if ( ! empty( $data ) ) {
|
2543 |
+
file_put_contents( $file, json_encode( $data ) );
|
2544 |
+
} elseif ( is_readable( $file ) ) {
|
2545 |
+
$json = file_get_contents( $file );
|
2546 |
+
$data = json_decode( $json, true );
|
2547 |
+
}
|
2548 |
+
|
2549 |
+
return $data;
|
2550 |
+
}
|
2551 |
+
|
2552 |
+
/**
|
2553 |
+
* Add a Folders to Folder list that should be backup
|
2554 |
+
*
|
2555 |
+
* @param array $folders folder to add
|
2556 |
+
* @param bool $new overwrite existing file
|
2557 |
+
*/
|
2558 |
+
public function add_folders_to_backup( $folders = array(), $new = false ) {
|
2559 |
+
|
2560 |
+
if ( ! is_array( $folders ) ) {
|
2561 |
+
$folders = (array) $folders;
|
2562 |
+
}
|
2563 |
+
|
2564 |
+
$file = BackWPup::get_plugin_data( 'temp' ) . 'backwpup-' . BackWPup::get_plugin_data( 'hash' ) . '-folder.php';
|
2565 |
+
|
2566 |
+
if ( ! file_exists( $file ) || $new ) {
|
2567 |
+
file_put_contents( $file, '<?php' . PHP_EOL );
|
2568 |
+
}
|
2569 |
+
|
2570 |
+
$content = '';
|
2571 |
+
foreach ( $folders AS $folder ) {
|
2572 |
+
$content .= '//' . $folder . PHP_EOL;
|
2573 |
+
}
|
2574 |
+
|
2575 |
+
if ( $content ) {
|
2576 |
+
file_put_contents( $file, $content, FILE_APPEND );
|
2577 |
+
}
|
2578 |
+
}
|
2579 |
+
|
2580 |
+
}
|
inc/class-jobtype-file.php
CHANGED
@@ -63,7 +63,7 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
63 |
|
64 |
@set_time_limit( 300 );
|
65 |
$abs_folder_up = BackWPup_Option::get( $main, 'backupabsfolderup' );
|
66 |
-
$abs_path = realpath( ABSPATH );
|
67 |
if ( $abs_folder_up ) {
|
68 |
$abs_path = dirname( $abs_path );
|
69 |
}
|
@@ -75,185 +75,40 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
75 |
<th scope="row"><label for="idbackuproot"><?php esc_html_e( 'Backup WordPress install folder', 'backwpup' ); ?></label></th>
|
76 |
<td>
|
77 |
<?php
|
78 |
-
$
|
79 |
-
if ( $folder ) {
|
80 |
-
$folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
|
81 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder, FALSE ), 2 ) . ')' : '';
|
82 |
-
}
|
83 |
?>
|
84 |
-
<input class="checkbox"
|
85 |
-
type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backuproot' ), TRUE, TRUE );?>
|
86 |
-
name="backuproot" id="idbackuproot" value="1" /> <code title="<?php echo esc_attr(sprintf( __( 'Path as set by user (symlink?): %s', 'backwpup' ), $abs_path )); ?>"><?php echo esc_attr( $folder ); ?></code><?php echo esc_html( $folder_size ); ?>
|
87 |
-
|
88 |
-
<fieldset id="backuprootexcludedirs" style="padding-left:15px; margin:2px;">
|
89 |
-
<legend><strong><?php esc_html_e( 'Exclude:', 'backwpup' ); ?></strong></legend>
|
90 |
-
<?php
|
91 |
-
if ( $folder && $dir = opendir( $folder ) ) {
|
92 |
-
while ( ( $file = readdir( $dir ) ) !== FALSE ) {
|
93 |
-
$excludes = BackWPup_Option::get( $main, 'backuprootexcludedirs' );
|
94 |
-
if ( ! in_array( $file, array( '.', '..' ), true ) && is_dir( $folder . '/' . $file ) && ! in_array( trailingslashit( $folder . '/' . $file ), $this->get_exclude_dirs( $folder ), true ) ) {
|
95 |
-
$donotbackup = file_exists( $folder . '/' . $file . '/.donotbackup' );
|
96 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder . '/' . $file ), 2 ) . ')' : '';
|
97 |
-
$title = '';
|
98 |
-
if ( $donotbackup ) {
|
99 |
-
$excludes[] = $file;
|
100 |
-
$title = ' title="' . esc_attr__( 'Excluded by .donotbackup file!', 'backwpup' ) . '"';
|
101 |
-
}
|
102 |
-
echo '<nobr><label for="idrootexcludedirs-'.sanitize_file_name( $file ).'"><input class="checkbox" type="checkbox"' . checked( in_array( $file, $excludes, true ), TRUE, FALSE ) . ' name="backuprootexcludedirs[]" id="idrootexcludedirs-' . sanitize_file_name( $file ) . '" value="' . esc_attr( $file ) . '"' . disabled( $donotbackup, TRUE, FALSE ) . $title . ' /> ' . esc_html( $file ) . esc_html( $folder_size ) . '</label><br /></nobr>';
|
103 |
-
}
|
104 |
-
}
|
105 |
-
closedir( $dir );
|
106 |
-
}
|
107 |
-
?>
|
108 |
-
</fieldset>
|
109 |
</td>
|
110 |
</tr>
|
111 |
<tr>
|
112 |
<th scope="row"><label for="idbackupcontent"><?php esc_html_e( 'Backup content folder', 'backwpup' ); ?></label></th>
|
113 |
<td>
|
114 |
<?php
|
115 |
-
$
|
116 |
-
if ( $folder ) {
|
117 |
-
$folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
|
118 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder, FALSE ), 2 ) . ')' : '';
|
119 |
-
}
|
120 |
?>
|
121 |
-
<input class="checkbox"
|
122 |
-
type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupcontent' ), TRUE, TRUE );?>
|
123 |
-
name="backupcontent" id="idbackupcontent" value="1" /> <code title="<?php echo esc_attr(sprintf( __( 'Path as set by user (symlink?): %s', 'backwpup' ), WP_CONTENT_DIR )); ?>"><?php echo esc_html( $folder ); ?></code><?php echo esc_html($folder_size); ?>
|
124 |
-
|
125 |
-
<fieldset id="backupcontentexcludedirs" style="padding-left:15px; margin:2px;">
|
126 |
-
<legend><strong><?php esc_html_e( 'Exclude:', 'backwpup' ); ?></strong></legend>
|
127 |
-
<?php
|
128 |
-
if ( $folder && $dir = opendir( $folder ) ) {
|
129 |
-
$excludes = BackWPup_Option::get( $main, 'backupcontentexcludedirs' );
|
130 |
-
while ( ( $file = readdir( $dir ) ) !== FALSE ) {
|
131 |
-
if ( ! in_array( $file, array( '.', '..' ), true ) && is_dir( $folder . '/' . $file ) && ! in_array( trailingslashit( $folder . '/' . $file ), $this->get_exclude_dirs( $folder ), true ) ) {
|
132 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder . '/' . $file ), 2 ) . ')' : '';
|
133 |
-
$donotbackup = file_exists( $folder . '/' . $file . '/.donotbackup' );
|
134 |
-
$title = '';
|
135 |
-
if ( $donotbackup ) {
|
136 |
-
$excludes[] = $file;
|
137 |
-
$title = ' title="' . esc_attr__( 'Excluded by .donotbackup file!', 'backwpup' ) . '"';
|
138 |
-
}
|
139 |
-
echo '<nobr><label for="idcontentexcludedirs-'.sanitize_file_name( $file ).'"><input class="checkbox" type="checkbox"' . checked( in_array( $file, $excludes, true ), TRUE, FALSE ) . ' name="backupcontentexcludedirs[]" id="idcontentexcludedirs-'.sanitize_file_name( $file ).'" value="' . esc_attr($file) . '"' . disabled( $donotbackup, TRUE, FALSE ) . $title . ' /> ' . esc_html( $file ) . esc_html($folder_size) . '</label><br /></nobr>';
|
140 |
-
}
|
141 |
-
}
|
142 |
-
closedir( $dir );
|
143 |
-
}
|
144 |
-
?>
|
145 |
-
</fieldset>
|
146 |
</td>
|
147 |
</tr>
|
148 |
<tr>
|
149 |
<th scope="row"><label for="idbackupplugins"><?php _e( 'Backup plugins', 'backwpup' ); ?></label></th>
|
150 |
<td>
|
151 |
<?php
|
152 |
-
$
|
153 |
-
if ( $folder ) {
|
154 |
-
$folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
|
155 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder, FALSE ), 2 ) . ')' : '';
|
156 |
-
}
|
157 |
?>
|
158 |
-
<input class="checkbox"
|
159 |
-
type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupplugins' ), TRUE, TRUE );?>
|
160 |
-
name="backupplugins" id="idbackupplugins" value="1" /> <code title="<?php echo sprintf( __( 'Path as set by user (symlink?): %s', 'backwpup' ), esc_attr( WP_PLUGIN_DIR ) ); ?>"><?php echo esc_attr( $folder ); ?></code><?php echo $folder_size; ?>
|
161 |
-
|
162 |
-
<fieldset id="backuppluginsexcludedirs" style="padding-left:15px; margin:2px;">
|
163 |
-
<legend><strong><?php _e( 'Exclude:', 'backwpup' ); ?></strong></legend>
|
164 |
-
<?php
|
165 |
-
if ( $folder && $dir = opendir( $folder ) ) {
|
166 |
-
$excludes = BackWPup_Option::get( $main, 'backuppluginsexcludedirs' );
|
167 |
-
while ( ( $file = readdir( $dir ) ) !== FALSE ) {
|
168 |
-
if ( ! in_array( $file, array( '.', '..' ), true ) && is_dir( $folder . '/' . $file ) && ! in_array( trailingslashit( $folder . '/' . $file ), $this->get_exclude_dirs( $folder ), true ) ) {
|
169 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder . '/' . $file ), 2 ) . ')' : '';
|
170 |
-
$donotbackup = file_exists( $folder . '/' . $file . '/.donotbackup' );
|
171 |
-
$title = '';
|
172 |
-
if ( $donotbackup ) {
|
173 |
-
$excludes[] = $file;
|
174 |
-
$title = ' title="' . esc_attr__( 'Excluded by .donotbackup file!', 'backwpup' ) . '"';
|
175 |
-
}
|
176 |
-
echo '<nobr><label for="idpluginexcludedirs-'.sanitize_file_name( $file ).'"><input class="checkbox" type="checkbox"' . checked( in_array( $file, $excludes, true ), TRUE, FALSE ) . ' name="backuppluginsexcludedirs[]" id="idpluginexcludedirs-'.sanitize_file_name( $file ).'" value="' . esc_attr($file) . '"' . disabled( $donotbackup, TRUE, FALSE ) . $title . ' /> ' . esc_html( $file ) . esc_html($folder_size) . '</label><br /></nobr>';
|
177 |
-
}
|
178 |
-
}
|
179 |
-
closedir( $dir );
|
180 |
-
}
|
181 |
-
?>
|
182 |
-
</fieldset>
|
183 |
</td>
|
184 |
</tr>
|
185 |
<tr>
|
186 |
<th scope="row"><label for="idbackupthemes"><?php esc_html_e( 'Backup themes', 'backwpup' ); ?></label></th>
|
187 |
<td>
|
188 |
<?php
|
189 |
-
$
|
190 |
-
if ( $folder ) {
|
191 |
-
$folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
|
192 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder, FALSE ), 2 ) . ')' : '';
|
193 |
-
}
|
194 |
?>
|
195 |
-
<input class="checkbox"
|
196 |
-
type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupthemes' ), TRUE, TRUE );?>
|
197 |
-
name="backupthemes" id="idbackupthemes" value="1" /> <code title="<?php echo sprintf( __( 'Path as set by user (symlink?): %s', 'backwpup' ), esc_attr( get_theme_root() ) ); ?>"><?php echo esc_attr( $folder ); ?></code><?php echo $folder_size; ?>
|
198 |
-
|
199 |
-
<fieldset id="backupthemesexcludedirs" style="padding-left:15px; margin:2px;">
|
200 |
-
<legend><strong><?php _e( 'Exclude:', 'backwpup' ); ?></strong></legend>
|
201 |
-
<?php
|
202 |
-
if ( $folder && $dir = opendir( $folder ) ) {
|
203 |
-
$excludes = BackWPup_Option::get( $main, 'backupthemesexcludedirs' );
|
204 |
-
while ( ( $file = readdir( $dir ) ) !== FALSE ) {
|
205 |
-
if ( ! in_array( $file, array( '.', '..' ), true ) && is_dir( $folder . '/' . $file ) && ! in_array( trailingslashit( $folder . '/' . $file ), $this->get_exclude_dirs( $folder ), true ) ) {
|
206 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder . '/' . $file ), 2 ) . ')' : '';
|
207 |
-
$donotbackup = file_exists( $folder . '/' . $file . '/.donotbackup' );
|
208 |
-
$title = '';
|
209 |
-
if ( $donotbackup ) {
|
210 |
-
$excludes[] = $file;
|
211 |
-
$title = ' title="' . esc_attr__( 'Excluded by .donotbackup file!', 'backwpup' ) . '"';
|
212 |
-
}
|
213 |
-
echo '<nobr><label for="idthemesexcludedirs-'.sanitize_file_name( $file ).'"><input class="checkbox" type="checkbox"' . checked( in_array( $file, $excludes, true ), TRUE, FALSE ) . ' name="backupthemesexcludedirs[]" id="idthemesexcludedirs-'.sanitize_file_name( $file ).'" value="' . $file . '"' . disabled( $donotbackup, TRUE, FALSE ) . $title . ' /> ' . esc_attr( $file ) . $folder_size . '</label><br /></nobr>';
|
214 |
-
}
|
215 |
-
}
|
216 |
-
closedir( $dir );
|
217 |
-
}
|
218 |
-
?>
|
219 |
-
</fieldset>
|
220 |
</td>
|
221 |
</tr>
|
222 |
<tr>
|
223 |
<th scope="row"><label for="idbackupuploads"><?php esc_html_e( 'Backup uploads folder', 'backwpup' ); ?></label></th>
|
224 |
<td>
|
225 |
<?php
|
226 |
-
$
|
227 |
-
if ( $folder ) {
|
228 |
-
$folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
|
229 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder, FALSE ), 2 ) . ')' : '';
|
230 |
-
}
|
231 |
?>
|
232 |
-
<input class="checkbox"
|
233 |
-
type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupuploads' ), TRUE, TRUE );?>
|
234 |
-
name="backupuploads" id="idbackupuploads" value="1" /> <code title="<?php echo sprintf( __( 'Path as set by user (symlink?): %s', 'backwpup' ), esc_attr( BackWPup_File::get_upload_dir() ) ); ?>"><?php echo esc_html( $folder ); ?></code><?php echo $folder_size; ?>
|
235 |
-
|
236 |
-
<fieldset id="backupuploadsexcludedirs" style="padding-left:15px; margin:2px;">
|
237 |
-
<legend><strong><?php esc_html_e( 'Exclude:', 'backwpup' ); ?></strong></legend>
|
238 |
-
<?php
|
239 |
-
if ( $folder && $dir = opendir( $folder ) ) {
|
240 |
-
$excludes = BackWPup_Option::get( $main, 'backupuploadsexcludedirs' );
|
241 |
-
while ( ( $file = readdir( $dir ) ) !== FALSE ) {
|
242 |
-
if ( ! in_array( $file, array( '.', '..' ), true ) && is_dir( $folder . '/' . $file ) && ! in_array( trailingslashit( $folder . '/' . $file ), $this->get_exclude_dirs( $folder ), true ) ) {
|
243 |
-
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder . '/' . $file ), 2 ) . ')' : '';
|
244 |
-
$donotbackup = file_exists( $folder . '/' . $file . '/.donotbackup' );
|
245 |
-
$title = '';
|
246 |
-
if ( $donotbackup ) {
|
247 |
-
$excludes[] = $file;
|
248 |
-
$title = ' title="' . esc_attr__( 'Excluded by .donotbackup file!', 'backwpup' ) . '"';
|
249 |
-
}
|
250 |
-
echo '<nobr><label for="iduploadexcludedirs-'.sanitize_file_name( $file ).'"><input class="checkbox" type="checkbox"' . checked( in_array( $file, $excludes, true ), TRUE, FALSE ) . ' name="backupuploadsexcludedirs[]" id="iduploadexcludedirs-'.sanitize_file_name( $file ).'" value="' . esc_attr($file) . '"' . disabled( $donotbackup, TRUE, FALSE ) . $title . ' /> ' . esc_html( $file ) . esc_html($folder_size) . '</label><br /></nobr>';
|
251 |
-
}
|
252 |
-
}
|
253 |
-
closedir( $dir );
|
254 |
-
}
|
255 |
-
?>
|
256 |
-
</fieldset>
|
257 |
</td>
|
258 |
</tr>
|
259 |
<tr>
|
@@ -289,7 +144,7 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
289 |
<tr>
|
290 |
<th scope="row"><?php esc_html_e( 'Include special files', 'backwpup' ); ?></th>
|
291 |
<td>
|
292 |
-
<label for="idbackupspecialfiles"><input class="checkbox" id="idbackupspecialfiles" type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupspecialfiles' ), TRUE, TRUE ); ?> name="backupspecialfiles" value="1" /> <?php esc_html_e( 'Backup wp-config.php, robots.txt, nginx.conf, .htaccess, .htpasswd
|
293 |
</td>
|
294 |
</tr>
|
295 |
<tr>
|
@@ -309,69 +164,67 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
309 |
*/
|
310 |
public function edit_form_post_save( $id ) {
|
311 |
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
|
|
|
|
319 |
}
|
320 |
-
sort( $
|
321 |
-
BackWPup_Option::update( $id, 'fileexclude', implode( ',', $
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
|
|
|
|
|
|
|
|
|
|
329 |
}
|
330 |
-
sort( $
|
331 |
-
BackWPup_Option::update( $id, 'dirinclude', implode( ',', $
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
sort( $_POST[ 'backupcontentexcludedirs' ] );
|
350 |
-
BackWPup_Option::update( $id, 'backupcontentexcludedirs', $_POST[ 'backupcontentexcludedirs' ] );
|
351 |
-
|
352 |
-
BackWPup_Option::update( $id, 'backupplugins', ! empty( $_POST[ 'backupplugins' ] ) );
|
353 |
-
|
354 |
-
if ( ! isset( $_POST[ 'backuppluginsexcludedirs' ] ) || ! is_array( $_POST[ 'backuppluginsexcludedirs' ] ) ) {
|
355 |
-
$_POST[ 'backuppluginsexcludedirs' ] = array();
|
356 |
-
}
|
357 |
-
sort( $_POST[ 'backuppluginsexcludedirs' ] );
|
358 |
-
BackWPup_Option::update( $id, 'backuppluginsexcludedirs', $_POST[ 'backuppluginsexcludedirs' ] );
|
359 |
-
|
360 |
-
BackWPup_Option::update( $id, 'backupthemes', ! empty( $_POST[ 'backupthemes' ] ) );
|
361 |
-
|
362 |
-
if ( ! isset( $_POST[ 'backupthemesexcludedirs' ] ) || ! is_array( $_POST[ 'backupthemesexcludedirs' ] ) ) {
|
363 |
-
$_POST[ 'backupthemesexcludedirs' ] = array();
|
364 |
}
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
}
|
373 |
-
|
374 |
-
BackWPup_Option::update( $id, 'backupuploadsexcludedirs', $_POST[ 'backupuploadsexcludedirs' ] );
|
375 |
}
|
376 |
|
377 |
/**
|
@@ -385,7 +238,7 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
385 |
}
|
386 |
$job_object->substeps_todo = 8;
|
387 |
|
388 |
-
$abs_path = realpath( ABSPATH );
|
389 |
if ( $job_object->job['backupabsfolderup'] ) {
|
390 |
$abs_path = dirname( $abs_path );
|
391 |
}
|
@@ -497,6 +350,8 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
497 |
|
498 |
//add extra files if selected
|
499 |
if ( ! empty( $job_object->job['backupspecialfiles'] ) ) {
|
|
|
|
|
500 |
if ( is_readable( ABSPATH . 'wp-config.php' ) ) {
|
501 |
$job_object->additional_files_to_backup[] = str_replace( '\\', '/', ABSPATH . 'wp-config.php' );
|
502 |
$job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), 'wp-config.php' ) );
|
@@ -506,25 +361,22 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
506 |
$job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), 'wp-config.php' ) );
|
507 |
}
|
508 |
}
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
if ( is_readable( $abs_path . 'favicon.ico' ) && empty( $job_object->job['backuproot'] ) ) {
|
526 |
-
$job_object->additional_files_to_backup[] = $abs_path . 'favicon.ico';
|
527 |
-
$job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), 'favicon.ico' ) );
|
528 |
}
|
529 |
}
|
530 |
|
@@ -555,44 +407,47 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
555 |
|
556 |
$folder = trailingslashit( $folder );
|
557 |
|
558 |
-
|
|
|
559 |
//add folder to folder list
|
560 |
$job_object->add_folders_to_backup( $folder );
|
561 |
//scan folder
|
562 |
-
|
563 |
-
if (
|
564 |
continue;
|
565 |
}
|
|
|
566 |
foreach ( $job_object->exclude_from_backup as $exclusion ) { //exclude files
|
567 |
$exclusion = trim( $exclusion );
|
568 |
-
if (
|
569 |
continue 2;
|
570 |
}
|
571 |
}
|
572 |
-
if (
|
573 |
-
if ( in_array( trailingslashit( $
|
574 |
continue;
|
575 |
}
|
576 |
-
if ( file_exists( trailingslashit( $
|
577 |
continue;
|
578 |
}
|
579 |
-
if ( !
|
580 |
-
$job_object->log( sprintf( __( 'Folder "%s" is not readable!', 'backwpup' ), $
|
581 |
continue;
|
582 |
}
|
583 |
-
$this->get_folder_list( $job_object, trailingslashit( $
|
584 |
}
|
585 |
if ( $first ) {
|
586 |
$job_object->do_restart_time();
|
587 |
}
|
588 |
}
|
589 |
-
|
|
|
|
|
590 |
}
|
591 |
|
592 |
return true;
|
593 |
}
|
594 |
|
595 |
-
|
596 |
/**
|
597 |
*
|
598 |
* Get folder to exclude from a given folder for file backups
|
@@ -605,7 +460,7 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
605 |
*/
|
606 |
private function get_exclude_dirs( $folder, $excludedir = array() ) {
|
607 |
|
608 |
-
$folder = trailingslashit( str_replace( '\\', '/', realpath( $folder ) ) );
|
609 |
|
610 |
if ( false !== strpos( trailingslashit( str_replace( '\\', '/', realpath( WP_CONTENT_DIR ) ) ), $folder ) && trailingslashit( str_replace( '\\', '/', realpath( WP_CONTENT_DIR ) ) ) != $folder ) {
|
611 |
$excludedir[] = trailingslashit( str_replace( '\\', '/', realpath( WP_CONTENT_DIR ) ) );
|
@@ -622,4 +477,52 @@ class BackWPup_JobType_File extends BackWPup_JobTypes {
|
|
622 |
|
623 |
return array_unique( $excludedir );
|
624 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
625 |
}
|
63 |
|
64 |
@set_time_limit( 300 );
|
65 |
$abs_folder_up = BackWPup_Option::get( $main, 'backupabsfolderup' );
|
66 |
+
$abs_path = realpath( BackWPup_Path_Fixer::fix_path( ABSPATH ) );
|
67 |
if ( $abs_folder_up ) {
|
68 |
$abs_path = dirname( $abs_path );
|
69 |
}
|
75 |
<th scope="row"><label for="idbackuproot"><?php esc_html_e( 'Backup WordPress install folder', 'backwpup' ); ?></label></th>
|
76 |
<td>
|
77 |
<?php
|
78 |
+
$this->show_folder( 'root', $main, $abs_path );
|
|
|
|
|
|
|
|
|
79 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
</td>
|
81 |
</tr>
|
82 |
<tr>
|
83 |
<th scope="row"><label for="idbackupcontent"><?php esc_html_e( 'Backup content folder', 'backwpup' ); ?></label></th>
|
84 |
<td>
|
85 |
<?php
|
86 |
+
$this->show_folder( 'content', $main, WP_CONTENT_DIR );
|
|
|
|
|
|
|
|
|
87 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
</td>
|
89 |
</tr>
|
90 |
<tr>
|
91 |
<th scope="row"><label for="idbackupplugins"><?php _e( 'Backup plugins', 'backwpup' ); ?></label></th>
|
92 |
<td>
|
93 |
<?php
|
94 |
+
$this->show_folder( 'plugins', $main, WP_PLUGIN_DIR );
|
|
|
|
|
|
|
|
|
95 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
</td>
|
97 |
</tr>
|
98 |
<tr>
|
99 |
<th scope="row"><label for="idbackupthemes"><?php esc_html_e( 'Backup themes', 'backwpup' ); ?></label></th>
|
100 |
<td>
|
101 |
<?php
|
102 |
+
$this->show_folder( 'themes', $main, get_theme_root() );
|
|
|
|
|
|
|
|
|
103 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
</td>
|
105 |
</tr>
|
106 |
<tr>
|
107 |
<th scope="row"><label for="idbackupuploads"><?php esc_html_e( 'Backup uploads folder', 'backwpup' ); ?></label></th>
|
108 |
<td>
|
109 |
<?php
|
110 |
+
$this->show_folder( 'uploads', $main, BackWPup_File::get_upload_dir() );
|
|
|
|
|
|
|
|
|
111 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
</td>
|
113 |
</tr>
|
114 |
<tr>
|
144 |
<tr>
|
145 |
<th scope="row"><?php esc_html_e( 'Include special files', 'backwpup' ); ?></th>
|
146 |
<td>
|
147 |
+
<label for="idbackupspecialfiles"><input class="checkbox" id="idbackupspecialfiles" type="checkbox"<?php checked( BackWPup_Option::get( $main, 'backupspecialfiles' ), TRUE, TRUE ); ?> name="backupspecialfiles" value="1" /> <?php esc_html_e( 'Backup wp-config.php, robots.txt, nginx.conf, .htaccess, .htpasswd, favicon.ico, and Web.config from root if it is not included in backup.', 'backwpup' ); ?></label>
|
148 |
</td>
|
149 |
</tr>
|
150 |
<tr>
|
164 |
*/
|
165 |
public function edit_form_post_save( $id ) {
|
166 |
|
167 |
+
// Parse and save files to exclude
|
168 |
+
$exclude_input = filter_input( INPUT_POST , 'fileexclude' );
|
169 |
+
$to_exclude_list = $exclude_input ? str_replace( array( "\r\n", "\r" ), ',', $exclude_input ) : array();
|
170 |
+
$to_exclude_list and $to_exclude_list = sanitize_text_field( stripslashes( $to_exclude_list ) );
|
171 |
+
$to_exclude = $to_exclude_list ? explode( ',', $to_exclude_list ) : array();
|
172 |
+
$to_exclude_parsed = array();
|
173 |
+
foreach ( $to_exclude as $key => $value ) {
|
174 |
+
$normalized = wp_normalize_path( trim( $value ) );
|
175 |
+
$normalized and $to_exclude_parsed[$key] = $normalized;
|
176 |
}
|
177 |
+
sort( $to_exclude_parsed );
|
178 |
+
BackWPup_Option::update( $id, 'fileexclude', implode( ',', $to_exclude_parsed ) );
|
179 |
+
unset( $exclude_input, $to_exclude_list, $to_exclude, $to_exclude_parsed, $normalized );
|
180 |
+
|
181 |
+
// Parse and save folders to include
|
182 |
+
$include_input = filter_input( INPUT_POST , 'dirinclude' );
|
183 |
+
$include_list = $include_input ? str_replace( array( "\r\n", "\r" ), ',', $include_input ) : array();
|
184 |
+
$to_include = $include_list ? explode( ',', $include_list ) : array();
|
185 |
+
$to_include_parsed = array();
|
186 |
+
foreach ( $to_include as $key => $value ) {
|
187 |
+
$normalized = trailingslashit( wp_normalize_path( trim( $value ) ) );
|
188 |
+
$normalized and $normalized = filter_var( $normalized, FILTER_SANITIZE_URL );
|
189 |
+
$realpath = $normalized && $normalized !== '/' ? realpath( $normalized ) : false;
|
190 |
+
$realpath and $to_include_parsed[$key] = $realpath;
|
191 |
}
|
192 |
+
sort( $to_include_parsed );
|
193 |
+
BackWPup_Option::update( $id, 'dirinclude', implode( ',', $to_include_parsed ) );
|
194 |
+
unset( $include_input, $include_list, $to_include, $to_include_parsed, $normalized, $realpath );
|
195 |
+
|
196 |
+
// Parse and save boolean fields
|
197 |
+
$boolean_fields_def = array(
|
198 |
+
'backupexcludethumbs' => FILTER_VALIDATE_BOOLEAN,
|
199 |
+
'backupspecialfiles' => FILTER_VALIDATE_BOOLEAN,
|
200 |
+
'backuproot' => FILTER_VALIDATE_BOOLEAN,
|
201 |
+
'backupabsfolderup' => FILTER_VALIDATE_BOOLEAN,
|
202 |
+
'backupcontent' => FILTER_VALIDATE_BOOLEAN,
|
203 |
+
'backupplugins' => FILTER_VALIDATE_BOOLEAN,
|
204 |
+
'backupthemes' => FILTER_VALIDATE_BOOLEAN,
|
205 |
+
'backupuploads' => FILTER_VALIDATE_BOOLEAN,
|
206 |
+
);
|
207 |
+
$boolean_data = filter_input_array( INPUT_POST, $boolean_fields_def );
|
208 |
+
$boolean_data or $boolean_data = array();
|
209 |
+
foreach( $boolean_fields_def as $key => $value ) {
|
210 |
+
BackWPup_Option::update( $id, $key, ! empty( $boolean_data[$key] ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
}
|
212 |
+
unset( $boolean_fields_def, $boolean_data );
|
213 |
+
|
214 |
+
// Parse and save directories to exclude
|
215 |
+
$exclude_dirs_def = array(
|
216 |
+
'backuprootexcludedirs' => array( 'filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FORCE_ARRAY ),
|
217 |
+
'backuppluginsexcludedirs' => array( 'filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FORCE_ARRAY ),
|
218 |
+
'backupthemesexcludedirs' => array( 'filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FORCE_ARRAY ),
|
219 |
+
'backupuploadsexcludedirs' => array( 'filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FORCE_ARRAY ),
|
220 |
+
);
|
221 |
+
$exclude_dirs = filter_input_array( INPUT_POST, $exclude_dirs_def );
|
222 |
+
$exclude_dirs or $exclude_dirs = array();
|
223 |
+
foreach( $exclude_dirs_def as $key => $filter ) {
|
224 |
+
$value = ! empty( $exclude_dirs[$key] ) && is_array( $exclude_dirs[$key] ) ? $exclude_dirs[$key] : array();
|
225 |
+
BackWPup_Option::update( $id, $key, $value );
|
226 |
}
|
227 |
+
unset( $exclude_dirs_def, $exclude_dirs );
|
|
|
228 |
}
|
229 |
|
230 |
/**
|
238 |
}
|
239 |
$job_object->substeps_todo = 8;
|
240 |
|
241 |
+
$abs_path = realpath( BackWPup_Path_Fixer::fix_path( ABSPATH ) );
|
242 |
if ( $job_object->job['backupabsfolderup'] ) {
|
243 |
$abs_path = dirname( $abs_path );
|
244 |
}
|
350 |
|
351 |
//add extra files if selected
|
352 |
if ( ! empty( $job_object->job['backupspecialfiles'] ) ) {
|
353 |
+
|
354 |
+
// Special handling for wp-config.php
|
355 |
if ( is_readable( ABSPATH . 'wp-config.php' ) ) {
|
356 |
$job_object->additional_files_to_backup[] = str_replace( '\\', '/', ABSPATH . 'wp-config.php' );
|
357 |
$job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), 'wp-config.php' ) );
|
361 |
$job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), 'wp-config.php' ) );
|
362 |
}
|
363 |
}
|
364 |
+
|
365 |
+
// Files to include
|
366 |
+
$special_files = array(
|
367 |
+
'.htaccess',
|
368 |
+
'nginx.conf',
|
369 |
+
'.htpasswd',
|
370 |
+
'robots.txt',
|
371 |
+
'favicon.ico',
|
372 |
+
'Web.config',
|
373 |
+
);
|
374 |
+
|
375 |
+
foreach ( $special_files as $file ) {
|
376 |
+
if ( is_readable( $abs_path . $file ) && empty( $job_object->job['backuproot'] ) ) {
|
377 |
+
$job_object->additional_files_to_backup[] = $abs_path . $file;
|
378 |
+
$job_object->log( sprintf( __( 'Added "%s" to backup file list', 'backwpup' ), $file ) );
|
379 |
+
}
|
|
|
|
|
|
|
380 |
}
|
381 |
}
|
382 |
|
407 |
|
408 |
$folder = trailingslashit( $folder );
|
409 |
|
410 |
+
try {
|
411 |
+
$dir = new BackWPup_Directory( $folder );
|
412 |
//add folder to folder list
|
413 |
$job_object->add_folders_to_backup( $folder );
|
414 |
//scan folder
|
415 |
+
foreach ( $dir as $file ) {
|
416 |
+
if ( $file->isDot() ) {
|
417 |
continue;
|
418 |
}
|
419 |
+
$path = str_replace( '\\', '/', realpath( $file->getPathname() ) );
|
420 |
foreach ( $job_object->exclude_from_backup as $exclusion ) { //exclude files
|
421 |
$exclusion = trim( $exclusion );
|
422 |
+
if ( stripos( $path, $exclusion ) !== false && ! empty( $exclusion ) ) {
|
423 |
continue 2;
|
424 |
}
|
425 |
}
|
426 |
+
if ( $file->isDir() ) {
|
427 |
+
if ( in_array( trailingslashit( $path ), $excludedirs, true ) ) {
|
428 |
continue;
|
429 |
}
|
430 |
+
if ( file_exists( trailingslashit( $file->getPathname() ) . '.donotbackup' ) ) {
|
431 |
continue;
|
432 |
}
|
433 |
+
if ( ! $file->isReadable() ) {
|
434 |
+
$job_object->log( sprintf( __( 'Folder "%s" is not readable!', 'backwpup' ), $file->getPathname() ), E_USER_WARNING );
|
435 |
continue;
|
436 |
}
|
437 |
+
$this->get_folder_list( $job_object, trailingslashit( $path ), $excludedirs, false );
|
438 |
}
|
439 |
if ( $first ) {
|
440 |
$job_object->do_restart_time();
|
441 |
}
|
442 |
}
|
443 |
+
}
|
444 |
+
catch ( UnexpectedValueException $e ) {
|
445 |
+
$job_object->log( sprintf( __( "Could not open path: %s", 'backwpup' ), $e->getMessage() ), E_USER_WARNING );
|
446 |
}
|
447 |
|
448 |
return true;
|
449 |
}
|
450 |
|
|
|
451 |
/**
|
452 |
*
|
453 |
* Get folder to exclude from a given folder for file backups
|
460 |
*/
|
461 |
private function get_exclude_dirs( $folder, $excludedir = array() ) {
|
462 |
|
463 |
+
$folder = trailingslashit( str_replace( '\\', '/', realpath( BackWPup_Path_Fixer::fix_path( $folder ) ) ) );
|
464 |
|
465 |
if ( false !== strpos( trailingslashit( str_replace( '\\', '/', realpath( WP_CONTENT_DIR ) ) ), $folder ) && trailingslashit( str_replace( '\\', '/', realpath( WP_CONTENT_DIR ) ) ) != $folder ) {
|
466 |
$excludedir[] = trailingslashit( str_replace( '\\', '/', realpath( WP_CONTENT_DIR ) ) );
|
477 |
|
478 |
return array_unique( $excludedir );
|
479 |
}
|
480 |
+
|
481 |
+
/**
|
482 |
+
* Shows a folder with the options of which files to exclude.
|
483 |
+
*
|
484 |
+
*/
|
485 |
+
private function show_folder( $id, $jobid, $path ) {
|
486 |
+
$folder = realpath( BackWPup_Path_Fixer::fix_path( $path ) );
|
487 |
+
if ( $folder ) {
|
488 |
+
$folder = untrailingslashit( str_replace( '\\', '/', $folder ) );
|
489 |
+
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize') ) ? ' (' . size_format( BackWPup_File::get_folder_size( $folder, FALSE ), 2 ) . ')' : '';
|
490 |
+
}
|
491 |
+
?>
|
492 |
+
<input class="checkbox"
|
493 |
+
type="checkbox"<?php checked( BackWPup_Option::get( $jobid, 'backup' . $id ) ) ?>
|
494 |
+
name="backup<?php echo esc_attr( $id ) ?>" id="idbackup<?php echo esc_attr( $id ) ?>" value="1" /> <code title="<?php echo esc_attr( sprintf( __( 'Path as set by user (symlink?): %s', 'backwpup' ), $path ) ) ?>"><?php echo esc_attr( $folder ) ?></code><?php echo esc_html( $folder_size ) ?>
|
495 |
+
|
496 |
+
<fieldset id="backup<?php echo esc_attr( $id ) ?>excludedirs" style="padding-left:15px; margin:2px;">
|
497 |
+
<legend><strong><?php esc_html_e( 'Exclude:', 'backwpup' ) ?></strong></legend>
|
498 |
+
<?php
|
499 |
+
try {
|
500 |
+
$dir = new BackWPup_Directory( $folder );
|
501 |
+
$excludes = BackWPup_Option::get( $jobid, 'backup' . $id . 'excludedirs' );
|
502 |
+
foreach ( $dir as $file ) {
|
503 |
+
if ( ! $file->isDot() && $file->isDir() && ! in_array( trailingslashit( $file->getPathname() ), $this->get_exclude_dirs( $folder ), true ) ) {
|
504 |
+
$donotbackup = file_exists( $file->getPathname() . '/.donotbackup' );
|
505 |
+
$folder_size = ( get_site_option( 'backwpup_cfg_showfoldersize' ) ) ? ' (' . size_format( BackWPup_File::get_folder_size( $file->getPathname() ), 2 ) . ')' : '';
|
506 |
+
$title = '';
|
507 |
+
if ( $donotbackup ) {
|
508 |
+
$excludes[] = $file->getFilename();
|
509 |
+
$title = ' title="' . esc_attr__( 'Excluded by .donotbackup file!', 'backwpup' ) . '"';
|
510 |
+
}
|
511 |
+
echo '<nobr><label for="id' . esc_attr( $id ) . 'excludedirs-' . sanitize_file_name( $file->getFilename() ) . '">' .
|
512 |
+
'<input class="checkbox" type="checkbox"' .
|
513 |
+
checked( in_array( $file->getFilename(), $excludes, true ), true, false ) . ' name="backup' . esc_attr( $id ) . 'excludedirs[]" ' .
|
514 |
+
'id="id' . esc_attr( $id ) . 'excludedirs-' . sanitize_file_name( $file->getFilename() ) . '" ' .
|
515 |
+
'value="' . esc_attr( $file->getFilename() ) . '"' . disabled( $donotbackup, true, false ) . $title . ' /> ' .
|
516 |
+
esc_html( $file->getFilename() ) . esc_html( $folder_size ) . '</label><br /></nobr>';
|
517 |
+
}
|
518 |
+
}
|
519 |
+
}
|
520 |
+
catch ( Exception $e ) {
|
521 |
+
// Do nothing, just skip
|
522 |
+
}
|
523 |
+
?>
|
524 |
+
</fieldset>
|
525 |
+
<?php
|
526 |
+
}
|
527 |
+
|
528 |
}
|
inc/class-jobtype-wpexp.php
CHANGED
@@ -117,7 +117,7 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
|
|
117 |
$job_object->substeps_done = 0;
|
118 |
}
|
119 |
|
120 |
-
add_filter( '
|
121 |
|
122 |
if ( $job_object->steps_data[ $job_object->step_working ]['substep'] == 'header' ) {
|
123 |
|
@@ -343,7 +343,7 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
|
|
343 |
|
344 |
$postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
|
345 |
foreach ( $postmeta as $meta ) {
|
346 |
-
if ( apply_filters( '
|
347 |
continue;
|
348 |
}
|
349 |
$wxr_post .= "\t\t<wp:postmeta>\n\t\t\t<wp:meta_key>" . $meta->meta_key ."</wp:meta_key>\n\t\t\t<wp:meta_value>" .$this->wxr_cdata( $meta->meta_value ) ."</wp:meta_value>\n\t\t</wp:postmeta>\n";
|
@@ -394,7 +394,7 @@ class BackWPup_JobType_WPEXP extends BackWPup_JobTypes {
|
|
394 |
$job_object->do_restart_time();
|
395 |
}
|
396 |
|
397 |
-
remove_filter( '
|
398 |
|
399 |
if ( $job_object->steps_data[ $job_object->step_working ]['substep'] == 'check' ) {
|
400 |
|
117 |
$job_object->substeps_done = 0;
|
118 |
}
|
119 |
|
120 |
+
add_filter( 'backwpup_wxr_export_skip_postmeta', array( $this, 'wxr_filter_postmeta' ), 10, 2 );
|
121 |
|
122 |
if ( $job_object->steps_data[ $job_object->step_working ]['substep'] == 'header' ) {
|
123 |
|
343 |
|
344 |
$postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
|
345 |
foreach ( $postmeta as $meta ) {
|
346 |
+
if ( apply_filters( 'backwpup_wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) ) {
|
347 |
continue;
|
348 |
}
|
349 |
$wxr_post .= "\t\t<wp:postmeta>\n\t\t\t<wp:meta_key>" . $meta->meta_key ."</wp:meta_key>\n\t\t\t<wp:meta_value>" .$this->wxr_cdata( $meta->meta_value ) ."</wp:meta_value>\n\t\t</wp:postmeta>\n";
|
394 |
$job_object->do_restart_time();
|
395 |
}
|
396 |
|
397 |
+
remove_filter( 'backwpup_wxr_export_skip_postmeta', array( $this, 'wxr_filter_postmeta' ), 10 );
|
398 |
|
399 |
if ( $job_object->steps_data[ $job_object->step_working ]['substep'] == 'check' ) {
|
400 |
|
inc/class-mysqldump.php
CHANGED
@@ -518,6 +518,9 @@ class BackWPup_MySQLDump {
|
|
518 |
$value = "NULL";
|
519 |
} elseif ( in_array( (int) $fieldinfo[ $key ]->type, array( MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_TINY, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_LONG, MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_LONGLONG, MYSQLI_TYPE_INT24 ), true ) ) {//is value numeric no esc
|
520 |
$value = empty( $value ) ? 0 : $value;
|
|
|
|
|
|
|
521 |
} else {
|
522 |
$value = "'" . $this->mysqli->real_escape_string( $value ) . "'";
|
523 |
}
|
518 |
$value = "NULL";
|
519 |
} elseif ( in_array( (int) $fieldinfo[ $key ]->type, array( MYSQLI_TYPE_DECIMAL, MYSQLI_TYPE_TINY, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_LONG, MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE, MYSQLI_TYPE_LONGLONG, MYSQLI_TYPE_INT24 ), true ) ) {//is value numeric no esc
|
520 |
$value = empty( $value ) ? 0 : $value;
|
521 |
+
} elseif ( $fieldinfo[ $key ]->flags & ( MYSQLI_BLOB_FLAG | MYSQLI_BINARY_FLAG ) ) {//is value binary or blob
|
522 |
+
$hex = unpack( 'H*', $value );
|
523 |
+
$value = empty( $value ) ? "''" : "0x$hex[1]";
|
524 |
} else {
|
525 |
$value = "'" . $this->mysqli->real_escape_string( $value ) . "'";
|
526 |
}
|
inc/class-option.php
CHANGED
@@ -27,6 +27,7 @@ final class BackWPup_Option {
|
|
27 |
add_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
28 |
add_site_option( 'backwpup_cfg_jobwaittimems', 0 );
|
29 |
add_site_option( 'backwpup_cfg_jobdooutput', 0 );
|
|
|
30 |
//Logs
|
31 |
add_site_option( 'backwpup_cfg_maxlogs', 30 );
|
32 |
add_site_option( 'backwpup_cfg_gzlogs', 0 );
|
@@ -136,7 +137,13 @@ final class BackWPup_Option {
|
|
136 |
} elseif ( ! isset( $jobs_options[ $jobid ][ $option ] ) ) {
|
137 |
return self::defaults_job( $option );
|
138 |
} else {
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
}
|
141 |
}
|
142 |
|
@@ -168,7 +175,7 @@ final class BackWPup_Option {
|
|
168 |
$default['mailerroronly'] = true;
|
169 |
$default['backuptype'] = 'archive';
|
170 |
$default['archiveformat'] = '.zip';
|
171 |
-
$default['archivename'] =
|
172 |
//defaults vor destinations
|
173 |
foreach ( BackWPup::get_registered_destinations() as $dest_key => $dest ) {
|
174 |
if ( ! empty( $dest['class'] ) ) {
|
@@ -295,4 +302,71 @@ final class BackWPup_Option {
|
|
295 |
|
296 |
return $new_option_job_ids;
|
297 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
}
|
27 |
add_site_option( 'backwpup_cfg_loglevel', 'normal_translated' );
|
28 |
add_site_option( 'backwpup_cfg_jobwaittimems', 0 );
|
29 |
add_site_option( 'backwpup_cfg_jobdooutput', 0 );
|
30 |
+
add_site_option( 'backwpup_cfg_windows', 0 );
|
31 |
//Logs
|
32 |
add_site_option( 'backwpup_cfg_maxlogs', 30 );
|
33 |
add_site_option( 'backwpup_cfg_gzlogs', 0 );
|
137 |
} elseif ( ! isset( $jobs_options[ $jobid ][ $option ] ) ) {
|
138 |
return self::defaults_job( $option );
|
139 |
} else {
|
140 |
+
// Ensure archive name formatted properly
|
141 |
+
if ( $option == 'archivename' ) {
|
142 |
+
return self::normalize_archive_name( $jobs_options[ $jobid ][ $option ], $jobid );
|
143 |
+
}
|
144 |
+
else {
|
145 |
+
return $jobs_options[ $jobid ][ $option ];
|
146 |
+
}
|
147 |
}
|
148 |
}
|
149 |
|
175 |
$default['mailerroronly'] = true;
|
176 |
$default['backuptype'] = 'archive';
|
177 |
$default['archiveformat'] = '.zip';
|
178 |
+
$default['archivename'] = self::get_archive_name_prefix( self::next_job_id() ) . '%Y-%m-%d_%H-%i-%s';
|
179 |
//defaults vor destinations
|
180 |
foreach ( BackWPup::get_registered_destinations() as $dest_key => $dest ) {
|
181 |
if ( ! empty( $dest['class'] ) ) {
|
302 |
|
303 |
return $new_option_job_ids;
|
304 |
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Gets the next available job id.
|
308 |
+
*
|
309 |
+
* @return int
|
310 |
+
*/
|
311 |
+
public static function next_job_id() {
|
312 |
+
$ids = self::get_job_ids();
|
313 |
+
sort( $ids );
|
314 |
+
return end( $ids ) + 1;
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Normalizes the archive name.
|
319 |
+
*
|
320 |
+
* The archive name should include the hash to identify this site, and the job id to identify this job.
|
321 |
+
*
|
322 |
+
* This allows backup files belonging to this job to be tracked.
|
323 |
+
*
|
324 |
+
* @param string $archive_name
|
325 |
+
* @param int $jobid
|
326 |
+
*
|
327 |
+
* @return string The normalized archive name
|
328 |
+
*/
|
329 |
+
public static function normalize_archive_name( $archive_name, $jobid ) {
|
330 |
+
$hash = BackWPup::get_plugin_data( 'hash' );
|
331 |
+
|
332 |
+
// If name starts with 'backwpup', then we can try to parse
|
333 |
+
if ( substr( $archive_name, 0, 8 ) == 'backwpup' ) {
|
334 |
+
$parts = explode( '_', $archive_name );
|
335 |
+
|
336 |
+
// Format = [hash][jobid]
|
337 |
+
if ( preg_match( '/^' . preg_quote( $hash ) . '(\d{2,})?$/', $parts[1], $matches ) ) {
|
338 |
+
// Was job id included?
|
339 |
+
if ( ! isset( $matches[1] ) ) {
|
340 |
+
// Append the job id
|
341 |
+
$parts[1] .= sprintf( '%02d', $jobid );
|
342 |
+
}
|
343 |
+
elseif ( $matches[1] != $jobid ) {
|
344 |
+
// This isn't the job ID you're looking for
|
345 |
+
// So fix, append the correct one
|
346 |
+
$parts[1] = $hash . sprintf( '%02d', $jobid );
|
347 |
+
}
|
348 |
+
}
|
349 |
+
else {
|
350 |
+
// Hash not included, so insert
|
351 |
+
array_splice( $parts, 1, 0, $hash . sprintf( '%02d', $jobid ) );
|
352 |
+
}
|
353 |
+
return implode( '_', $parts );
|
354 |
+
}
|
355 |
+
else {
|
356 |
+
// But otherwise, just prepend required format
|
357 |
+
return "backwpup_$hash" . sprintf( '%02d', $jobid ) . '_' . $archive_name;
|
358 |
+
}
|
359 |
+
}
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Get the prefix for an archive name.
|
363 |
+
*
|
364 |
+
* Format should be backwpup_[hash][jobid]_
|
365 |
+
*
|
366 |
+
* @return string
|
367 |
+
*/
|
368 |
+
public static function get_archive_name_prefix( $jobid ) {
|
369 |
+
return 'backwpup_' . BackWPup::get_plugin_data( 'hash' ) . sprintf( '%02d', $jobid ) . '_';
|
370 |
+
}
|
371 |
+
|
372 |
}
|
inc/class-page-about.php
CHANGED
@@ -368,7 +368,7 @@ class BackWPup_Page_About {
|
|
368 |
<img class="backwpup-banner-img" src="<?php echo BackWPup::get_plugin_data( 'URL' );?>/assets/images/backwpupbanner.png" />
|
369 |
<h1><?php esc_html_e( 'Welcome to BackWPup Pro', 'backwpup' ); ?></h1>
|
370 |
<p><?php esc_html_e( 'BackWPup’s job wizards make planning and scheduling your backup jobs a breeze.', 'backwpup' ); echo ' ';
|
371 |
-
_e( 'Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server. With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin
|
372 |
<p><?php echo str_replace( '\"','"', sprintf( __( 'Ready to <a href="%1$s">set up a backup job</a>? You can <a href="%2$s">use the wizards</a> or plan your backup in expert mode.', 'backwpup' ), network_admin_url( 'admin.php').'?page=backwpupeditjob' , network_admin_url( 'admin.php').'?page=backwpupwizard' ) ); ?></p>
|
373 |
</div>
|
374 |
<?php if ( '2016-06-30' > date( 'Y-m-d' ) ) { ?>
|
@@ -381,7 +381,7 @@ _e( 'Use your backup archives to save your entire WordPress installation includi
|
|
381 |
<img class="backwpup-banner-img" src="<?php echo esc_attr( BackWPup::get_plugin_data( 'URL' ));?>/assets/images/backwpupbanner.png" />
|
382 |
<h1><?php esc_html_e( 'Welcome to BackWPup', 'backwpup' ); ?></h1>
|
383 |
<p><?php
|
384 |
-
_e( 'Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server. With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin
|
385 |
<p><?php esc_html_e( 'Ready to set up a backup job? Use one of the wizards to plan what you want to save.', 'backwpup' ); ?></p>
|
386 |
</div>
|
387 |
<?php if ( '2016-06-30' > date( 'Y-m-d' ) ) { ?>
|
368 |
<img class="backwpup-banner-img" src="<?php echo BackWPup::get_plugin_data( 'URL' );?>/assets/images/backwpupbanner.png" />
|
369 |
<h1><?php esc_html_e( 'Welcome to BackWPup Pro', 'backwpup' ); ?></h1>
|
370 |
<p><?php esc_html_e( 'BackWPup’s job wizards make planning and scheduling your backup jobs a breeze.', 'backwpup' ); echo ' ';
|
371 |
+
_e( 'Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server. With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin to restore your database backup files.', 'backwpup' ); ?></p>
|
372 |
<p><?php echo str_replace( '\"','"', sprintf( __( 'Ready to <a href="%1$s">set up a backup job</a>? You can <a href="%2$s">use the wizards</a> or plan your backup in expert mode.', 'backwpup' ), network_admin_url( 'admin.php').'?page=backwpupeditjob' , network_admin_url( 'admin.php').'?page=backwpupwizard' ) ); ?></p>
|
373 |
</div>
|
374 |
<?php if ( '2016-06-30' > date( 'Y-m-d' ) ) { ?>
|
381 |
<img class="backwpup-banner-img" src="<?php echo esc_attr( BackWPup::get_plugin_data( 'URL' ));?>/assets/images/backwpupbanner.png" />
|
382 |
<h1><?php esc_html_e( 'Welcome to BackWPup', 'backwpup' ); ?></h1>
|
383 |
<p><?php
|
384 |
+
_e( 'Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server. With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin to restore your database backup files.', 'backwpup' ); ?></p>
|
385 |
<p><?php esc_html_e( 'Ready to set up a backup job? Use one of the wizards to plan what you want to save.', 'backwpup' ); ?></p>
|
386 |
</div>
|
387 |
<?php if ( '2016-06-30' > date( 'Y-m-d' ) ) { ?>
|
inc/class-page-backups.php
CHANGED
@@ -357,7 +357,6 @@ class BackWPup_Page_Backups extends WP_List_Table {
|
|
357 |
*/
|
358 |
function column_time( $item ) {
|
359 |
|
360 |
-
$item[ 'time' ] = $item[ 'time' ] + get_option( 'gmt_offset' ) * 3600;
|
361 |
return sprintf( __( '%1$s at %2$s', 'backwpup' ), date_i18n( get_option( 'date_format' ), $item[ 'time' ], TRUE ), date_i18n( get_option( 'time_format' ), $item[ 'time' ], TRUE ) );
|
362 |
}
|
363 |
|
357 |
*/
|
358 |
function column_time( $item ) {
|
359 |
|
|
|
360 |
return sprintf( __( '%1$s at %2$s', 'backwpup' ), date_i18n( get_option( 'date_format' ), $item[ 'time' ], TRUE ), date_i18n( get_option( 'time_format' ), $item[ 'time' ], TRUE ) );
|
361 |
}
|
362 |
|
inc/class-page-backwpup.php
CHANGED
@@ -74,7 +74,7 @@ class BackWPup_Page_BackWPup {
|
|
74 |
<h3><?php _ex( 'Planning backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
75 |
<p><?php _e('BackWPup’s job wizards make planning and scheduling your backup jobs a breeze.','backwpup' ); echo ' '; _e('Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server.','backwpup'); ?></p>
|
76 |
<h3><?php _ex( 'Restoring backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
77 |
-
<p><?php _e( 'With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin
|
78 |
<h3><?php _ex( 'Ready to set up a backup job?', 'Dashboard heading','backwpup' ); ?></h3>
|
79 |
<p><?php printf( __('Use one of the wizards to plan a backup, or use <a href="%s">expert mode</a> for full control over all options.','backwpup'), network_admin_url( 'admin.php') . '?page=backwpupeditjob' ); echo ' '; _e( '<strong>Please note: You are solely responsible for the security of your data; the authors of this plugin are not.</strong>', 'backwpup' ); ?></p>
|
80 |
</div>
|
@@ -83,7 +83,7 @@ class BackWPup_Page_BackWPup {
|
|
83 |
<h3><?php _ex( 'Planning backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
84 |
<p><?php _e('Use the short links in the <strong>First steps</strong> box to plan and schedule backup jobs.','backwpup' ); echo ' '; _e('Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server.','backwpup'); ?></p>
|
85 |
<h3><?php _ex( 'Restoring backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
86 |
-
<p><?php _e( 'With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin
|
87 |
<h3><?php _ex( 'Ready to set up a backup job?', 'Dashboard heading','backwpup' ); ?></h3>
|
88 |
<p><?php printf( __('<a href="%s">Add a new backup job</a> and plan what you want to save.','backwpup'), network_admin_url( 'admin.php') . '?page=backwpupeditjob' ); ?>
|
89 |
<br /><?php _e( '<strong>Please note: You are solely responsible for the security of your data; the authors of this plugin are not.</strong>', 'backwpup' ); ?></p>
|
@@ -254,7 +254,7 @@ class BackWPup_Page_BackWPup {
|
|
254 |
<p><img class="backwpup-banner-img" src="<?php echo BackWPup::get_plugin_data( 'URL' ) . '/assets/images/backwpupbanner.png'; ?>" alt="BackWPup Banner" /></p>
|
255 |
<h3 class="backwpup-text-center"><?php _ex( 'Get access to:', 'Pro teaser box', 'backwpup' ); ?></h3>
|
256 |
<ul class="backwpup-text-center">
|
257 |
-
<li><?php _ex( 'First-class <strong>dedicated support</strong> at
|
258 |
<li><?php echo esc_html_x( 'Differential backups to Google Drive and other cloud storage service.', 'Pro teaser box', 'backwpup' ); ?></li>
|
259 |
<li><?php echo esc_html_x( 'Easy-peasy wizards to create and schedule backup jobs.', 'Pro teaser box', 'backwpup' ); ?></li>
|
260 |
<li><?php printf( '<a href="' . esc_html__( 'http://backwpup.com', 'backwpup' ) .'">%s</a>', _x( 'And more…', 'Pro teaser box, link text', 'backwpup' ) ); ?></li>
|
@@ -351,39 +351,47 @@ class BackWPup_Page_BackWPup {
|
|
351 |
$logfiles = array();
|
352 |
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
353 |
$log_folder = BackWPup_File::get_absolute_path( $log_folder );
|
354 |
-
if ( is_readable( $log_folder )
|
355 |
-
|
356 |
-
|
357 |
-
|
|
|
|
|
|
|
358 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
359 |
}
|
360 |
-
closedir( $dir );
|
361 |
-
krsort( $logfiles, SORT_NUMERIC );
|
362 |
}
|
363 |
|
364 |
if ( count( $logfiles ) > 0 ) {
|
365 |
$count = 0;
|
366 |
$alternate = TRUE;
|
367 |
foreach ( $logfiles as $logfile ) {
|
368 |
-
$logdata = BackWPup_Job::read_logheader( $
|
369 |
if ( ! $alternate ) {
|
370 |
echo '<tr>';
|
371 |
$alternate = TRUE;
|
372 |
-
}
|
|
|
373 |
echo '<tr class="alternate">';
|
374 |
$alternate = FALSE;
|
375 |
}
|
376 |
echo '<td>' . sprintf( __( '%1$s at %2$s', 'backwpup' ), date_i18n( get_option( 'date_format' ) , $logdata[ 'logtime' ] ), date_i18n( get_option( 'time_format' ), $logdata[ 'logtime' ] ) ) . '</td>';
|
377 |
-
$log_name = str_replace( array( '.html', '.gz' ), '',
|
378 |
-
echo '<td><a class="thickbox" href="' . admin_url( 'admin-ajax.php
|
379 |
echo '<td>';
|
380 |
-
if ( $logdata[
|
381 |
-
printf( '<span style="color:red;font-weight:bold;">' . _n( "%d ERROR", "%d ERRORS", $logdata[
|
382 |
}
|
383 |
-
if ( $logdata[
|
384 |
-
printf( '<span style="color:#e66f00;font-weight:bold;">' . _n( "%d WARNING", "%d WARNINGS", $logdata[
|
385 |
}
|
386 |
-
if ( ! $logdata[
|
387 |
echo '<span style="color:green;font-weight:bold;">' . __( 'OK', 'backwpup' ) . '</span>';
|
388 |
}
|
389 |
echo '</td></tr>';
|
74 |
<h3><?php _ex( 'Planning backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
75 |
<p><?php _e('BackWPup’s job wizards make planning and scheduling your backup jobs a breeze.','backwpup' ); echo ' '; _e('Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server.','backwpup'); ?></p>
|
76 |
<h3><?php _ex( 'Restoring backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
77 |
+
<p><?php _e( 'With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin to restore your database backup files.', 'backwpup' ) ?></p>
|
78 |
<h3><?php _ex( 'Ready to set up a backup job?', 'Dashboard heading','backwpup' ); ?></h3>
|
79 |
<p><?php printf( __('Use one of the wizards to plan a backup, or use <a href="%s">expert mode</a> for full control over all options.','backwpup'), network_admin_url( 'admin.php') . '?page=backwpupeditjob' ); echo ' '; _e( '<strong>Please note: You are solely responsible for the security of your data; the authors of this plugin are not.</strong>', 'backwpup' ); ?></p>
|
80 |
</div>
|
83 |
<h3><?php _ex( 'Planning backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
84 |
<p><?php _e('Use the short links in the <strong>First steps</strong> box to plan and schedule backup jobs.','backwpup' ); echo ' '; _e('Use your backup archives to save your entire WordPress installation including <code>/wp-content/</code>. Push them to an external storage service if you don’t want to save the backups on the same server.','backwpup'); ?></p>
|
85 |
<h3><?php _ex( 'Restoring backups', 'Dashboard heading', 'backwpup' ); ?></h3>
|
86 |
+
<p><?php _e( 'With a single backup archive you are able to restore an installation. Use a tool like phpMyAdmin to restore your database backup files.', 'backwpup' ) ?></p>
|
87 |
<h3><?php _ex( 'Ready to set up a backup job?', 'Dashboard heading','backwpup' ); ?></h3>
|
88 |
<p><?php printf( __('<a href="%s">Add a new backup job</a> and plan what you want to save.','backwpup'), network_admin_url( 'admin.php') . '?page=backwpupeditjob' ); ?>
|
89 |
<br /><?php _e( '<strong>Please note: You are solely responsible for the security of your data; the authors of this plugin are not.</strong>', 'backwpup' ); ?></p>
|
254 |
<p><img class="backwpup-banner-img" src="<?php echo BackWPup::get_plugin_data( 'URL' ) . '/assets/images/backwpupbanner.png'; ?>" alt="BackWPup Banner" /></p>
|
255 |
<h3 class="backwpup-text-center"><?php _ex( 'Get access to:', 'Pro teaser box', 'backwpup' ); ?></h3>
|
256 |
<ul class="backwpup-text-center">
|
257 |
+
<li><?php _ex( 'First-class <strong>dedicated support</strong> at backwpup.com.', 'Pro teaser box', 'backwpup' ); ?></li>
|
258 |
<li><?php echo esc_html_x( 'Differential backups to Google Drive and other cloud storage service.', 'Pro teaser box', 'backwpup' ); ?></li>
|
259 |
<li><?php echo esc_html_x( 'Easy-peasy wizards to create and schedule backup jobs.', 'Pro teaser box', 'backwpup' ); ?></li>
|
260 |
<li><?php printf( '<a href="' . esc_html__( 'http://backwpup.com', 'backwpup' ) .'">%s</a>', _x( 'And more…', 'Pro teaser box, link text', 'backwpup' ) ); ?></li>
|
351 |
$logfiles = array();
|
352 |
$log_folder = get_site_option( 'backwpup_cfg_logfolder' );
|
353 |
$log_folder = BackWPup_File::get_absolute_path( $log_folder );
|
354 |
+
if ( is_readable( $log_folder ) ) {
|
355 |
+
try {
|
356 |
+
$dir = new BackWPup_Directory( $log_folder );
|
357 |
+
foreach ( $dir as $file ) {
|
358 |
+
if ( $file->isReadable() && $file->isFile() && strpos( $file->getFilename(), 'backwpup_log_' ) !== false && strpos( $file->getFilename(), '.html' ) !== false ) {
|
359 |
+
$logfiles[ $file->getMTime() ] = clone $file;
|
360 |
+
}
|
361 |
}
|
362 |
+
krsort( $logfiles, SORT_NUMERIC );
|
363 |
+
}
|
364 |
+
catch ( UnexpectedValueException $e ) {
|
365 |
+
echo '<tr><td colspan="3"><span style="color:red;font-weight:bold;">' .
|
366 |
+
sprintf( __( 'Could not open log folder: %s', 'backwpup' ), $log_folder ) .
|
367 |
+
'</td></tr>';
|
368 |
}
|
|
|
|
|
369 |
}
|
370 |
|
371 |
if ( count( $logfiles ) > 0 ) {
|
372 |
$count = 0;
|
373 |
$alternate = TRUE;
|
374 |
foreach ( $logfiles as $logfile ) {
|
375 |
+
$logdata = BackWPup_Job::read_logheader( $logfile->getPathname() );
|
376 |
if ( ! $alternate ) {
|
377 |
echo '<tr>';
|
378 |
$alternate = TRUE;
|
379 |
+
}
|
380 |
+
else {
|
381 |
echo '<tr class="alternate">';
|
382 |
$alternate = FALSE;
|
383 |
}
|
384 |
echo '<td>' . sprintf( __( '%1$s at %2$s', 'backwpup' ), date_i18n( get_option( 'date_format' ) , $logdata[ 'logtime' ] ), date_i18n( get_option( 'time_format' ), $logdata[ 'logtime' ] ) ) . '</td>';
|
385 |
+
$log_name = str_replace( array( '.html', '.gz' ), '', $logfile->getBasename() );
|
386 |
+
echo '<td><a class="thickbox" href="' . admin_url( 'admin-ajax.php?action=backwpup_view_log&log=' . $log_name .'&_ajax_nonce=' . wp_create_nonce( 'view-log_' . $log_name ) . '&TB_iframe=true&width=640&height=440' ) . '" title="' . esc_attr( $logfile->getBasename() ) . '">' . esc_html( $logdata['name'] ) . '</i></a></td>';
|
387 |
echo '<td>';
|
388 |
+
if ( $logdata['errors'] ) {
|
389 |
+
printf( '<span style="color:red;font-weight:bold;">' . _n( "%d ERROR", "%d ERRORS", $logdata['errors'], 'backwpup' ) . '</span><br />', $logdata[ 'errors' ] );
|
390 |
}
|
391 |
+
if ( $logdata['warnings'] ) {
|
392 |
+
printf( '<span style="color:#e66f00;font-weight:bold;">' . _n( "%d WARNING", "%d WARNINGS", $logdata['warnings'], 'backwpup' ) . '</span><br />', $logdata['warnings'] );
|
393 |
}
|
394 |
+
if ( ! $logdata['errors'] && ! $logdata['warnings'] ) {
|
395 |
echo '<span style="color:green;font-weight:bold;">' . __( 'OK', 'backwpup' ) . '</span>';
|
396 |
}
|
397 |
echo '</td></tr>';
|
inc/class-page-editjob.php
CHANGED
@@ -122,7 +122,7 @@ class BackWPup_Page_Editjob {
|
|
122 |
), true ) ? $_POST['archiveformat'] : '.zip';
|
123 |
BackWPup_Option::update( $jobid, 'archiveformat', $archiveformat );
|
124 |
|
125 |
-
BackWPup_Option::update( $jobid, 'archivename', BackWPup_Job::sanitize_file_name( $_POST['archivename'] ) );
|
126 |
break;
|
127 |
case 'cron':
|
128 |
$activetype = in_array( $_POST['activetype'], array(
|
@@ -313,9 +313,7 @@ class BackWPup_Page_Editjob {
|
|
313 |
}
|
314 |
else {
|
315 |
//generate jobid if not exists
|
316 |
-
$
|
317 |
-
sort( $newjobid );
|
318 |
-
$jobid = end( $newjobid ) + 1;
|
319 |
}
|
320 |
|
321 |
$destinations = BackWPup::get_registered_destinations();
|
@@ -437,7 +435,8 @@ class BackWPup_Page_Editjob {
|
|
437 |
<tr class="nosync">
|
438 |
<th scope="row"><label for="archivename"><?php esc_html_e( 'Archive name', 'backwpup' ) ?></label></th>
|
439 |
<td>
|
440 |
-
<input name="archivename" type="text" id="archivename" placeholder="
|
|
|
441 |
<?php
|
442 |
$current_time = current_time( 'timestamp' );
|
443 |
$datevars = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
|
122 |
), true ) ? $_POST['archiveformat'] : '.zip';
|
123 |
BackWPup_Option::update( $jobid, 'archiveformat', $archiveformat );
|
124 |
|
125 |
+
BackWPup_Option::update( $jobid, 'archivename', BackWPup_Job::sanitize_file_name( BackWPup_Option::normalize_archive_name( $_POST['archivename'], $jobid ) ) );
|
126 |
break;
|
127 |
case 'cron':
|
128 |
$activetype = in_array( $_POST['activetype'], array(
|
313 |
}
|
314 |
else {
|
315 |
//generate jobid if not exists
|
316 |
+
$jobid = BackWPup_Option::next_job_id();
|
|
|
|
|
317 |
}
|
318 |
|
319 |
$destinations = BackWPup::get_registered_destinations();
|
435 |
<tr class="nosync">
|
436 |
<th scope="row"><label for="archivename"><?php esc_html_e( 'Archive name', 'backwpup' ) ?></label></th>
|
437 |
<td>
|
438 |
+
<input name="archivename" type="text" id="archivename" placeholder="%Y-%m-%d_%H-%i-%s" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'archivename' ) );?>" class="regular-text code" />
|
439 |
+
<p><?php printf( __( '<em>Note</em>: In order for backup file tracking to work, the archive name must begin with %s.', 'backwpup' ), BackWPup_Option::get_archive_name_prefix( $jobid ) ) ?></p>
|
440 |
<?php
|
441 |
$current_time = current_time( 'timestamp' );
|
442 |
$datevars = array( '%d', '%j', '%m', '%n', '%Y', '%y', '%a', '%A', '%B', '%g', '%G', '%h', '%H', '%i', '%s' );
|
inc/class-page-logs.php
CHANGED
@@ -46,15 +46,15 @@ class BackWPup_Page_Logs extends WP_List_Table {
|
|
46 |
|
47 |
//load logs
|
48 |
$logfiles = array();
|
49 |
-
if ( is_readable( $this->log_folder )
|
50 |
-
|
51 |
-
|
52 |
-
if (
|
53 |
-
$logfiles[] = $file;
|
54 |
}
|
55 |
}
|
56 |
-
closedir( $dir );
|
57 |
}
|
|
|
58 |
//ordering
|
59 |
$order = isset( $_GET[ 'order' ] ) ? $_GET[ 'order' ] : 'desc';
|
60 |
$orderby = isset( $_GET[ 'orderby' ] ) ? $_GET[ 'orderby' ] : 'time';
|
46 |
|
47 |
//load logs
|
48 |
$logfiles = array();
|
49 |
+
if ( is_readable( $this->log_folder ) ) {
|
50 |
+
$dir = new BackWPup_Directory( $this->log_folder );
|
51 |
+
foreach ( $dir as $file ) {
|
52 |
+
if ( $file->isFile() && $file->isReadable() && strpos( $file->getFilename(), 'backwpup_log_' ) !== false && strpos( $file->getFilename(), '.html' ) !== false ) {
|
53 |
+
$logfiles[] = $file->getFilename();
|
54 |
}
|
55 |
}
|
|
|
56 |
}
|
57 |
+
|
58 |
//ordering
|
59 |
$order = isset( $_GET[ 'order' ] ) ? $_GET[ 'order' ] : 'desc';
|
60 |
$orderby = isset( $_GET[ 'orderby' ] ) ? $_GET[ 'orderby' ] : 'time';
|
inc/class-page-settings.php
CHANGED
@@ -41,6 +41,7 @@ class BackWPup_Page_Settings {
|
|
41 |
delete_site_option( 'backwpup_cfg_jobwaittimems' );
|
42 |
delete_site_option( 'backwpup_cfg_jobrunauthkey' );
|
43 |
delete_site_option( 'backwpup_cfg_jobdooutput' );
|
|
|
44 |
delete_site_option( 'backwpup_cfg_maxlogs' );
|
45 |
delete_site_option( 'backwpup_cfg_gzlogs' );
|
46 |
delete_site_option( 'backwpup_cfg_protectfolders' );
|
@@ -74,6 +75,7 @@ class BackWPup_Page_Settings {
|
|
74 |
update_site_option( 'backwpup_cfg_loglevel', in_array( $_POST[ 'loglevel' ], array( 'normal_translated', 'normal', 'debug_translated', 'debug' ), true ) ? $_POST[ 'loglevel' ] : 'normal_translated' );
|
75 |
update_site_option( 'backwpup_cfg_jobwaittimems', absint( $_POST[ 'jobwaittimems' ] ) );
|
76 |
update_site_option( 'backwpup_cfg_jobdooutput', ! empty( $_POST[ 'jobdooutput' ] ) );
|
|
|
77 |
update_site_option( 'backwpup_cfg_maxlogs', absint( $_POST[ 'maxlogs' ] ) );
|
78 |
update_site_option( 'backwpup_cfg_gzlogs', ! empty( $_POST[ 'gzlogs' ] ) );
|
79 |
update_site_option( 'backwpup_cfg_protectfolders', ! empty( $_POST[ 'protectfolders' ] ) );
|
@@ -291,6 +293,19 @@ class BackWPup_Page_Settings {
|
|
291 |
</fieldset>
|
292 |
</td>
|
293 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
</table>
|
295 |
|
296 |
</div>
|
@@ -339,7 +354,7 @@ class BackWPup_Page_Settings {
|
|
339 |
<label for="authentication_user_id">
|
340 |
<select name="authentication_user_id" size="1" >
|
341 |
<?php
|
342 |
-
$users = get_users( array( '
|
343 |
foreach ( $users as $user ) {
|
344 |
echo '<option value="' . $user->ID . '" '. selected( $authentication[ 'user_id' ], $user->ID, FALSE ) .'>'. esc_attr( $user->display_name ) .'</option>';
|
345 |
}
|
41 |
delete_site_option( 'backwpup_cfg_jobwaittimems' );
|
42 |
delete_site_option( 'backwpup_cfg_jobrunauthkey' );
|
43 |
delete_site_option( 'backwpup_cfg_jobdooutput' );
|
44 |
+
delete_site_option( 'backwpup_cfg_windows' );
|
45 |
delete_site_option( 'backwpup_cfg_maxlogs' );
|
46 |
delete_site_option( 'backwpup_cfg_gzlogs' );
|
47 |
delete_site_option( 'backwpup_cfg_protectfolders' );
|
75 |
update_site_option( 'backwpup_cfg_loglevel', in_array( $_POST[ 'loglevel' ], array( 'normal_translated', 'normal', 'debug_translated', 'debug' ), true ) ? $_POST[ 'loglevel' ] : 'normal_translated' );
|
76 |
update_site_option( 'backwpup_cfg_jobwaittimems', absint( $_POST[ 'jobwaittimems' ] ) );
|
77 |
update_site_option( 'backwpup_cfg_jobdooutput', ! empty( $_POST[ 'jobdooutput' ] ) );
|
78 |
+
update_site_option( 'backwpup_cfg_windows', ! empty( $_POST[ 'windows' ] ) );
|
79 |
update_site_option( 'backwpup_cfg_maxlogs', absint( $_POST[ 'maxlogs' ] ) );
|
80 |
update_site_option( 'backwpup_cfg_gzlogs', ! empty( $_POST[ 'gzlogs' ] ) );
|
81 |
update_site_option( 'backwpup_cfg_protectfolders', ! empty( $_POST[ 'protectfolders' ] ) );
|
293 |
</fieldset>
|
294 |
</td>
|
295 |
</tr>
|
296 |
+
<tr>
|
297 |
+
<th scope="row"><?php _e( 'Windows IIS compatibility', 'backwpup' ); ?></th>
|
298 |
+
<td>
|
299 |
+
<fieldset>
|
300 |
+
<legend class="screen-reader-text"><span><?php _e( 'Enable compatibility with IIS on Windows.', 'backwpup' ); ?></span></legend>
|
301 |
+
<label for="windows">
|
302 |
+
<input name="windows" type="checkbox" id="windows" value="1"<?php checked( get_site_option( 'backwpup_cfg_windows' ), true ) ?> />
|
303 |
+
<?php _e( 'Enable compatibility with IIS on Windows.', 'backwpup' ); ?>
|
304 |
+
</label>
|
305 |
+
<p class="description"><?php _e( 'There is a PHP bug (<a href="https://bugs.php.net/43817">bug #43817</a>), which is triggered on some versions of Windows and IIS. Checking this box will enable a workaround for that bug. Only enable if you are getting errors about “Permission denied” in your logs.', 'backwpup' ) ?></p>
|
306 |
+
</fieldset>
|
307 |
+
</td>
|
308 |
+
</tr>
|
309 |
</table>
|
310 |
|
311 |
</div>
|
354 |
<label for="authentication_user_id">
|
355 |
<select name="authentication_user_id" size="1" >
|
356 |
<?php
|
357 |
+
$users = get_users( array( 'role' => 'administrator', 'number' => 99, 'orderby' => 'display_name' ) );
|
358 |
foreach ( $users as $user ) {
|
359 |
echo '<option value="' . $user->ID . '" '. selected( $authentication[ 'user_id' ], $user->ID, FALSE ) .'>'. esc_attr( $user->display_name ) .'</option>';
|
360 |
}
|
inc/class-path-fixer.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Fix paths so they don't trigger an error on Windows.
|
5 |
+
*
|
6 |
+
* This class is meant to be a workaround for PHP bug #43817.
|
7 |
+
*
|
8 |
+
* On Windows IIS, if the parent directory is not readable, then the given directory will give access denied.
|
9 |
+
*
|
10 |
+
* @since 3.4.0
|
11 |
+
*/
|
12 |
+
class BackWPup_Path_Fixer {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Fix the path if necessary.
|
16 |
+
*
|
17 |
+
* @param string $path
|
18 |
+
*
|
19 |
+
* @return string The fixed path.
|
20 |
+
*/
|
21 |
+
public static function fix_path( $path ) {
|
22 |
+
if ( get_site_option( 'backwpup_cfg_windows' ) ) {
|
23 |
+
$path = trailingslashit( $path );
|
24 |
+
|
25 |
+
if ( is_dir( $path . 'wp-content' ) ) {
|
26 |
+
return $path . 'wp-content/..';
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
return $path;
|
31 |
+
}
|
32 |
+
|
33 |
+
}
|
inc/class-recursive-directory.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Wraps RecursiveDirectoryIterator to fix paths.
|
5 |
+
*
|
6 |
+
* @since 3.4.0
|
7 |
+
*/
|
8 |
+
class BackWPup_Recursive_Directory extends RecursiveDirectoryIterator {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Creates the iterator.
|
12 |
+
*
|
13 |
+
* Fixes the path before calling the parent constructor.
|
14 |
+
*
|
15 |
+
* @param string $path
|
16 |
+
*/
|
17 |
+
public function __construct( $path, $flags = null ) {
|
18 |
+
if ( $flags === null ) {
|
19 |
+
$flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO;
|
20 |
+
}
|
21 |
+
parent::__construct( BackWPup_Path_Fixer::fix_path( $path ), $flags );
|
22 |
+
}
|
23 |
+
|
24 |
+
}
|
languages/backwpup.pot
CHANGED
@@ -1,16 +1,16 @@
|
|
1 |
-
#
|
2 |
-
#
|
3 |
-
# This file is distributed under the same license BackWPup Pro package.
|
4 |
-
#
|
5 |
-
#, fuzzy
|
6 |
msgid ""
|
7 |
msgstr ""
|
8 |
-
"
|
|
|
|
|
9 |
"MIME-Version: 1.0\n"
|
10 |
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
"Content-Transfer-Encoding: 8bit\n"
|
12 |
-
"
|
13 |
-
"
|
|
|
14 |
|
15 |
#: backwpup.php:333 inc/class-page-backups.php:271
|
16 |
msgid "Folder"
|
@@ -36,7 +36,7 @@ msgstr ""
|
|
36 |
msgid "Backup to FTP"
|
37 |
msgstr ""
|
38 |
|
39 |
-
#: backwpup.php:381 inc/class-destination-dropbox.php:
|
40 |
msgid "Dropbox"
|
41 |
msgstr ""
|
42 |
|
@@ -77,17 +77,14 @@ msgid "Backup to SugarSync"
|
|
77 |
msgstr ""
|
78 |
|
79 |
#: backwpup.php:470
|
80 |
-
#, php-format
|
81 |
msgid "PHP Version %1$s is to low, you need Version %2$s or above."
|
82 |
msgstr ""
|
83 |
|
84 |
#: backwpup.php:477
|
85 |
-
#, php-format
|
86 |
msgid "Missing function \"%s\"."
|
87 |
msgstr ""
|
88 |
|
89 |
#: backwpup.php:486
|
90 |
-
#, php-format
|
91 |
msgid "Missing class \"%s\"."
|
92 |
msgstr ""
|
93 |
|
@@ -108,7 +105,7 @@ msgid "Dashboard"
|
|
108 |
msgstr ""
|
109 |
|
110 |
#: inc/class-admin.php:243 inc/class-adminbar.php:82
|
111 |
-
#: inc/class-page-settings.php:
|
112 |
msgid "Jobs"
|
113 |
msgstr ""
|
114 |
|
@@ -117,7 +114,7 @@ msgid "Add new job"
|
|
117 |
msgstr ""
|
118 |
|
119 |
#: inc/class-admin.php:273 inc/class-adminbar.php:98
|
120 |
-
#: inc/class-page-logs.php:328 inc/class-page-settings.php:
|
121 |
msgid "Logs"
|
122 |
msgstr ""
|
123 |
|
@@ -138,24 +135,24 @@ msgid "Cheating, huh?"
|
|
138 |
msgstr ""
|
139 |
|
140 |
#: inc/class-admin.php:381
|
141 |
-
#, php-format
|
142 |
msgid "<a class=\"backwpup-get-pro\" href=\"%s\">Get BackWPup Pro now.</a>"
|
143 |
msgstr ""
|
144 |
|
|
|
|
|
145 |
#: inc/class-admin.php:381 inc/class-admin.php:401 inc/class-help.php:17
|
146 |
#: inc/class-help.php:22 inc/class-job.php:394
|
147 |
#: inc/class-jobtype-dbcheck.php:15 inc/class-jobtype-dbdump.php:15
|
148 |
#: inc/class-jobtype-file.php:15 inc/class-jobtype-wpexp.php:15
|
149 |
#: inc/class-jobtype-wpplugin.php:15 inc/class-page-about.php:624
|
150 |
#: inc/class-page-backwpup.php:260 inc/class-page-backwpup.php:262
|
151 |
-
#: inc/class-page-settings.php:
|
152 |
#: inc/pro/class-wizard-jobimport.php:16
|
153 |
#: inc/pro/class-wizard-systemtest.php:16
|
154 |
msgid "http://backwpup.com"
|
155 |
msgstr ""
|
156 |
|
157 |
#: inc/class-admin.php:401
|
158 |
-
#, php-format
|
159 |
msgid "version %s"
|
160 |
msgstr ""
|
161 |
|
@@ -192,19 +189,23 @@ msgstr ""
|
|
192 |
msgid "Make BackWPup better!"
|
193 |
msgstr ""
|
194 |
|
195 |
-
#: inc/class-become-inpsyder-widget.php:
|
196 |
-
msgid "
|
|
|
|
|
197 |
msgstr ""
|
198 |
|
199 |
-
#: inc/class-become-inpsyder-widget.php:
|
200 |
msgid "We want to make BackWPup even stronger and its support much faster."
|
201 |
msgstr ""
|
202 |
|
203 |
-
#: inc/class-become-inpsyder-widget.php:
|
204 |
-
msgid "
|
|
|
|
|
205 |
msgstr ""
|
206 |
|
207 |
-
#: inc/class-become-inpsyder-widget.php:
|
208 |
msgid "and other exciting WordPress projects at our VIP partner agency."
|
209 |
msgstr ""
|
210 |
|
@@ -229,8 +230,10 @@ msgstr ""
|
|
229 |
msgid "https://backwpup.com/become-backwpup-beta-tester/"
|
230 |
msgstr ""
|
231 |
|
232 |
-
#: inc/class-betatester-admin-notice.php:
|
233 |
-
msgid "
|
|
|
|
|
234 |
msgstr ""
|
235 |
|
236 |
#: inc/class-create-archive.php:64
|
@@ -238,7 +241,6 @@ msgid "The file name of an archive cannot be empty."
|
|
238 |
msgstr ""
|
239 |
|
240 |
#: inc/class-create-archive.php:72
|
241 |
-
#, php-format
|
242 |
msgctxt "%s = Folder name"
|
243 |
msgid "Folder %s for archive not found"
|
244 |
msgstr ""
|
@@ -253,13 +255,11 @@ msgid "Functions for bz2 compression not available"
|
|
253 |
msgstr ""
|
254 |
|
255 |
#: inc/class-create-archive.php:106
|
256 |
-
#, php-format
|
257 |
msgctxt "ZipArchive open() result"
|
258 |
msgid "Cannot create zip archive: %d"
|
259 |
msgstr ""
|
260 |
|
261 |
#: inc/class-create-archive.php:135
|
262 |
-
#, php-format
|
263 |
msgctxt "%s = file name"
|
264 |
msgid "Method to archive file %s not detected"
|
265 |
msgstr ""
|
@@ -269,7 +269,6 @@ msgid "Cannot open archive file"
|
|
269 |
msgstr ""
|
270 |
|
271 |
#: inc/class-create-archive.php:155 inc/class-create-archive.php:349
|
272 |
-
#, php-format
|
273 |
msgid "PclZip archive add error: %s"
|
274 |
msgstr ""
|
275 |
|
@@ -282,7 +281,6 @@ msgid "File name cannot be empty"
|
|
282 |
msgstr ""
|
283 |
|
284 |
#: inc/class-create-archive.php:228
|
285 |
-
#, php-format
|
286 |
msgctxt "File to add to archive"
|
287 |
msgid "File %s does not exist or is not readable"
|
288 |
msgstr ""
|
@@ -293,7 +291,6 @@ msgid "This archive method can only add one file"
|
|
293 |
msgstr ""
|
294 |
|
295 |
#: inc/class-create-archive.php:247 inc/class-create-archive.php:263
|
296 |
-
#, php-format
|
297 |
msgid "Cannot open source file %s to archive"
|
298 |
msgstr ""
|
299 |
|
@@ -303,7 +300,6 @@ msgstr ""
|
|
303 |
|
304 |
#: inc/class-create-archive.php:329 inc/class-create-archive.php:338
|
305 |
#: inc/class-create-archive.php:407
|
306 |
-
#, php-format
|
307 |
msgid "Cannot add \"%s\" to zip archive!"
|
308 |
msgstr ""
|
309 |
|
@@ -312,29 +308,24 @@ msgid "Folder name cannot be empty"
|
|
312 |
msgstr ""
|
313 |
|
314 |
#: inc/class-create-archive.php:379
|
315 |
-
#, php-format
|
316 |
msgctxt "Folder path to add to archive"
|
317 |
msgid "Folder %s does not exist or is not readable"
|
318 |
msgstr ""
|
319 |
|
320 |
#: inc/class-create-archive.php:429
|
321 |
-
#, php-format
|
322 |
msgctxt "Text of ZipArchive status Message"
|
323 |
msgid "ZipArchive returns status: %s"
|
324 |
msgstr ""
|
325 |
|
326 |
#: inc/class-create-archive.php:459
|
327 |
-
#, php-format
|
328 |
msgid "File name \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
329 |
msgstr ""
|
330 |
|
331 |
#: inc/class-create-archive.php:462
|
332 |
-
#, php-format
|
333 |
msgid "File path \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
334 |
msgstr ""
|
335 |
|
336 |
#: inc/class-create-archive.php:474
|
337 |
-
#, php-format
|
338 |
msgid "Cannot open source file %s for archiving"
|
339 |
msgstr ""
|
340 |
|
@@ -344,204 +335,233 @@ msgid "Unknown"
|
|
344 |
msgstr ""
|
345 |
|
346 |
#: inc/class-create-archive.php:570
|
347 |
-
#, php-format
|
348 |
msgid "Folder name \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
349 |
msgstr ""
|
350 |
|
351 |
#: inc/class-create-archive.php:573
|
352 |
-
#, php-format
|
353 |
msgid "Folder path \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
354 |
msgstr ""
|
355 |
|
356 |
#: inc/class-create-archive.php:654
|
357 |
-
|
358 |
-
|
|
|
|
|
359 |
msgstr ""
|
360 |
|
361 |
#: inc/class-cron.php:69
|
362 |
msgid "Aborted, because no progress for one hour!"
|
363 |
msgstr ""
|
364 |
|
365 |
-
#: inc/class-
|
366 |
-
#: inc/
|
367 |
-
|
|
|
|
|
|
|
|
|
|
|
368 |
msgid "Dropbox API: %s"
|
369 |
msgstr ""
|
370 |
|
371 |
-
#: inc/class-destination-dropbox.php:
|
372 |
#: inc/pro/class-destination-gdrive.php:51
|
373 |
msgid "Login"
|
374 |
msgstr ""
|
375 |
|
376 |
-
#: inc/class-destination-dropbox.php:
|
377 |
#: inc/class-destination-sugarsync.php:43
|
378 |
msgid "Authentication"
|
379 |
msgstr ""
|
380 |
|
381 |
-
#: inc/class-destination-dropbox.php:
|
382 |
#: inc/pro/class-destination-gdrive.php:57
|
383 |
-
#: inc/pro/class-destination-gdrive.php:
|
384 |
msgid "Not authenticated!"
|
385 |
msgstr ""
|
386 |
|
387 |
-
#: inc/class-destination-dropbox.php:
|
388 |
-
#: inc/pro/class-destination-dropbox.php:
|
389 |
msgid "Create Account"
|
390 |
msgstr ""
|
391 |
|
392 |
-
#: inc/class-destination-dropbox.php:
|
393 |
-
#: inc/pro/class-destination-dropbox.php:
|
394 |
#: inc/pro/class-destination-gdrive.php:59
|
395 |
-
#: inc/pro/class-destination-gdrive.php:
|
396 |
#: inc/pro/class-destination-sugarsync.php:31
|
397 |
msgid "Authenticated!"
|
398 |
msgstr ""
|
399 |
|
400 |
-
#: inc/class-destination-dropbox.php:
|
401 |
msgid "Delete Dropbox Authentication"
|
402 |
msgstr ""
|
403 |
|
404 |
-
#: inc/class-destination-dropbox.php:
|
405 |
msgid "App Access to Dropbox"
|
406 |
msgstr ""
|
407 |
|
408 |
-
#: inc/class-destination-dropbox.php:
|
409 |
msgid "Get Dropbox App auth code"
|
410 |
msgstr ""
|
411 |
|
412 |
-
#: inc/class-destination-dropbox.php:
|
413 |
-
msgid "
|
|
|
|
|
|
|
|
|
414 |
msgstr ""
|
415 |
|
416 |
-
#: inc/class-destination-dropbox.php:
|
417 |
-
msgid " OR "
|
418 |
msgstr ""
|
419 |
|
420 |
-
#: inc/class-destination-dropbox.php:
|
421 |
msgid "Full Access to Dropbox"
|
422 |
msgstr ""
|
423 |
|
424 |
-
#: inc/class-destination-dropbox.php:
|
425 |
msgid "Get full Dropbox auth code "
|
426 |
msgstr ""
|
427 |
|
428 |
-
#: inc/class-destination-dropbox.php:
|
429 |
-
msgid "
|
|
|
|
|
|
|
|
|
430 |
msgstr ""
|
431 |
|
432 |
-
#: inc/class-destination-dropbox.php:
|
433 |
#: inc/class-destination-ftp.php:49 inc/class-destination-msazure.php:66
|
434 |
#: inc/class-destination-rsc.php:95 inc/class-destination-sugarsync.php:81
|
435 |
#: inc/pro/class-destination-gdrive.php:68
|
436 |
msgid "Backup settings"
|
437 |
msgstr ""
|
438 |
|
439 |
-
#: inc/class-destination-dropbox.php:
|
440 |
msgid "Destination Folder"
|
441 |
msgstr ""
|
442 |
|
443 |
-
#: inc/class-destination-dropbox.php:
|
444 |
-
msgid "
|
|
|
|
|
|
|
|
|
445 |
msgstr ""
|
446 |
|
447 |
-
#: inc/class-destination-dropbox.php:
|
448 |
#: inc/class-destination-ftp.php:59 inc/class-destination-sugarsync.php:91
|
449 |
#: inc/pro/class-destination-gdrive.php:81
|
450 |
msgid "File Deletion"
|
451 |
msgstr ""
|
452 |
|
453 |
-
#: inc/class-destination-dropbox.php:
|
454 |
#: inc/class-destination-ftp.php:66 inc/class-destination-msazure.php:83
|
455 |
-
#: inc/class-destination-rsc.php:112 inc/class-destination-s3.php:
|
456 |
#: inc/class-destination-sugarsync.php:98
|
457 |
-
#: inc/pro/class-destination-dropbox.php:
|
458 |
#: inc/pro/class-destination-folder.php:43
|
459 |
#: inc/pro/class-destination-gdrive.php:90
|
460 |
-
#: inc/pro/class-destination-gdrive.php:
|
461 |
#: inc/pro/class-destination-msazure.php:45
|
462 |
-
#: inc/pro/class-destination-rsc.php:65 inc/pro/class-destination-s3.php:
|
463 |
msgid "Number of files to keep in folder."
|
464 |
msgstr ""
|
465 |
|
466 |
-
#: inc/class-destination-dropbox.php:
|
467 |
-
#: inc/class-destination-ftp.php:
|
468 |
-
#: inc/class-destination-rsc.php:
|
469 |
-
#: inc/class-destination-sugarsync.php:
|
470 |
-
#: inc/pro/class-destination-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
471 |
#: inc/pro/class-destination-folder.php:48
|
472 |
#: inc/pro/class-destination-ftp.php:44
|
473 |
-
#: inc/pro/class-destination-gdrive.php:
|
474 |
-
#: inc/pro/class-destination-gdrive.php:
|
475 |
#: inc/pro/class-destination-msazure.php:56
|
476 |
-
#: inc/pro/class-destination-rsc.php:70 inc/pro/class-destination-s3.php:
|
477 |
#: inc/pro/class-destination-sugarsync.php:65
|
478 |
msgid "Do not delete files while syncing to destination!"
|
479 |
msgstr ""
|
480 |
|
481 |
-
#: inc/class-destination-dropbox.php:
|
482 |
-
#, php-format
|
483 |
msgid "%d. Try to send backup file to Dropbox …"
|
484 |
msgstr ""
|
485 |
|
486 |
-
#: inc/class-destination-dropbox.php:
|
487 |
-
#: inc/pro/class-destination-dropbox.php:
|
488 |
-
#, php-format
|
489 |
msgid "Authenticated with Dropbox of user: %s"
|
490 |
msgstr ""
|
491 |
|
492 |
-
#: inc/class-destination-dropbox.php:
|
493 |
-
#: inc/pro/class-destination-dropbox.php:
|
494 |
-
#, php-format
|
495 |
msgid "%s available on your Dropbox"
|
496 |
msgstr ""
|
497 |
|
498 |
-
#: inc/class-destination-dropbox.php:
|
499 |
-
#: inc/pro/class-destination-dropbox.php:
|
500 |
msgid "Not Authenticated with Dropbox!"
|
501 |
msgstr ""
|
502 |
|
503 |
-
#: inc/class-destination-dropbox.php:
|
504 |
msgid "Uploading to Dropbox …"
|
505 |
msgstr ""
|
506 |
|
507 |
-
#: inc/class-destination-dropbox.php:
|
508 |
-
#: inc/class-destination-sugarsync.php:
|
509 |
-
#: inc/pro/class-destination-gdrive.php:
|
510 |
-
#, php-format
|
511 |
msgid "Backup transferred to %s"
|
512 |
msgstr ""
|
513 |
|
514 |
-
#: inc/class-destination-dropbox.php:
|
515 |
-
#: inc/pro/class-destination-gdrive.php:
|
516 |
msgid "Uploaded file size and local file size don't match."
|
517 |
msgstr ""
|
518 |
|
519 |
-
#: inc/class-destination-dropbox.php:
|
520 |
-
#: inc/pro/class-destination-gdrive.php:
|
521 |
-
#: inc/pro/class-destination-glacier.php:
|
522 |
-
#, php-format
|
523 |
msgid "Error transfering backup to %s."
|
524 |
msgstr ""
|
525 |
|
526 |
-
#: inc/class-destination-dropbox.php:
|
527 |
-
#, php-format
|
528 |
-
msgid "Error while deleting file from Dropbox: %s"
|
529 |
-
msgstr ""
|
530 |
-
|
531 |
-
#: inc/class-destination-dropbox.php:358
|
532 |
-
#, php-format
|
533 |
msgid "One file deleted from Dropbox"
|
534 |
msgid_plural "%d files deleted on Dropbox"
|
535 |
msgstr[0] ""
|
536 |
msgstr[1] ""
|
537 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
538 |
#: inc/class-destination-email.php:38 inc/pro/class-destination-email.php:16
|
539 |
#: inc/pro/class-destination-email.php:18
|
540 |
msgid "Email address"
|
541 |
msgstr ""
|
542 |
|
543 |
#: inc/class-destination-email.php:41
|
544 |
-
msgid "To email address"
|
545 |
msgstr ""
|
546 |
|
547 |
#: inc/class-destination-email.php:47 inc/class-destination-email.php:49
|
@@ -614,7 +634,7 @@ msgstr ""
|
|
614 |
#: inc/class-destination-email.php:106 inc/class-jobtype-dbdump.php:67
|
615 |
#: inc/class-jobtype-dbdump.php:103 inc/class-jobtype-wpexp.php:73
|
616 |
#: inc/class-jobtype-wpplugin.php:57 inc/class-page-backwpup.php:329
|
617 |
-
#: inc/class-page-backwpup.php:
|
618 |
#: inc/pro/class-jobtype-dbdump.php:157 inc/pro/class-jobtype-dbdump.php:205
|
619 |
msgid "none"
|
620 |
msgstr ""
|
@@ -636,7 +656,6 @@ msgid "SMTP password"
|
|
636 |
msgstr ""
|
637 |
|
638 |
#: inc/class-destination-email.php:199
|
639 |
-
#, php-format
|
640 |
msgid "%d. Try to send backup with email …"
|
641 |
msgstr ""
|
642 |
|
@@ -645,17 +664,14 @@ msgid "Backup archive too big to be sent by email!"
|
|
645 |
msgstr ""
|
646 |
|
647 |
#: inc/class-destination-email.php:211
|
648 |
-
#, php-format
|
649 |
msgid "Sending email to %s…"
|
650 |
msgstr ""
|
651 |
|
652 |
#: inc/class-destination-email.php:289
|
653 |
-
#, php-format
|
654 |
msgid "BackWPup archive from %1$s: %2$s"
|
655 |
msgstr ""
|
656 |
|
657 |
#: inc/class-destination-email.php:292
|
658 |
-
#, php-format
|
659 |
msgid "Backup archive: %s"
|
660 |
msgstr ""
|
661 |
|
@@ -672,15 +688,16 @@ msgid "BackWPup archive sending TEST Message"
|
|
672 |
msgstr ""
|
673 |
|
674 |
#: inc/class-destination-email.php:417
|
675 |
-
msgid "
|
|
|
|
|
676 |
msgstr ""
|
677 |
|
678 |
#: inc/class-destination-folder.php:33
|
679 |
msgid "Folder to store backups in"
|
680 |
msgstr ""
|
681 |
|
682 |
-
#: inc/class-destination-folder.php:
|
683 |
-
#, php-format
|
684 |
msgid "One backup file deleted"
|
685 |
msgid_plural "%d backup files deleted"
|
686 |
msgstr[0] ""
|
@@ -706,151 +723,137 @@ msgstr ""
|
|
706 |
msgid "Folder to store files in"
|
707 |
msgstr ""
|
708 |
|
709 |
-
#: inc/class-destination-ftp.php:
|
710 |
msgid "FTP specific settings"
|
711 |
msgstr ""
|
712 |
|
713 |
-
#: inc/class-destination-ftp.php:
|
714 |
msgid "Timeout for FTP connection"
|
715 |
msgstr ""
|
716 |
|
717 |
-
#: inc/class-destination-ftp.php:
|
718 |
-
#: inc/class-page-settings.php:
|
719 |
msgid "seconds"
|
720 |
msgstr ""
|
721 |
|
722 |
-
#: inc/class-destination-ftp.php:
|
723 |
msgid "SSL-FTP connection"
|
724 |
msgstr ""
|
725 |
|
726 |
-
#: inc/class-destination-ftp.php:
|
727 |
msgid "Use explicit SSL-FTP connection."
|
728 |
msgstr ""
|
729 |
|
730 |
-
#: inc/class-destination-ftp.php:
|
731 |
msgid "FTP Passive Mode"
|
732 |
msgstr ""
|
733 |
|
734 |
-
#: inc/class-destination-ftp.php:
|
735 |
msgid "Use FTP Passive Mode."
|
736 |
msgstr ""
|
737 |
|
738 |
-
#: inc/class-destination-ftp.php:
|
739 |
msgid "FTP: Login failure!"
|
740 |
msgstr ""
|
741 |
|
742 |
-
#: inc/class-destination-ftp.php:
|
743 |
-
#, php-format
|
744 |
msgid "%d. Try to send backup file to an FTP server …"
|
745 |
msgstr ""
|
746 |
|
747 |
-
#: inc/class-destination-ftp.php:
|
748 |
-
#, php-format
|
749 |
msgid "Connected via explicit SSL-FTP to server: %s"
|
750 |
msgstr ""
|
751 |
|
752 |
-
#: inc/class-destination-ftp.php:
|
753 |
-
#, php-format
|
754 |
msgid "Cannot connect via explicit SSL-FTP to server: %s"
|
755 |
msgstr ""
|
756 |
|
757 |
-
#: inc/class-destination-ftp.php:
|
758 |
msgid "PHP function to connect with explicit SSL-FTP to server does not exist!"
|
759 |
msgstr ""
|
760 |
|
761 |
-
#: inc/class-destination-ftp.php:
|
762 |
-
#, php-format
|
763 |
msgid "Connected to FTP server: %s"
|
764 |
msgstr ""
|
765 |
|
766 |
-
#: inc/class-destination-ftp.php:
|
767 |
-
#, php-format
|
768 |
msgid "Cannot connect to FTP server: %s"
|
769 |
msgstr ""
|
770 |
|
771 |
-
#: inc/class-destination-ftp.php:
|
772 |
-
#: inc/class-destination-ftp.php:
|
773 |
-
#, php-format
|
774 |
msgid "FTP client command: %s"
|
775 |
msgstr ""
|
776 |
|
777 |
-
#: inc/class-destination-ftp.php:
|
778 |
-
#, php-format
|
779 |
msgid "FTP server response: %s"
|
780 |
msgstr ""
|
781 |
|
782 |
-
#: inc/class-destination-ftp.php:
|
783 |
-
#: inc/class-destination-ftp.php:
|
784 |
-
#: inc/class-destination-ftp.php:
|
785 |
-
#: inc/class-destination-ftp.php:
|
786 |
-
#: inc/class-destination-ftp.php:
|
787 |
-
#, php-format
|
788 |
msgid "FTP server reply: %s"
|
789 |
msgstr ""
|
790 |
|
791 |
-
#: inc/class-destination-ftp.php:
|
792 |
msgid "Error getting SYSTYPE"
|
793 |
msgstr ""
|
794 |
|
795 |
-
#: inc/class-destination-ftp.php:
|
796 |
-
#, php-format
|
797 |
msgid "FTP Folder \"%s\" created!"
|
798 |
msgstr ""
|
799 |
|
800 |
-
#: inc/class-destination-ftp.php:
|
801 |
-
#, php-format
|
802 |
msgid "FTP Folder \"%s\" cannot be created!"
|
803 |
msgstr ""
|
804 |
|
805 |
-
#: inc/class-destination-ftp.php:
|
806 |
-
#, php-format
|
807 |
msgid "FTP current folder is: %s"
|
808 |
msgstr ""
|
809 |
|
810 |
-
#: inc/class-destination-ftp.php:
|
811 |
msgid "Entering passive mode"
|
812 |
msgstr ""
|
813 |
|
814 |
-
#: inc/class-destination-ftp.php:
|
815 |
msgid "Cannot enter passive mode"
|
816 |
msgstr ""
|
817 |
|
818 |
-
#: inc/class-destination-ftp.php:
|
819 |
msgid "Entering normal mode"
|
820 |
msgstr ""
|
821 |
|
822 |
-
#: inc/class-destination-ftp.php:
|
823 |
msgid "Cannot enter normal mode"
|
824 |
msgstr ""
|
825 |
|
826 |
-
#: inc/class-destination-ftp.php:
|
827 |
msgid "Starting upload to FTP  …"
|
828 |
msgstr ""
|
829 |
|
830 |
-
#: inc/class-destination-ftp.php:
|
831 |
msgid "Cannot transfer backup to FTP server!"
|
832 |
msgstr ""
|
833 |
|
834 |
-
#: inc/class-destination-ftp.php:
|
835 |
-
#, php-format
|
836 |
msgid "Backup transferred to FTP server: %s"
|
837 |
msgstr ""
|
838 |
|
839 |
-
#: inc/class-destination-ftp.php:
|
840 |
-
#: inc/class-destination-rsc.php:
|
841 |
-
#: inc/class-destination-s3.php:
|
842 |
-
#: inc/pro/class-destination-glacier.php:
|
843 |
#: inc/pro/class-destination-rsc.php:226 inc/pro/class-destination-rsc.php:259
|
844 |
msgid "Can not open source file for transfer."
|
845 |
msgstr ""
|
846 |
|
847 |
-
#: inc/class-destination-ftp.php:
|
848 |
-
#, php-format
|
849 |
msgid "Cannot delete \"%s\" on FTP server!"
|
850 |
msgstr ""
|
851 |
|
852 |
-
#: inc/class-destination-ftp.php:
|
853 |
-
#, php-format
|
854 |
msgid "One file deleted on FTP server"
|
855 |
msgid_plural "%d files deleted on FTP server"
|
856 |
msgstr[0] ""
|
@@ -885,66 +888,59 @@ msgid "Folder in container"
|
|
885 |
msgstr ""
|
886 |
|
887 |
#: inc/class-destination-msazure.php:76 inc/class-destination-rsc.php:105
|
888 |
-
#: inc/class-destination-s3.php:
|
889 |
msgid "File deletion"
|
890 |
msgstr ""
|
891 |
|
892 |
-
#: inc/class-destination-msazure.php:
|
893 |
#: inc/pro/class-destination-msazure.php:99
|
894 |
-
#, php-format
|
895 |
msgid "MS Azure container \"%s\" created."
|
896 |
msgstr ""
|
897 |
|
898 |
-
#: inc/class-destination-msazure.php:
|
899 |
#: inc/pro/class-destination-msazure.php:102
|
900 |
-
#, php-format
|
901 |
msgid "MS Azure container create: %s"
|
902 |
msgstr ""
|
903 |
|
904 |
-
#: inc/class-destination-msazure.php:
|
905 |
-
#, php-format
|
906 |
msgid "%d. Try sending backup to a Microsoft Azure (Blob) …"
|
907 |
msgstr ""
|
908 |
|
909 |
-
#: inc/class-destination-msazure.php:
|
910 |
#: inc/pro/class-destination-msazure.php:144
|
911 |
-
#, php-format
|
912 |
msgid "MS Azure container \"%s\" does not exist!"
|
913 |
msgstr ""
|
914 |
|
915 |
-
#: inc/class-destination-msazure.php:
|
916 |
#: inc/pro/class-destination-msazure.php:148
|
917 |
-
#, php-format
|
918 |
msgid "Connected to MS Azure container \"%s\"."
|
919 |
msgstr ""
|
920 |
|
921 |
-
#: inc/class-destination-msazure.php:
|
922 |
msgid "Starting upload to MS Azure …"
|
923 |
msgstr ""
|
924 |
|
925 |
-
#: inc/class-destination-msazure.php:
|
926 |
#: inc/pro/class-destination-msazure.php:233
|
927 |
-
#, php-format
|
928 |
msgid "Microsoft Azure API: %s"
|
929 |
msgstr ""
|
930 |
|
931 |
-
#: inc/class-destination-msazure.php:
|
932 |
-
#, php-format
|
933 |
msgid "One file deleted on Microsoft Azure container."
|
934 |
msgid_plural "%d files deleted on Microsoft Azure container."
|
935 |
msgstr[0] ""
|
936 |
msgstr[1] ""
|
937 |
|
938 |
-
#: inc/class-destination-msazure.php:
|
939 |
msgid "Missing account name!"
|
940 |
msgstr ""
|
941 |
|
942 |
-
#: inc/class-destination-msazure.php:
|
943 |
-
#: inc/pro/class-destination-glacier.php:
|
944 |
msgid "Missing access key!"
|
945 |
msgstr ""
|
946 |
|
947 |
-
#: inc/class-destination-msazure.php:
|
948 |
msgid "No container found!"
|
949 |
msgstr ""
|
950 |
|
@@ -989,61 +985,56 @@ msgstr ""
|
|
989 |
msgid "Hong Kong (HKG)"
|
990 |
msgstr ""
|
991 |
|
992 |
-
#: inc/class-destination-rsc.php:99 inc/class-destination-s3.php:
|
993 |
msgid "Folder in bucket"
|
994 |
msgstr ""
|
995 |
|
996 |
-
#: inc/class-destination-rsc.php:
|
997 |
-
#, php-format
|
998 |
msgid "Rackspace Cloud container \"%s\" created."
|
999 |
msgstr ""
|
1000 |
|
1001 |
-
#: inc/class-destination-rsc.php:
|
1002 |
-
#: inc/class-destination-rsc.php:
|
1003 |
#: inc/pro/class-destination-rsc.php:120 inc/pro/class-destination-rsc.php:170
|
1004 |
#: inc/pro/class-destination-rsc.php:290
|
1005 |
-
#, php-format
|
1006 |
msgid "Rackspace Cloud API: %s"
|
1007 |
msgstr ""
|
1008 |
|
1009 |
-
#: inc/class-destination-rsc.php:
|
1010 |
-
#, php-format
|
1011 |
msgid "%d. Trying to send backup file to Rackspace cloud …"
|
1012 |
msgstr ""
|
1013 |
|
1014 |
-
#: inc/class-destination-rsc.php:
|
1015 |
-
#, php-format
|
1016 |
msgid "Connected to Rackspace cloud files container %s"
|
1017 |
msgstr ""
|
1018 |
|
1019 |
-
#: inc/class-destination-rsc.php:
|
1020 |
msgid "Upload to Rackspace cloud started …"
|
1021 |
msgstr ""
|
1022 |
|
1023 |
-
#: inc/class-destination-rsc.php:
|
1024 |
msgid "Backup File transferred to RSC://"
|
1025 |
msgstr ""
|
1026 |
|
1027 |
-
#: inc/class-destination-rsc.php:
|
1028 |
msgid "Cannot transfer backup to Rackspace cloud."
|
1029 |
msgstr ""
|
1030 |
|
1031 |
-
#: inc/class-destination-rsc.php:
|
1032 |
-
#, php-format
|
1033 |
msgid "One file deleted on Rackspace cloud container."
|
1034 |
msgid_plural "%d files deleted on Rackspace cloud container."
|
1035 |
msgstr[0] ""
|
1036 |
msgstr[1] ""
|
1037 |
|
1038 |
-
#: inc/class-destination-rsc.php:
|
1039 |
msgid "Missing username!"
|
1040 |
msgstr ""
|
1041 |
|
1042 |
-
#: inc/class-destination-rsc.php:
|
1043 |
msgid "Missing API Key!"
|
1044 |
msgstr ""
|
1045 |
|
1046 |
-
#: inc/class-destination-rsc.php:
|
1047 |
msgid "A container could not be found!"
|
1048 |
msgstr ""
|
1049 |
|
@@ -1119,39 +1110,35 @@ msgstr ""
|
|
1119 |
msgid "Dream Host Cloud Storage"
|
1120 |
msgstr ""
|
1121 |
|
1122 |
-
#: inc/class-destination-s3.php:
|
1123 |
-
msgid "GreenQloud Storage Qloud"
|
1124 |
-
msgstr ""
|
1125 |
-
|
1126 |
-
#: inc/class-destination-s3.php:55
|
1127 |
msgid "Or a S3 Server URL"
|
1128 |
msgstr ""
|
1129 |
|
1130 |
-
#: inc/class-destination-s3.php:
|
1131 |
msgid "S3 Access Keys"
|
1132 |
msgstr ""
|
1133 |
|
1134 |
-
#: inc/class-destination-s3.php:
|
1135 |
msgid "Access Key"
|
1136 |
msgstr ""
|
1137 |
|
1138 |
-
#: inc/class-destination-s3.php:
|
1139 |
msgid "Secret Key"
|
1140 |
msgstr ""
|
1141 |
|
1142 |
-
#: inc/class-destination-s3.php:
|
1143 |
msgid "S3 Bucket"
|
1144 |
msgstr ""
|
1145 |
|
1146 |
-
#: inc/class-destination-s3.php:
|
1147 |
msgid "Bucket selection"
|
1148 |
msgstr ""
|
1149 |
|
1150 |
-
#: inc/class-destination-s3.php:
|
1151 |
msgid "Create a new bucket"
|
1152 |
msgstr ""
|
1153 |
|
1154 |
-
#: inc/class-destination-s3.php:
|
1155 |
msgid "S3 Backup settings"
|
1156 |
msgstr ""
|
1157 |
|
@@ -1164,7 +1151,10 @@ msgid "Use multipart upload for uploading a file"
|
|
1164 |
msgstr ""
|
1165 |
|
1166 |
#: inc/class-destination-s3.php:137
|
1167 |
-
msgid "
|
|
|
|
|
|
|
1168 |
msgstr ""
|
1169 |
|
1170 |
#: inc/class-destination-s3.php:143
|
@@ -1195,81 +1185,69 @@ msgstr ""
|
|
1195 |
msgid "Save files encrypted (AES256) on server."
|
1196 |
msgstr ""
|
1197 |
|
1198 |
-
#: inc/class-destination-s3.php:
|
1199 |
msgid "Missing secret access key!"
|
1200 |
msgstr ""
|
1201 |
|
1202 |
-
#: inc/class-destination-s3.php:
|
1203 |
msgid "No bucket found!"
|
1204 |
msgstr ""
|
1205 |
|
1206 |
-
#: inc/class-destination-s3.php:
|
1207 |
-
#, php-format
|
1208 |
msgid "Bucket %1$s created."
|
1209 |
msgstr ""
|
1210 |
|
1211 |
-
#: inc/class-destination-s3.php:
|
1212 |
-
#, php-format
|
1213 |
msgid " %s is not a valid bucket name."
|
1214 |
msgstr ""
|
1215 |
|
1216 |
-
#: inc/class-destination-s3.php:
|
1217 |
-
#: inc/class-destination-s3.php:
|
1218 |
-
#: inc/class-destination-s3.php:
|
1219 |
-
#, php-format
|
1220 |
msgid "S3 Service API: %s"
|
1221 |
msgstr ""
|
1222 |
|
1223 |
-
#: inc/class-destination-s3.php:
|
1224 |
-
#, php-format
|
1225 |
msgid "%d. Trying to send backup file to S3 Service …"
|
1226 |
msgstr ""
|
1227 |
|
1228 |
-
#: inc/class-destination-s3.php:
|
1229 |
-
#, php-format
|
1230 |
msgid "Connected to S3 Bucket \"%1$s\" in %2$s"
|
1231 |
msgstr ""
|
1232 |
|
1233 |
-
#: inc/class-destination-s3.php:
|
1234 |
-
#, php-format
|
1235 |
msgid "S3 Bucket \"%s\" does not exist!"
|
1236 |
msgstr ""
|
1237 |
|
1238 |
-
#: inc/class-destination-s3.php:
|
1239 |
msgid "Checking for not aborted multipart Uploads …"
|
1240 |
msgstr ""
|
1241 |
|
1242 |
-
#: inc/class-destination-s3.php:
|
1243 |
-
#, php-format
|
1244 |
msgid "Upload for %s aborted."
|
1245 |
msgstr ""
|
1246 |
|
1247 |
-
#: inc/class-destination-s3.php:
|
1248 |
msgid "Starting upload to S3 Service …"
|
1249 |
msgstr ""
|
1250 |
|
1251 |
-
#: inc/class-destination-s3.php:
|
1252 |
-
#, php-format
|
1253 |
msgid "Backup transferred to %s."
|
1254 |
msgstr ""
|
1255 |
|
1256 |
-
#: inc/class-destination-s3.php:
|
1257 |
-
#, php-format
|
1258 |
msgid "Cannot transfer backup to S3! (%1$d) %2$s"
|
1259 |
msgstr ""
|
1260 |
|
1261 |
-
#: inc/class-destination-s3.php:
|
1262 |
-
#, php-format
|
1263 |
msgid "Storage Class: %s"
|
1264 |
msgstr ""
|
1265 |
|
1266 |
-
#: inc/class-destination-s3.php:
|
1267 |
-
#, php-format
|
1268 |
msgid "Cannot delete backup from %s."
|
1269 |
msgstr ""
|
1270 |
|
1271 |
-
#: inc/class-destination-s3.php:
|
1272 |
-
#, php-format
|
1273 |
msgid "One file deleted on S3 Bucket."
|
1274 |
msgid_plural "%d files deleted on S3 Bucket"
|
1275 |
msgstr[0] ""
|
@@ -1291,19 +1269,19 @@ msgid "Password:"
|
|
1291 |
msgstr ""
|
1292 |
|
1293 |
#: inc/class-destination-sugarsync.php:37
|
1294 |
-
#: inc/class-destination-sugarsync.php:
|
1295 |
msgid "Authenticate with Sugarsync!"
|
1296 |
msgstr ""
|
1297 |
|
1298 |
#: inc/class-destination-sugarsync.php:38
|
1299 |
-
#: inc/class-destination-sugarsync.php:
|
1300 |
#: inc/pro/class-destination-sugarsync.php:26
|
1301 |
#: inc/pro/class-destination-sugarsync.php:98
|
1302 |
msgid "Create Sugarsync account"
|
1303 |
msgstr ""
|
1304 |
|
1305 |
#: inc/class-destination-sugarsync.php:46
|
1306 |
-
#: inc/class-destination-sugarsync.php:
|
1307 |
#: inc/pro/class-destination-sugarsync.php:32
|
1308 |
#: inc/pro/class-destination-sugarsync.php:94
|
1309 |
msgid "Delete Sugarsync authentication!"
|
@@ -1326,49 +1304,42 @@ msgstr ""
|
|
1326 |
msgid "Folder in root"
|
1327 |
msgstr ""
|
1328 |
|
1329 |
-
#: inc/class-destination-sugarsync.php:
|
1330 |
-
#, php-format
|
1331 |
msgid "%d. Try to send backup to SugarSync …"
|
1332 |
msgstr ""
|
1333 |
|
1334 |
-
#: inc/class-destination-sugarsync.php:
|
1335 |
-
#, php-format
|
1336 |
msgid "Authenticated to SugarSync with nickname %s"
|
1337 |
msgstr ""
|
1338 |
|
1339 |
-
#: inc/class-destination-sugarsync.php:
|
1340 |
-
#, php-format
|
1341 |
msgctxt "Available space on SugarSync"
|
1342 |
msgid "Not enough disk space available on SugarSync. Available: %s."
|
1343 |
msgstr ""
|
1344 |
|
1345 |
-
#: inc/class-destination-sugarsync.php:
|
1346 |
-
#, php-format
|
1347 |
msgid "%s available at SugarSync"
|
1348 |
msgstr ""
|
1349 |
|
1350 |
-
#: inc/class-destination-sugarsync.php:
|
1351 |
msgid "Starting upload to SugarSync …"
|
1352 |
msgstr ""
|
1353 |
|
1354 |
-
#: inc/class-destination-sugarsync.php:
|
1355 |
msgid "Cannot transfer backup to SugarSync!"
|
1356 |
msgstr ""
|
1357 |
|
1358 |
-
#: inc/class-destination-sugarsync.php:
|
1359 |
-
#, php-format
|
1360 |
msgid "One file deleted on SugarSync folder"
|
1361 |
msgid_plural "%d files deleted on SugarSync folder"
|
1362 |
msgstr[0] ""
|
1363 |
msgstr[1] ""
|
1364 |
|
1365 |
-
#: inc/class-destination-sugarsync.php:
|
1366 |
-
#, php-format
|
1367 |
msgid "SugarSync API: %s"
|
1368 |
msgstr ""
|
1369 |
|
1370 |
#: inc/class-easycron.php:179
|
1371 |
-
#, php-format
|
1372 |
msgid "EasyCron.com API returns (%s): %s"
|
1373 |
msgstr ""
|
1374 |
|
@@ -1377,7 +1348,10 @@ msgid "EasyCron"
|
|
1377 |
msgstr ""
|
1378 |
|
1379 |
#: inc/class-easycron.php:189
|
1380 |
-
msgid "
|
|
|
|
|
|
|
1381 |
msgstr ""
|
1382 |
|
1383 |
#: inc/class-easycron.php:192
|
@@ -1389,31 +1363,31 @@ msgid "Trigger WordPress Cron:"
|
|
1389 |
msgstr ""
|
1390 |
|
1391 |
#: inc/class-easycron.php:203
|
1392 |
-
msgid "
|
|
|
|
|
1393 |
msgstr ""
|
1394 |
|
1395 |
-
#: inc/class-file.php:
|
1396 |
-
#, php-format
|
1397 |
msgid "Folder %1$s not allowed, please use another folder."
|
1398 |
msgstr ""
|
1399 |
|
1400 |
-
#: inc/class-file.php:
|
1401 |
-
#, php-format
|
1402 |
msgid "Folder %1$s is not in open basedir, please use another folder."
|
1403 |
msgstr ""
|
1404 |
|
1405 |
-
#: inc/class-file.php:
|
1406 |
-
#, php-format
|
1407 |
msgid "Cannot create folder: %1$s"
|
1408 |
msgstr ""
|
1409 |
|
1410 |
-
#: inc/class-file.php:
|
1411 |
-
#, php-format
|
1412 |
msgid "Folder \"%1$s\" is not writable"
|
1413 |
msgstr ""
|
1414 |
|
1415 |
-
#: inc/class-file.php:
|
1416 |
-
msgid "
|
|
|
|
|
1417 |
msgstr ""
|
1418 |
|
1419 |
#: inc/class-help.php:15
|
@@ -1421,13 +1395,16 @@ msgid "Plugin Info"
|
|
1421 |
msgstr ""
|
1422 |
|
1423 |
#: inc/class-help.php:17
|
1424 |
-
#, php-format
|
1425 |
msgctxt "Plugin name and link; Plugin Version"
|
1426 |
-
msgid "
|
|
|
|
|
1427 |
msgstr ""
|
1428 |
|
1429 |
#: inc/class-help.php:18
|
1430 |
-
msgid "
|
|
|
|
|
1431 |
msgstr ""
|
1432 |
|
1433 |
#: inc/class-help.php:21
|
@@ -1475,18 +1452,15 @@ msgid "End of Job"
|
|
1475 |
msgstr ""
|
1476 |
|
1477 |
#: inc/class-job.php:377
|
1478 |
-
#, php-format
|
1479 |
msgid "BackWPup log for %1$s from %2$s at %3$s"
|
1480 |
msgstr ""
|
1481 |
|
1482 |
#: inc/class-job.php:394
|
1483 |
-
#, php-format
|
1484 |
msgctxt "Plugin name; Plugin Version; plugin url"
|
1485 |
msgid "[INFO] %1$s %2$s; A project of Inpsyde GmbH"
|
1486 |
msgstr ""
|
1487 |
|
1488 |
#: inc/class-job.php:395
|
1489 |
-
#, php-format
|
1490 |
msgctxt "WordPress Version; Blog url"
|
1491 |
msgid "[INFO] WordPress %1$s on %2$s"
|
1492 |
msgstr ""
|
@@ -1504,17 +1478,14 @@ msgid "(translated)"
|
|
1504 |
msgstr ""
|
1505 |
|
1506 |
#: inc/class-job.php:404
|
1507 |
-
#, php-format
|
1508 |
msgid "[INFO] Log Level: %1$s %2$s"
|
1509 |
msgstr ""
|
1510 |
|
1511 |
#: inc/class-job.php:409
|
1512 |
-
#, php-format
|
1513 |
msgid "[INFO] BackWPup job: %1$s"
|
1514 |
msgstr ""
|
1515 |
|
1516 |
#: inc/class-job.php:412
|
1517 |
-
#, php-format
|
1518 |
msgid "[INFO] Runs with user: %1$s (%2$d) "
|
1519 |
msgstr ""
|
1520 |
|
@@ -1524,7 +1495,6 @@ msgid "Not scheduled!"
|
|
1524 |
msgstr ""
|
1525 |
|
1526 |
#: inc/class-job.php:430 inc/class-job.php:440
|
1527 |
-
#, php-format
|
1528 |
msgid "[INFO] Cron: %s; Next: %s "
|
1529 |
msgstr ""
|
1530 |
|
@@ -1561,47 +1531,38 @@ msgid "[INFO] PHP ver.:"
|
|
1561 |
msgstr ""
|
1562 |
|
1563 |
#: inc/class-job.php:463
|
1564 |
-
#, php-format
|
1565 |
msgid "[INFO] Maximum PHP script execution time is %1$d seconds"
|
1566 |
msgstr ""
|
1567 |
|
1568 |
#: inc/class-job.php:467
|
1569 |
-
#, php-format
|
1570 |
msgid "[INFO] Script restart time is configured to %1$d seconds"
|
1571 |
msgstr ""
|
1572 |
|
1573 |
#: inc/class-job.php:470
|
1574 |
-
#, php-format
|
1575 |
msgid "[INFO] MySQL ver.: %s"
|
1576 |
msgstr ""
|
1577 |
|
1578 |
#: inc/class-job.php:472
|
1579 |
-
#, php-format
|
1580 |
msgid "[INFO] Web Server: %s"
|
1581 |
msgstr ""
|
1582 |
|
1583 |
#: inc/class-job.php:476
|
1584 |
-
#, php-format
|
1585 |
msgid "[INFO] curl ver.: %1$s; %2$s"
|
1586 |
msgstr ""
|
1587 |
|
1588 |
#: inc/class-job.php:478
|
1589 |
-
#, php-format
|
1590 |
msgid "[INFO] Temp folder is: %s"
|
1591 |
msgstr ""
|
1592 |
|
1593 |
#: inc/class-job.php:485
|
1594 |
-
#, php-format
|
1595 |
msgid "[INFO] Logfile is: %s"
|
1596 |
msgstr ""
|
1597 |
|
1598 |
#: inc/class-job.php:492
|
1599 |
-
#, php-format
|
1600 |
msgid "[INFO] Backup file is: %s"
|
1601 |
msgstr ""
|
1602 |
|
1603 |
#: inc/class-job.php:494
|
1604 |
-
#, php-format
|
1605 |
msgid "[INFO] Backup type is: %s"
|
1606 |
msgstr ""
|
1607 |
|
@@ -1610,289 +1571,315 @@ msgid "Could not write log file"
|
|
1610 |
msgstr ""
|
1611 |
|
1612 |
#: inc/class-job.php:514
|
1613 |
-
msgid "
|
|
|
1614 |
msgstr ""
|
1615 |
|
1616 |
-
#: inc/class-job.php:
|
1617 |
msgid "Cannot write progress to working file. Job will be aborted."
|
1618 |
msgstr ""
|
1619 |
|
1620 |
-
#: inc/class-job.php:
|
1621 |
msgid "WARNING:"
|
1622 |
msgstr ""
|
1623 |
|
1624 |
-
#: inc/class-job.php:
|
1625 |
msgid "ERROR:"
|
1626 |
msgstr ""
|
1627 |
|
1628 |
-
#: inc/class-job.php:
|
1629 |
msgid "DEPRECATED:"
|
1630 |
msgstr ""
|
1631 |
|
1632 |
-
#: inc/class-job.php:
|
1633 |
msgid "STRICT NOTICE:"
|
1634 |
msgstr ""
|
1635 |
|
1636 |
-
#: inc/class-job.php:
|
1637 |
msgid "RECOVERABLE ERROR:"
|
1638 |
msgstr ""
|
1639 |
|
1640 |
-
#: inc/class-job.php:
|
1641 |
msgid "Aborted by user!"
|
1642 |
msgstr ""
|
1643 |
|
1644 |
-
#: inc/class-job.php:
|
1645 |
-
#, php-format
|
1646 |
msgid "One old log deleted"
|
1647 |
msgid_plural "%d old logs deleted"
|
1648 |
msgstr[0] ""
|
1649 |
msgstr[1] ""
|
1650 |
|
1651 |
-
#: inc/class-job.php:
|
1652 |
-
|
1653 |
-
|
|
|
1654 |
msgstr ""
|
1655 |
|
1656 |
-
#: inc/class-job.php:
|
1657 |
-
|
1658 |
-
|
|
|
1659 |
msgstr ""
|
1660 |
|
1661 |
-
#: inc/class-job.php:
|
1662 |
-
#, php-format
|
1663 |
msgid "Job done in %s seconds."
|
1664 |
msgstr ""
|
1665 |
|
1666 |
-
#: inc/class-job.php:
|
1667 |
msgid "SUCCESSFUL"
|
1668 |
msgstr ""
|
1669 |
|
1670 |
-
#: inc/class-job.php:
|
1671 |
msgid "WARNING"
|
1672 |
msgstr ""
|
1673 |
|
1674 |
-
#: inc/class-job.php:
|
1675 |
msgid "ERROR"
|
1676 |
msgstr ""
|
1677 |
|
1678 |
-
#: inc/class-job.php:
|
1679 |
-
#, php-format
|
1680 |
msgid "[%3$s] BackWPup log %1$s: %2$s"
|
1681 |
msgstr ""
|
1682 |
|
1683 |
-
#: inc/class-job.php:
|
1684 |
-
#, php-format
|
1685 |
msgid "Restart after %1$d seconds."
|
1686 |
msgstr ""
|
1687 |
|
1688 |
-
#: inc/class-job.php:
|
1689 |
msgid "Restart after getting signal."
|
1690 |
msgstr ""
|
1691 |
|
1692 |
-
#: inc/class-job.php:
|
1693 |
msgid "Job restarts due to inactivity for more than 5 minutes."
|
1694 |
msgstr ""
|
1695 |
|
1696 |
-
#: inc/class-job.php:
|
1697 |
msgid "Step aborted: too many attempts!"
|
1698 |
msgstr ""
|
1699 |
|
1700 |
-
#: inc/class-job.php:
|
1701 |
-
#, php-format
|
1702 |
msgid "%d. Trying to create backup archive …"
|
1703 |
msgstr ""
|
1704 |
|
1705 |
-
#: inc/class-job.php:
|
1706 |
-
#, php-format
|
1707 |
msgctxt "Archive compression method"
|
1708 |
msgid "Compressing files as %s. Please be patient, this may take a moment."
|
1709 |
msgstr ""
|
1710 |
|
1711 |
-
#: inc/class-job.php:
|
1712 |
msgid "Adding Extra files to Archive"
|
1713 |
msgstr ""
|
1714 |
|
1715 |
-
#: inc/class-job.php:
|
1716 |
msgid "Cannot create backup archive correctly. Aborting creation."
|
1717 |
msgstr ""
|
1718 |
|
1719 |
-
#: inc/class-job.php:
|
1720 |
-
#, php-format
|
1721 |
msgid "Archiving Folder: %s"
|
1722 |
msgstr ""
|
1723 |
|
1724 |
-
#: inc/class-job.php:
|
1725 |
msgid "Backup archive created."
|
1726 |
msgstr ""
|
1727 |
|
1728 |
-
#: inc/class-job.php:
|
1729 |
-
msgid "
|
|
|
|
|
|
|
1730 |
msgstr ""
|
1731 |
|
1732 |
-
#: inc/class-job.php:
|
1733 |
-
#, php-format
|
1734 |
msgid "Archive size is %s."
|
1735 |
msgstr ""
|
1736 |
|
1737 |
-
#: inc/class-job.php:
|
1738 |
-
#, php-format
|
1739 |
msgid "%1$d Files with %2$s in Archive."
|
1740 |
msgstr ""
|
1741 |
|
1742 |
-
#: inc/class-job.php:
|
1743 |
-
#, php-format
|
1744 |
msgctxt "Folder name"
|
1745 |
-
msgid "Folder %s not
|
1746 |
msgstr ""
|
1747 |
|
1748 |
-
#: inc/class-job.php:
|
1749 |
-
#, php-format
|
1750 |
msgctxt "Folder name"
|
1751 |
-
msgid "Folder %s not readable"
|
1752 |
msgstr ""
|
1753 |
|
1754 |
-
#: inc/class-job.php:
|
1755 |
-
#, php-format
|
1756 |
msgid "Link \"%s\" not following."
|
1757 |
msgstr ""
|
1758 |
|
1759 |
-
#: inc/class-job.php:
|
1760 |
-
#, php-format
|
1761 |
msgid "File \"%s\" is not readable!"
|
1762 |
msgstr ""
|
1763 |
|
1764 |
-
#: inc/class-job.php:
|
1765 |
-
|
1766 |
-
|
|
|
1767 |
msgstr ""
|
1768 |
|
1769 |
-
#: inc/class-job.php:
|
1770 |
-
#, php-format
|
1771 |
msgid "%d. Trying to generate a manifest file …"
|
1772 |
msgstr ""
|
1773 |
|
1774 |
-
#: inc/class-job.php:
|
1775 |
msgid "You may have noticed the manifest.json file in this archive."
|
1776 |
msgstr ""
|
1777 |
|
1778 |
-
#: inc/class-job.php:
|
1779 |
-
msgid "
|
|
|
1780 |
msgstr ""
|
1781 |
|
1782 |
-
#: inc/class-job.php:
|
1783 |
-
msgid "
|
|
|
|
|
1784 |
msgstr ""
|
1785 |
|
1786 |
-
#: inc/class-job.php:
|
1787 |
-
#, php-format
|
1788 |
msgid "Added manifest.json file with %1$s to backup file list."
|
1789 |
msgstr ""
|
1790 |
|
1791 |
-
#: inc/class-job.php:
|
1792 |
msgid "Wrong BackWPup JobID"
|
1793 |
msgstr ""
|
1794 |
|
1795 |
-
#: inc/class-job.php:
|
1796 |
msgid "A BackWPup job is already running"
|
1797 |
msgstr ""
|
1798 |
|
1799 |
-
#: inc/class-job.php:
|
1800 |
-
msgctxt "
|
|
|
|
|
1801 |
msgid "Hangup detected on controlling terminal or death of controlling process"
|
1802 |
msgstr ""
|
1803 |
|
1804 |
-
#: inc/class-job.php:
|
1805 |
-
msgctxt "
|
|
|
|
|
1806 |
msgid "Interrupt from keyboard"
|
1807 |
msgstr ""
|
1808 |
|
1809 |
-
#: inc/class-job.php:
|
1810 |
-
msgctxt "
|
|
|
|
|
1811 |
msgid "Quit from keyboard"
|
1812 |
msgstr ""
|
1813 |
|
1814 |
-
#: inc/class-job.php:
|
1815 |
-
msgctxt "
|
|
|
|
|
1816 |
msgid "Illegal Instruction"
|
1817 |
msgstr ""
|
1818 |
|
1819 |
-
#: inc/class-job.php:
|
1820 |
-
msgctxt "
|
|
|
|
|
1821 |
msgid "Abort signal from abort(3)"
|
1822 |
msgstr ""
|
1823 |
|
1824 |
-
#: inc/class-job.php:
|
1825 |
-
msgctxt "
|
|
|
|
|
1826 |
msgid "Bus error (bad memory access)"
|
1827 |
msgstr ""
|
1828 |
|
1829 |
-
#: inc/class-job.php:
|
1830 |
-
msgctxt "
|
|
|
|
|
1831 |
msgid "Floating point exception"
|
1832 |
msgstr ""
|
1833 |
|
1834 |
-
#: inc/class-job.php:
|
1835 |
-
msgctxt "
|
|
|
|
|
1836 |
msgid "Invalid memory reference"
|
1837 |
msgstr ""
|
1838 |
|
1839 |
-
#: inc/class-job.php:
|
1840 |
-
msgctxt "
|
|
|
|
|
1841 |
msgid "Termination signal"
|
1842 |
msgstr ""
|
1843 |
|
1844 |
-
#: inc/class-job.php:
|
1845 |
-
msgctxt "
|
|
|
|
|
1846 |
msgid "Stack fault on coprocessor"
|
1847 |
msgstr ""
|
1848 |
|
1849 |
-
#: inc/class-job.php:
|
1850 |
-
msgctxt "
|
|
|
|
|
1851 |
msgid "User-defined signal 1"
|
1852 |
msgstr ""
|
1853 |
|
1854 |
-
#: inc/class-job.php:
|
1855 |
-
msgctxt "
|
|
|
|
|
1856 |
msgid "User-defined signal 2"
|
1857 |
msgstr ""
|
1858 |
|
1859 |
-
#: inc/class-job.php:
|
1860 |
-
msgctxt "
|
|
|
|
|
1861 |
msgid "Urgent condition on socket"
|
1862 |
msgstr ""
|
1863 |
|
1864 |
-
#: inc/class-job.php:
|
1865 |
-
msgctxt "
|
|
|
|
|
1866 |
msgid "CPU time limit exceeded"
|
1867 |
msgstr ""
|
1868 |
|
1869 |
-
#: inc/class-job.php:
|
1870 |
-
msgctxt "
|
|
|
|
|
1871 |
msgid "File size limit exceeded"
|
1872 |
msgstr ""
|
1873 |
|
1874 |
-
#: inc/class-job.php:
|
1875 |
-
msgctxt "
|
|
|
|
|
1876 |
msgid "Power failure"
|
1877 |
msgstr ""
|
1878 |
|
1879 |
-
#: inc/class-job.php:
|
1880 |
-
msgctxt "
|
|
|
|
|
1881 |
msgid "Bad argument to routine"
|
1882 |
msgstr ""
|
1883 |
|
1884 |
-
#: inc/class-job.php:
|
1885 |
-
#, php-format
|
1886 |
msgid "Signal \"%1$s\" (%2$s) is sent to script!"
|
1887 |
msgstr ""
|
1888 |
|
1889 |
-
#: inc/class-job.php:
|
1890 |
-
#, php-format
|
1891 |
msgid "System: %s"
|
1892 |
msgstr ""
|
1893 |
|
1894 |
-
#: inc/class-job.php:
|
1895 |
-
#, php-format
|
1896 |
msgid "Exception caught in %1$s: %2$s"
|
1897 |
msgstr ""
|
1898 |
|
@@ -1904,6 +1891,8 @@ msgstr ""
|
|
1904 |
msgid "Check database tables"
|
1905 |
msgstr ""
|
1906 |
|
|
|
|
|
1907 |
#: inc/class-jobtype-dbcheck.php:17 inc/class-jobtype-dbdump.php:17
|
1908 |
#: inc/class-jobtype-file.php:17 inc/class-jobtype-wpexp.php:17
|
1909 |
#: inc/class-jobtype-wpplugin.php:17 inc/pro/class-wizard-job.php:19
|
@@ -1933,29 +1922,24 @@ msgid "Try to repair defect table"
|
|
1933 |
msgstr ""
|
1934 |
|
1935 |
#: inc/class-jobtype-dbcheck.php:79
|
1936 |
-
#, php-format
|
1937 |
msgid "%d. Trying to check database …"
|
1938 |
msgstr ""
|
1939 |
|
1940 |
#: inc/class-jobtype-dbcheck.php:111
|
1941 |
-
#, php-format
|
1942 |
msgid "Table %1$s is a view. Not checked."
|
1943 |
msgstr ""
|
1944 |
|
1945 |
#: inc/class-jobtype-dbcheck.php:116
|
1946 |
-
#, php-format
|
1947 |
msgid "Table %1$s is not a MyISAM/InnoDB table. Not checked."
|
1948 |
msgstr ""
|
1949 |
|
1950 |
#: inc/class-jobtype-dbcheck.php:124 inc/class-jobtype-dbcheck.php:127
|
1951 |
#: inc/class-jobtype-dbcheck.php:129
|
1952 |
-
#, php-format
|
1953 |
msgid "Result of table check for %1$s is: %2$s"
|
1954 |
msgstr ""
|
1955 |
|
1956 |
#: inc/class-jobtype-dbcheck.php:135 inc/class-jobtype-dbcheck.php:137
|
1957 |
#: inc/class-jobtype-dbcheck.php:139
|
1958 |
-
#, php-format
|
1959 |
msgid "Result of table repair for %1$s is: %2$s"
|
1960 |
msgstr ""
|
1961 |
|
@@ -2004,12 +1988,10 @@ msgid "GZip"
|
|
2004 |
msgstr ""
|
2005 |
|
2006 |
#: inc/class-jobtype-dbdump.php:159 inc/pro/class-jobtype-dbdump.php:475
|
2007 |
-
#, php-format
|
2008 |
msgid "%d. Try to backup database …"
|
2009 |
msgstr ""
|
2010 |
|
2011 |
#: inc/class-jobtype-dbdump.php:173 inc/pro/class-jobtype-dbdump.php:495
|
2012 |
-
#, php-format
|
2013 |
msgid "Connected to database %1$s on %2$s"
|
2014 |
msgstr ""
|
2015 |
|
@@ -2018,7 +2000,6 @@ msgid "No tables to backup."
|
|
2018 |
msgstr ""
|
2019 |
|
2020 |
#: inc/class-jobtype-dbdump.php:210 inc/pro/class-jobtype-dbdump.php:536
|
2021 |
-
#, php-format
|
2022 |
msgid "Backup database table \"%s\" with \"%s\" records"
|
2023 |
msgstr ""
|
2024 |
|
@@ -2027,7 +2008,6 @@ msgid "MySQL backup file not created"
|
|
2027 |
msgstr ""
|
2028 |
|
2029 |
#: inc/class-jobtype-dbdump.php:254 inc/pro/class-jobtype-dbdump.php:763
|
2030 |
-
#, php-format
|
2031 |
msgid "Added database dump \"%1$s\" with %2$s to backup file list"
|
2032 |
msgstr ""
|
2033 |
|
@@ -2052,117 +2032,115 @@ msgstr ""
|
|
2052 |
msgid "Backup WordPress install folder"
|
2053 |
msgstr ""
|
2054 |
|
2055 |
-
#: inc/class-jobtype-file.php:
|
2056 |
-
#: inc/class-jobtype-file.php:160 inc/class-jobtype-file.php:197
|
2057 |
-
#: inc/class-jobtype-file.php:234
|
2058 |
-
#, php-format
|
2059 |
-
msgid "Path as set by user (symlink?): %s"
|
2060 |
-
msgstr ""
|
2061 |
-
|
2062 |
-
#: inc/class-jobtype-file.php:89 inc/class-jobtype-file.php:126
|
2063 |
-
#: inc/class-jobtype-file.php:163 inc/class-jobtype-file.php:200
|
2064 |
-
#: inc/class-jobtype-file.php:237
|
2065 |
-
msgid "Exclude:"
|
2066 |
-
msgstr ""
|
2067 |
-
|
2068 |
-
#: inc/class-jobtype-file.php:100 inc/class-jobtype-file.php:137
|
2069 |
-
#: inc/class-jobtype-file.php:174 inc/class-jobtype-file.php:211
|
2070 |
-
#: inc/class-jobtype-file.php:248
|
2071 |
-
msgid "Excluded by .donotbackup file!"
|
2072 |
-
msgstr ""
|
2073 |
-
|
2074 |
-
#: inc/class-jobtype-file.php:112
|
2075 |
msgid "Backup content folder"
|
2076 |
msgstr ""
|
2077 |
|
2078 |
-
#: inc/class-jobtype-file.php:
|
2079 |
msgid "Backup plugins"
|
2080 |
msgstr ""
|
2081 |
|
2082 |
-
#: inc/class-jobtype-file.php:
|
2083 |
msgid "Backup themes"
|
2084 |
msgstr ""
|
2085 |
|
2086 |
-
#: inc/class-jobtype-file.php:
|
2087 |
#: inc/pro/class-wizard-job.php:746
|
2088 |
msgid "Backup uploads folder"
|
2089 |
msgstr ""
|
2090 |
|
2091 |
-
#: inc/class-jobtype-file.php:
|
2092 |
msgid "Extra folders to backup"
|
2093 |
msgstr ""
|
2094 |
|
2095 |
-
#: inc/class-jobtype-file.php:
|
2096 |
-
msgid "
|
|
|
|
|
2097 |
msgstr ""
|
2098 |
|
2099 |
-
#: inc/class-jobtype-file.php:
|
2100 |
msgid "Exclude from backup"
|
2101 |
msgstr ""
|
2102 |
|
2103 |
-
#: inc/class-jobtype-file.php:
|
2104 |
msgid "Thumbnails in uploads"
|
2105 |
msgstr ""
|
2106 |
|
2107 |
-
#: inc/class-jobtype-file.php:
|
2108 |
msgid "Don't backup thumbnails from the site's uploads folder."
|
2109 |
msgstr ""
|
2110 |
|
2111 |
-
#: inc/class-jobtype-file.php:
|
2112 |
msgid "Exclude files/folders from backup"
|
2113 |
msgstr ""
|
2114 |
|
2115 |
-
#: inc/class-jobtype-file.php:
|
2116 |
-
msgid "
|
|
|
|
|
2117 |
msgstr ""
|
2118 |
|
2119 |
-
#: inc/class-jobtype-file.php:
|
2120 |
msgid "Special options"
|
2121 |
msgstr ""
|
2122 |
|
2123 |
-
#: inc/class-jobtype-file.php:
|
2124 |
msgid "Include special files"
|
2125 |
msgstr ""
|
2126 |
|
2127 |
-
#: inc/class-jobtype-file.php:
|
2128 |
-
msgid "
|
|
|
|
|
2129 |
msgstr ""
|
2130 |
|
2131 |
-
#: inc/class-jobtype-file.php:
|
2132 |
msgid "Use one folder above as WP install folder"
|
2133 |
msgstr ""
|
2134 |
|
2135 |
-
#: inc/class-jobtype-file.php:
|
2136 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
2137 |
msgstr ""
|
2138 |
|
2139 |
-
#: inc/class-jobtype-file.php:
|
2140 |
-
#, php-format
|
2141 |
msgid "%d. Trying to make a list of folders to back up …"
|
2142 |
msgstr ""
|
2143 |
|
2144 |
-
#: inc/class-jobtype-file.php:
|
2145 |
-
#: inc/class-jobtype-file.php:
|
2146 |
-
#: inc/class-jobtype-file.php:519 inc/class-jobtype-file.php:523
|
2147 |
-
#: inc/class-jobtype-file.php:527
|
2148 |
-
#, php-format
|
2149 |
msgid "Added \"%s\" to backup file list"
|
2150 |
msgstr ""
|
2151 |
|
2152 |
-
#: inc/class-jobtype-file.php:
|
2153 |
msgid "No files/folder for the backup."
|
2154 |
msgstr ""
|
2155 |
|
2156 |
-
#: inc/class-jobtype-file.php:
|
2157 |
-
#, php-format
|
2158 |
msgid "%1$d folders to backup."
|
2159 |
msgstr ""
|
2160 |
|
2161 |
-
#: inc/class-jobtype-file.php:
|
2162 |
-
#, php-format
|
2163 |
msgid "Folder \"%s\" is not readable!"
|
2164 |
msgstr ""
|
2165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2166 |
#: inc/class-jobtype-wpexp.php:13
|
2167 |
msgid "XML export"
|
2168 |
msgstr ""
|
@@ -2201,13 +2179,11 @@ msgid "BZip2"
|
|
2201 |
msgstr ""
|
2202 |
|
2203 |
#: inc/class-jobtype-wpexp.php:112
|
2204 |
-
#, php-format
|
2205 |
msgid "%d. Trying to create a WordPress export to XML file …"
|
2206 |
msgstr ""
|
2207 |
|
2208 |
#: inc/class-jobtype-wpexp.php:127
|
2209 |
-
|
2210 |
-
msgid "WP Export: Post type %s does not allow export."
|
2211 |
msgstr ""
|
2212 |
|
2213 |
#: inc/class-jobtype-wpexp.php:172 inc/class-jobtype-wpexp.php:186
|
@@ -2222,17 +2198,14 @@ msgid "Check WP Export file …"
|
|
2222 |
msgstr ""
|
2223 |
|
2224 |
#: inc/class-jobtype-wpexp.php:422
|
2225 |
-
#, php-format
|
2226 |
msgid "XML WARNING (%s): %s"
|
2227 |
msgstr ""
|
2228 |
|
2229 |
#: inc/class-jobtype-wpexp.php:425
|
2230 |
-
#, php-format
|
2231 |
msgid "XML RECOVERABLE (%s): %s"
|
2232 |
msgstr ""
|
2233 |
|
2234 |
#: inc/class-jobtype-wpexp.php:428
|
2235 |
-
#, php-format
|
2236 |
msgid "XML ERROR (%s): %s"
|
2237 |
msgstr ""
|
2238 |
|
@@ -2241,7 +2214,8 @@ msgid "There was an error when reading this WXR file"
|
|
2241 |
msgstr ""
|
2242 |
|
2243 |
#: inc/class-jobtype-wpexp.php:444 inc/class-jobtype-wpexp.php:451
|
2244 |
-
msgid "
|
|
|
2245 |
msgstr ""
|
2246 |
|
2247 |
#: inc/class-jobtype-wpexp.php:460
|
@@ -2249,7 +2223,9 @@ msgid "WP Export file is a valid WXR file."
|
|
2249 |
msgstr ""
|
2250 |
|
2251 |
#: inc/class-jobtype-wpexp.php:462
|
2252 |
-
msgid "
|
|
|
|
|
2253 |
msgstr ""
|
2254 |
|
2255 |
#: inc/class-jobtype-wpexp.php:474 inc/pro/class-jobtype-dbdump.php:741
|
@@ -2261,7 +2237,6 @@ msgid "Compressing done."
|
|
2261 |
msgstr ""
|
2262 |
|
2263 |
#: inc/class-jobtype-wpexp.php:500
|
2264 |
-
#, php-format
|
2265 |
msgid "Added XML export \"%1$s\" with %2$s to backup file list."
|
2266 |
msgstr ""
|
2267 |
|
@@ -2278,7 +2253,6 @@ msgid "Plugin list file name"
|
|
2278 |
msgstr ""
|
2279 |
|
2280 |
#: inc/class-jobtype-wpplugin.php:96
|
2281 |
-
#, php-format
|
2282 |
msgid "%d. Trying to generate a file with installed plugin names …"
|
2283 |
msgstr ""
|
2284 |
|
@@ -2287,7 +2261,6 @@ msgid "All plugin information:"
|
|
2287 |
msgstr ""
|
2288 |
|
2289 |
#: inc/class-jobtype-wpplugin.php:126
|
2290 |
-
#, php-format
|
2291 |
msgid "from %s"
|
2292 |
msgstr ""
|
2293 |
|
@@ -2304,7 +2277,6 @@ msgid "Can not open target file for writing."
|
|
2304 |
msgstr ""
|
2305 |
|
2306 |
#: inc/class-jobtype-wpplugin.php:148
|
2307 |
-
#, php-format
|
2308 |
msgid "Added plugin list file \"%1$s\" with %2$s to backup file list."
|
2309 |
msgstr ""
|
2310 |
|
@@ -2325,12 +2297,10 @@ msgid "Setting of MySQLi connection timeout failed"
|
|
2325 |
msgstr ""
|
2326 |
|
2327 |
#: inc/class-mysqldump.php:110 inc/pro/class-jobtype-dbdump.php:843
|
2328 |
-
#, php-format
|
2329 |
msgid "Cannot connect to MySQL database %1$d: %2$s"
|
2330 |
msgstr ""
|
2331 |
|
2332 |
#: inc/class-mysqldump.php:117
|
2333 |
-
#, php-format
|
2334 |
msgctxt "Database Charset"
|
2335 |
msgid "Cannot set DB charset to %s error: %s"
|
2336 |
msgstr ""
|
@@ -2348,26 +2318,23 @@ msgstr ""
|
|
2348 |
#: inc/pro/class-jobtype-dbdump.php:859 inc/pro/class-jobtype-dbdump.php:873
|
2349 |
#: inc/pro/class-jobtype-dbdump.php:921 inc/pro/class-jobtype-dbdump.php:940
|
2350 |
#: inc/pro/class-jobtype-dbdump.php:983
|
2351 |
-
#, php-format
|
2352 |
msgid "Database error %1$s for query %2$s"
|
2353 |
msgstr ""
|
2354 |
|
2355 |
#: inc/class-mysqldump.php:479
|
2356 |
-
#, php-format
|
2357 |
msgid "Start for table backup is not correctly set: %1$s"
|
2358 |
msgstr ""
|
2359 |
|
2360 |
#: inc/class-mysqldump.php:483
|
2361 |
-
#, php-format
|
2362 |
msgid "Length for table backup is not correctly set: %1$s"
|
2363 |
msgstr ""
|
2364 |
|
2365 |
-
#: inc/class-mysqldump.php:
|
2366 |
msgid "Error while writing file!"
|
2367 |
msgstr ""
|
2368 |
|
2369 |
-
#: inc/class-option.php:
|
2370 |
-
#: inc/class-page-editjob.php:
|
2371 |
msgid "New Job"
|
2372 |
msgstr ""
|
2373 |
|
@@ -2376,16 +2343,24 @@ msgid "Welcome to BackWPup Pro"
|
|
2376 |
msgstr ""
|
2377 |
|
2378 |
#: inc/class-page-about.php:370 inc/class-page-backwpup.php:75
|
2379 |
-
msgid "
|
|
|
|
|
2380 |
msgstr ""
|
2381 |
|
2382 |
#: inc/class-page-about.php:371 inc/class-page-about.php:384
|
2383 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
2384 |
msgstr ""
|
2385 |
|
2386 |
#: inc/class-page-about.php:372
|
2387 |
-
|
2388 |
-
|
|
|
2389 |
msgstr ""
|
2390 |
|
2391 |
#: inc/class-page-about.php:382
|
@@ -2393,7 +2368,9 @@ msgid "Welcome to BackWPup"
|
|
2393 |
msgstr ""
|
2394 |
|
2395 |
#: inc/class-page-about.php:385
|
2396 |
-
msgid "
|
|
|
|
|
2397 |
msgstr ""
|
2398 |
|
2399 |
#: inc/class-page-about.php:398
|
@@ -2405,8 +2382,11 @@ msgid "Save your database regularly"
|
|
2405 |
msgstr ""
|
2406 |
|
2407 |
#: inc/class-page-about.php:402
|
2408 |
-
|
2409 |
-
|
|
|
|
|
|
|
2410 |
msgstr ""
|
2411 |
|
2412 |
#: inc/class-page-about.php:407 inc/class-page-about.php:411
|
@@ -2414,7 +2394,11 @@ msgid "WordPress XML Export"
|
|
2414 |
msgstr ""
|
2415 |
|
2416 |
#: inc/class-page-about.php:408
|
2417 |
-
msgid "
|
|
|
|
|
|
|
|
|
2418 |
msgstr ""
|
2419 |
|
2420 |
#: inc/class-page-about.php:416
|
@@ -2426,8 +2410,10 @@ msgid "Save all files"
|
|
2426 |
msgstr ""
|
2427 |
|
2428 |
#: inc/class-page-about.php:420
|
2429 |
-
|
2430 |
-
|
|
|
|
|
2431 |
msgstr ""
|
2432 |
|
2433 |
#: inc/class-page-about.php:425 inc/class-page-about.php:429
|
@@ -2435,7 +2421,9 @@ msgid "Security!"
|
|
2435 |
msgstr ""
|
2436 |
|
2437 |
#: inc/class-page-about.php:426
|
2438 |
-
msgid "
|
|
|
|
|
2439 |
msgstr ""
|
2440 |
|
2441 |
#: inc/class-page-about.php:434 inc/class-page-about.php:437
|
@@ -2443,7 +2431,9 @@ msgid "Cloud Support"
|
|
2443 |
msgstr ""
|
2444 |
|
2445 |
#: inc/class-page-about.php:438
|
2446 |
-
msgid "
|
|
|
|
|
2447 |
msgstr ""
|
2448 |
|
2449 |
#: inc/class-page-about.php:444
|
@@ -2629,9 +2619,8 @@ msgid "?"
|
|
2629 |
msgstr ""
|
2630 |
|
2631 |
#: inc/class-page-backups.php:361 inc/class-page-backwpup.php:321
|
2632 |
-
#: inc/class-page-backwpup.php:
|
2633 |
#: inc/class-page-logs.php:164
|
2634 |
-
#, php-format
|
2635 |
msgid "%1$s at %2$s"
|
2636 |
msgstr ""
|
2637 |
|
@@ -2645,12 +2634,10 @@ msgid "Backup Files"
|
|
2645 |
msgstr ""
|
2646 |
|
2647 |
#: inc/class-page-backups.php:489
|
2648 |
-
#, php-format
|
2649 |
msgid "%s › Manage Backup Archives"
|
2650 |
msgstr ""
|
2651 |
|
2652 |
#: inc/class-page-backwpup.php:67
|
2653 |
-
#, php-format
|
2654 |
msgid "%s › Dashboard"
|
2655 |
msgstr ""
|
2656 |
|
@@ -2660,7 +2647,10 @@ msgid "Planning backups"
|
|
2660 |
msgstr ""
|
2661 |
|
2662 |
#: inc/class-page-backwpup.php:75 inc/class-page-backwpup.php:84
|
2663 |
-
msgid "
|
|
|
|
|
|
|
2664 |
msgstr ""
|
2665 |
|
2666 |
#: inc/class-page-backwpup.php:76 inc/class-page-backwpup.php:85
|
@@ -2669,7 +2659,9 @@ msgid "Restoring backups"
|
|
2669 |
msgstr ""
|
2670 |
|
2671 |
#: inc/class-page-backwpup.php:77 inc/class-page-backwpup.php:86
|
2672 |
-
msgid "
|
|
|
|
|
2673 |
msgstr ""
|
2674 |
|
2675 |
#: inc/class-page-backwpup.php:78 inc/class-page-backwpup.php:87
|
@@ -2678,20 +2670,24 @@ msgid "Ready to set up a backup job?"
|
|
2678 |
msgstr ""
|
2679 |
|
2680 |
#: inc/class-page-backwpup.php:79
|
2681 |
-
|
2682 |
-
|
|
|
2683 |
msgstr ""
|
2684 |
|
2685 |
#: inc/class-page-backwpup.php:79 inc/class-page-backwpup.php:89
|
2686 |
-
msgid "
|
|
|
|
|
2687 |
msgstr ""
|
2688 |
|
2689 |
#: inc/class-page-backwpup.php:84
|
2690 |
-
msgid "
|
|
|
|
|
2691 |
msgstr ""
|
2692 |
|
2693 |
#: inc/class-page-backwpup.php:88
|
2694 |
-
#, php-format
|
2695 |
msgid "<a href=\"%s\">Add a new backup job</a> and plan what you want to save."
|
2696 |
msgstr ""
|
2697 |
|
@@ -2724,7 +2720,8 @@ msgid "One click backup"
|
|
2724 |
msgstr ""
|
2725 |
|
2726 |
#: inc/class-page-backwpup.php:117
|
2727 |
-
msgid "
|
|
|
2728 |
msgstr ""
|
2729 |
|
2730 |
#: inc/class-page-backwpup.php:117
|
@@ -2741,12 +2738,13 @@ msgid "https://backwpup.com/feed/"
|
|
2741 |
msgstr ""
|
2742 |
|
2743 |
#: inc/class-page-backwpup.php:130
|
2744 |
-
#, php-format
|
2745 |
msgid "<strong>RSS Error</strong>: %s"
|
2746 |
msgstr ""
|
2747 |
|
2748 |
#: inc/class-page-backwpup.php:132
|
2749 |
-
msgid "
|
|
|
|
|
2750 |
msgstr ""
|
2751 |
|
2752 |
#: inc/class-page-backwpup.php:146
|
@@ -2789,7 +2787,7 @@ msgstr ""
|
|
2789 |
|
2790 |
#: inc/class-page-backwpup.php:257
|
2791 |
msgctxt "Pro teaser box"
|
2792 |
-
msgid "First-class <strong>dedicated support</strong> at
|
2793 |
msgstr ""
|
2794 |
|
2795 |
#: inc/class-page-backwpup.php:258
|
@@ -2804,7 +2802,7 @@ msgstr ""
|
|
2804 |
|
2805 |
#: inc/class-page-backwpup.php:260
|
2806 |
msgctxt "Pro teaser box, link text"
|
2807 |
-
msgid "And more"
|
2808 |
msgstr ""
|
2809 |
|
2810 |
#: inc/class-page-backwpup.php:262
|
@@ -2827,7 +2825,6 @@ msgid "Job"
|
|
2827 |
msgstr ""
|
2828 |
|
2829 |
#: inc/class-page-backwpup.php:307
|
2830 |
-
#, php-format
|
2831 |
msgid "working since %d seconds"
|
2832 |
msgstr ""
|
2833 |
|
@@ -2847,31 +2844,31 @@ msgstr ""
|
|
2847 |
msgid "Result"
|
2848 |
msgstr ""
|
2849 |
|
2850 |
-
#: inc/class-page-backwpup.php:
|
2851 |
-
|
|
|
|
|
|
|
2852 |
msgid "%d ERROR"
|
2853 |
msgid_plural "%d ERRORS"
|
2854 |
msgstr[0] ""
|
2855 |
msgstr[1] ""
|
2856 |
|
2857 |
-
#: inc/class-page-backwpup.php:
|
2858 |
-
#, php-format
|
2859 |
msgid "%d WARNING"
|
2860 |
msgid_plural "%d WARNINGS"
|
2861 |
msgstr[0] ""
|
2862 |
msgstr[1] ""
|
2863 |
|
2864 |
-
#: inc/class-page-backwpup.php:
|
2865 |
msgid "OK"
|
2866 |
msgstr ""
|
2867 |
|
2868 |
#: inc/class-page-editjob.php:98
|
2869 |
-
#, php-format
|
2870 |
msgid "Job with ID %d"
|
2871 |
msgstr ""
|
2872 |
|
2873 |
#: inc/class-page-editjob.php:222
|
2874 |
-
#, php-format
|
2875 |
msgid "Changes for job <i>%s</i> saved."
|
2876 |
msgstr ""
|
2877 |
|
@@ -2883,423 +2880,429 @@ msgstr ""
|
|
2883 |
msgid "Run now"
|
2884 |
msgstr ""
|
2885 |
|
2886 |
-
#: inc/class-page-editjob.php:
|
2887 |
-
#, php-format
|
2888 |
msgid "%1$s › Job: %2$s"
|
2889 |
msgstr ""
|
2890 |
|
2891 |
-
#: inc/class-page-editjob.php:
|
2892 |
msgid "General"
|
2893 |
msgstr ""
|
2894 |
|
2895 |
-
#: inc/class-page-editjob.php:
|
2896 |
msgid "Schedule"
|
2897 |
msgstr ""
|
2898 |
|
2899 |
-
#: inc/class-page-editjob.php:
|
2900 |
-
#, php-format
|
2901 |
msgid "To: %s"
|
2902 |
msgstr ""
|
2903 |
|
2904 |
-
#: inc/class-page-editjob.php:
|
2905 |
#: inc/class-page-jobs.php:125
|
2906 |
msgid "Job Name"
|
2907 |
msgstr ""
|
2908 |
|
2909 |
-
#: inc/class-page-editjob.php:
|
2910 |
msgid "Please name this job."
|
2911 |
msgstr ""
|
2912 |
|
2913 |
-
#: inc/class-page-editjob.php:
|
2914 |
msgid "Job Tasks"
|
2915 |
msgstr ""
|
2916 |
|
2917 |
-
#: inc/class-page-editjob.php:
|
2918 |
msgid "This job is a …"
|
2919 |
msgstr ""
|
2920 |
|
2921 |
-
#: inc/class-page-editjob.php:
|
2922 |
msgid "Job tasks"
|
2923 |
msgstr ""
|
2924 |
|
2925 |
-
#: inc/class-page-editjob.php:
|
2926 |
msgid "Backup File Creation"
|
2927 |
msgstr ""
|
2928 |
|
2929 |
-
#: inc/class-page-editjob.php:
|
2930 |
#: inc/pro/class-wizard-job.php:402 inc/pro/class-wizard-job.php:405
|
2931 |
msgid "Backup type"
|
2932 |
msgstr ""
|
2933 |
|
2934 |
-
#: inc/class-page-editjob.php:
|
2935 |
msgid "Synchronize file by file to destination"
|
2936 |
msgstr ""
|
2937 |
|
2938 |
-
#: inc/class-page-editjob.php:
|
2939 |
msgid "Create a backup archive"
|
2940 |
msgstr ""
|
2941 |
|
2942 |
-
#: inc/class-page-editjob.php:
|
2943 |
msgid "Archive name"
|
2944 |
msgstr ""
|
2945 |
|
2946 |
-
#: inc/class-page-editjob.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
2947 |
msgid "Replacement patterns:"
|
2948 |
msgstr ""
|
2949 |
|
2950 |
-
#: inc/class-page-editjob.php:
|
2951 |
-
#, php-format
|
2952 |
msgid "%d = Two digit day of the month, with leading zeros"
|
2953 |
msgstr ""
|
2954 |
|
2955 |
-
#: inc/class-page-editjob.php:
|
2956 |
msgid "%j = Day of the month, without leading zeros"
|
2957 |
msgstr ""
|
2958 |
|
2959 |
-
#: inc/class-page-editjob.php:
|
2960 |
msgid "%m = Day of the month, with leading zeros"
|
2961 |
msgstr ""
|
2962 |
|
2963 |
-
#: inc/class-page-editjob.php:
|
2964 |
msgid "%n = Representation of the month (without leading zeros)"
|
2965 |
msgstr ""
|
2966 |
|
2967 |
-
#: inc/class-page-editjob.php:
|
2968 |
msgid "%Y = Four digit representation for the year"
|
2969 |
msgstr ""
|
2970 |
|
2971 |
-
#: inc/class-page-editjob.php:
|
2972 |
msgid "%y = Two digit representation of the year"
|
2973 |
msgstr ""
|
2974 |
|
2975 |
-
#: inc/class-page-editjob.php:
|
2976 |
msgid "%a = Lowercase ante meridiem (am) and post meridiem (pm)"
|
2977 |
msgstr ""
|
2978 |
|
2979 |
-
#: inc/class-page-editjob.php:
|
2980 |
msgid "%A = Uppercase ante meridiem (AM) and post meridiem (PM)"
|
2981 |
msgstr ""
|
2982 |
|
2983 |
-
#: inc/class-page-editjob.php:
|
2984 |
msgid "%B = Swatch Internet Time"
|
2985 |
msgstr ""
|
2986 |
|
2987 |
-
#: inc/class-page-editjob.php:
|
2988 |
msgid "%g = Hour in 12-hour format, without leading zeros"
|
2989 |
msgstr ""
|
2990 |
|
2991 |
-
#: inc/class-page-editjob.php:
|
2992 |
msgid "%G = Hour in 24-hour format, without leading zeros"
|
2993 |
msgstr ""
|
2994 |
|
2995 |
-
#: inc/class-page-editjob.php:
|
2996 |
msgid "%h = Hour in 12-hour format, with leading zeros"
|
2997 |
msgstr ""
|
2998 |
|
2999 |
-
#: inc/class-page-editjob.php:
|
3000 |
msgid "%H = Hour in 24-hour format, with leading zeros"
|
3001 |
msgstr ""
|
3002 |
|
3003 |
-
#: inc/class-page-editjob.php:
|
3004 |
msgid "%i = Two digit representation of the minute"
|
3005 |
msgstr ""
|
3006 |
|
3007 |
-
#: inc/class-page-editjob.php:
|
3008 |
-
#, php-format
|
3009 |
msgid "%s = Two digit representation of the second"
|
3010 |
msgstr ""
|
3011 |
|
3012 |
-
#: inc/class-page-editjob.php:
|
3013 |
msgid "Archive Format"
|
3014 |
msgstr ""
|
3015 |
|
3016 |
-
#: inc/class-page-editjob.php:
|
3017 |
#: inc/pro/class-wizard-job.php:426 inc/pro/class-wizard-job.php:429
|
3018 |
msgid "Zip"
|
3019 |
msgstr ""
|
3020 |
|
3021 |
-
#: inc/class-page-editjob.php:
|
3022 |
-
#, php-format
|
3023 |
msgid "Disabled due to missing %s PHP class."
|
3024 |
msgstr ""
|
3025 |
|
3026 |
-
#: inc/class-page-editjob.php:
|
3027 |
msgid "Tar"
|
3028 |
msgstr ""
|
3029 |
|
3030 |
-
#: inc/class-page-editjob.php:
|
3031 |
#: inc/pro/class-wizard-job.php:437 inc/pro/class-wizard-job.php:440
|
3032 |
msgid "Tar GZip"
|
3033 |
msgstr ""
|
3034 |
|
3035 |
-
#: inc/class-page-editjob.php:
|
3036 |
-
#, php-format
|
3037 |
msgid "Disabled due to missing %s PHP function."
|
3038 |
msgstr ""
|
3039 |
|
3040 |
-
#: inc/class-page-editjob.php:
|
3041 |
#: inc/pro/class-wizard-job.php:444 inc/pro/class-wizard-job.php:447
|
3042 |
msgid "Tar BZip2"
|
3043 |
msgstr ""
|
3044 |
|
3045 |
-
#: inc/class-page-editjob.php:
|
3046 |
msgid "Job Destination"
|
3047 |
msgstr ""
|
3048 |
|
3049 |
-
#: inc/class-page-editjob.php:
|
3050 |
msgid "Where should your backup file be stored?"
|
3051 |
msgstr ""
|
3052 |
|
3053 |
-
#: inc/class-page-editjob.php:
|
3054 |
msgid "Log Files"
|
3055 |
msgstr ""
|
3056 |
|
3057 |
-
#: inc/class-page-editjob.php:
|
3058 |
msgid "Send log to email address"
|
3059 |
msgstr ""
|
3060 |
|
3061 |
-
#: inc/class-page-editjob.php:
|
3062 |
-
msgid "
|
|
|
|
|
3063 |
msgstr ""
|
3064 |
|
3065 |
-
#: inc/class-page-editjob.php:
|
3066 |
msgid "Email FROM field"
|
3067 |
msgstr ""
|
3068 |
|
3069 |
-
#: inc/class-page-editjob.php:
|
3070 |
msgid "Your Name <mail@domain.tld>"
|
3071 |
msgstr ""
|
3072 |
|
3073 |
-
#: inc/class-page-editjob.php:
|
3074 |
msgid "Errors only"
|
3075 |
msgstr ""
|
3076 |
|
3077 |
-
#: inc/class-page-editjob.php:
|
3078 |
msgid "Send email with log only when errors occur during job execution."
|
3079 |
msgstr ""
|
3080 |
|
3081 |
-
#: inc/class-page-editjob.php:
|
3082 |
msgid "Job Schedule"
|
3083 |
msgstr ""
|
3084 |
|
3085 |
-
#: inc/class-page-editjob.php:
|
3086 |
msgid "Start job"
|
3087 |
msgstr ""
|
3088 |
|
3089 |
-
#: inc/class-page-editjob.php:
|
3090 |
msgid "manually only"
|
3091 |
msgstr ""
|
3092 |
|
3093 |
-
#: inc/class-page-editjob.php:
|
3094 |
msgid "with WordPress cron"
|
3095 |
msgstr ""
|
3096 |
|
3097 |
-
#: inc/class-page-editjob.php:
|
3098 |
-
msgid "
|
|
|
|
|
3099 |
msgstr ""
|
3100 |
|
3101 |
-
#: inc/class-page-editjob.php:
|
3102 |
-
#, php-format
|
3103 |
msgid "First setup <a href=\"%s\">API Key</a>."
|
3104 |
msgstr ""
|
3105 |
|
3106 |
-
#: inc/class-page-editjob.php:
|
3107 |
msgid "with a link"
|
3108 |
msgstr ""
|
3109 |
|
3110 |
-
#: inc/class-page-editjob.php:
|
3111 |
-
msgid "
|
|
|
|
|
3112 |
msgstr ""
|
3113 |
|
3114 |
-
#: inc/class-page-editjob.php:
|
3115 |
msgid "Start job with CLI"
|
3116 |
msgstr ""
|
3117 |
|
3118 |
-
#: inc/class-page-editjob.php:
|
3119 |
-
msgid "
|
|
|
3120 |
msgstr ""
|
3121 |
|
3122 |
-
#: inc/class-page-editjob.php:
|
3123 |
msgid "Schedule execution time"
|
3124 |
msgstr ""
|
3125 |
|
3126 |
-
#: inc/class-page-editjob.php:
|
3127 |
msgid "Scheduler type"
|
3128 |
msgstr ""
|
3129 |
|
3130 |
-
#: inc/class-page-editjob.php:
|
3131 |
msgid "basic"
|
3132 |
msgstr ""
|
3133 |
|
3134 |
-
#: inc/class-page-editjob.php:
|
3135 |
msgid "advanced"
|
3136 |
msgstr ""
|
3137 |
|
3138 |
-
#: inc/class-page-editjob.php:
|
3139 |
#: inc/pro/class-wizard-job.php:320
|
3140 |
msgid "Scheduler"
|
3141 |
msgstr ""
|
3142 |
|
3143 |
-
#: inc/class-page-editjob.php:
|
3144 |
#: inc/class-page-logs.php:139 inc/pro/class-wizard-job.php:324
|
3145 |
msgid "Type"
|
3146 |
msgstr ""
|
3147 |
|
3148 |
-
#: inc/class-page-editjob.php:
|
3149 |
msgid "Hour"
|
3150 |
msgstr ""
|
3151 |
|
3152 |
-
#: inc/class-page-editjob.php:
|
3153 |
msgid "Minute"
|
3154 |
msgstr ""
|
3155 |
|
3156 |
-
#: inc/class-page-editjob.php:
|
3157 |
msgid "monthly"
|
3158 |
msgstr ""
|
3159 |
|
3160 |
-
#: inc/class-page-editjob.php:
|
3161 |
msgid "on"
|
3162 |
msgstr ""
|
3163 |
|
3164 |
-
#: inc/class-page-editjob.php:
|
3165 |
msgid "weekly"
|
3166 |
msgstr ""
|
3167 |
|
3168 |
-
#: inc/class-page-editjob.php:
|
3169 |
#: inc/pro/class-wizard-job.php:351
|
3170 |
msgid "Sunday"
|
3171 |
msgstr ""
|
3172 |
|
3173 |
-
#: inc/class-page-editjob.php:
|
3174 |
#: inc/pro/class-wizard-job.php:352
|
3175 |
msgid "Monday"
|
3176 |
msgstr ""
|
3177 |
|
3178 |
-
#: inc/class-page-editjob.php:
|
3179 |
#: inc/pro/class-wizard-job.php:353
|
3180 |
msgid "Tuesday"
|
3181 |
msgstr ""
|
3182 |
|
3183 |
-
#: inc/class-page-editjob.php:
|
3184 |
#: inc/pro/class-wizard-job.php:354
|
3185 |
msgid "Wednesday"
|
3186 |
msgstr ""
|
3187 |
|
3188 |
-
#: inc/class-page-editjob.php:
|
3189 |
#: inc/pro/class-wizard-job.php:355
|
3190 |
msgid "Thursday"
|
3191 |
msgstr ""
|
3192 |
|
3193 |
-
#: inc/class-page-editjob.php:
|
3194 |
#: inc/pro/class-wizard-job.php:356
|
3195 |
msgid "Friday"
|
3196 |
msgstr ""
|
3197 |
|
3198 |
-
#: inc/class-page-editjob.php:
|
3199 |
#: inc/pro/class-wizard-job.php:357
|
3200 |
msgid "Saturday"
|
3201 |
msgstr ""
|
3202 |
|
3203 |
-
#: inc/class-page-editjob.php:
|
3204 |
msgid "daily"
|
3205 |
msgstr ""
|
3206 |
|
3207 |
-
#: inc/class-page-editjob.php:
|
3208 |
msgid "hourly"
|
3209 |
msgstr ""
|
3210 |
|
3211 |
-
#: inc/class-page-editjob.php:
|
3212 |
msgid "Minutes:"
|
3213 |
msgstr ""
|
3214 |
|
3215 |
-
#: inc/class-page-editjob.php:
|
3216 |
-
#: inc/class-page-editjob.php:
|
3217 |
-
#: inc/class-page-editjob.php:
|
3218 |
msgid "Any (*)"
|
3219 |
msgstr ""
|
3220 |
|
3221 |
-
#: inc/class-page-editjob.php:
|
3222 |
msgid "Hours:"
|
3223 |
msgstr ""
|
3224 |
|
3225 |
-
#: inc/class-page-editjob.php:
|
3226 |
msgid "Day of Month:"
|
3227 |
msgstr ""
|
3228 |
|
3229 |
-
#: inc/class-page-editjob.php:
|
3230 |
msgid "Month:"
|
3231 |
msgstr ""
|
3232 |
|
3233 |
-
#: inc/class-page-editjob.php:
|
3234 |
msgid "January"
|
3235 |
msgstr ""
|
3236 |
|
3237 |
-
#: inc/class-page-editjob.php:
|
3238 |
msgid "February"
|
3239 |
msgstr ""
|
3240 |
|
3241 |
-
#: inc/class-page-editjob.php:
|
3242 |
msgid "March"
|
3243 |
msgstr ""
|
3244 |
|
3245 |
-
#: inc/class-page-editjob.php:
|
3246 |
msgid "April"
|
3247 |
msgstr ""
|
3248 |
|
3249 |
-
#: inc/class-page-editjob.php:
|
3250 |
msgid "May"
|
3251 |
msgstr ""
|
3252 |
|
3253 |
-
#: inc/class-page-editjob.php:
|
3254 |
msgid "June"
|
3255 |
msgstr ""
|
3256 |
|
3257 |
-
#: inc/class-page-editjob.php:
|
3258 |
msgid "July"
|
3259 |
msgstr ""
|
3260 |
|
3261 |
-
#: inc/class-page-editjob.php:
|
3262 |
msgid "August"
|
3263 |
msgstr ""
|
3264 |
|
3265 |
-
#: inc/class-page-editjob.php:
|
3266 |
msgid "September"
|
3267 |
msgstr ""
|
3268 |
|
3269 |
-
#: inc/class-page-editjob.php:
|
3270 |
msgid "October"
|
3271 |
msgstr ""
|
3272 |
|
3273 |
-
#: inc/class-page-editjob.php:
|
3274 |
msgid "November"
|
3275 |
msgstr ""
|
3276 |
|
3277 |
-
#: inc/class-page-editjob.php:
|
3278 |
msgid "December"
|
3279 |
msgstr ""
|
3280 |
|
3281 |
-
#: inc/class-page-editjob.php:
|
3282 |
msgid "Day of Week:"
|
3283 |
msgstr ""
|
3284 |
|
3285 |
-
#: inc/class-page-editjob.php:
|
3286 |
msgid "Save changes"
|
3287 |
msgstr ""
|
3288 |
|
3289 |
-
#: inc/class-page-editjob.php:
|
3290 |
-
msgid "
|
|
|
3291 |
msgstr ""
|
3292 |
|
3293 |
-
#: inc/class-page-editjob.php:
|
3294 |
-
#, php-format
|
3295 |
msgid "ATTENTION: Job runs every %d minutes!"
|
3296 |
msgstr ""
|
3297 |
|
3298 |
-
#: inc/class-page-editjob.php:
|
3299 |
msgid "ATTENTION: Can't calculate cron!"
|
3300 |
msgstr ""
|
3301 |
|
3302 |
-
#: inc/class-page-editjob.php:
|
3303 |
msgid "Next runtime:"
|
3304 |
msgstr ""
|
3305 |
|
@@ -3321,7 +3324,6 @@ msgid "Last Run"
|
|
3321 |
msgstr ""
|
3322 |
|
3323 |
#: inc/class-page-jobs.php:172 inc/class-page-logs.php:200
|
3324 |
-
#, php-format
|
3325 |
msgid "Job ID: %d"
|
3326 |
msgstr ""
|
3327 |
|
@@ -3342,22 +3344,18 @@ msgid "Not needed or set"
|
|
3342 |
msgstr ""
|
3343 |
|
3344 |
#: inc/class-page-jobs.php:273
|
3345 |
-
#, php-format
|
3346 |
msgid "Running for: %s seconds"
|
3347 |
msgstr ""
|
3348 |
|
3349 |
#: inc/class-page-jobs.php:280 inc/class-page-jobs.php:289
|
3350 |
-
#, php-format
|
3351 |
msgid "Cron: %s"
|
3352 |
msgstr ""
|
3353 |
|
3354 |
#: inc/class-page-jobs.php:280
|
3355 |
-
#, php-format
|
3356 |
msgid "%1$s at %2$s by WP-Cron"
|
3357 |
msgstr ""
|
3358 |
|
3359 |
#: inc/class-page-jobs.php:289
|
3360 |
-
#, php-format
|
3361 |
msgid "%1$s at %2$s by EasyCron"
|
3362 |
msgstr ""
|
3363 |
|
@@ -3370,7 +3368,6 @@ msgid "Inactive"
|
|
3370 |
msgstr ""
|
3371 |
|
3372 |
#: inc/class-page-jobs.php:320
|
3373 |
-
#, php-format
|
3374 |
msgid "Runtime: %d seconds"
|
3375 |
msgstr ""
|
3376 |
|
@@ -3391,22 +3388,20 @@ msgid "Copy of"
|
|
3391 |
msgstr ""
|
3392 |
|
3393 |
#: inc/class-page-jobs.php:431
|
3394 |
-
#, php-format
|
3395 |
msgid "The job \"%s\" destination \"%s\" is not configured properly"
|
3396 |
msgstr ""
|
3397 |
|
3398 |
#: inc/class-page-jobs.php:436
|
3399 |
-
#, php-format
|
3400 |
msgid "The job \"%s\" needs properly configured destinations to run!"
|
3401 |
msgstr ""
|
3402 |
|
3403 |
#: inc/class-page-jobs.php:454
|
3404 |
-
|
3405 |
-
|
|
|
3406 |
msgstr ""
|
3407 |
|
3408 |
#: inc/class-page-jobs.php:459
|
3409 |
-
#, php-format
|
3410 |
msgid "Job \"%s\" started."
|
3411 |
msgstr ""
|
3412 |
|
@@ -3415,12 +3410,10 @@ msgid "Job will be terminated."
|
|
3415 |
msgstr ""
|
3416 |
|
3417 |
#: inc/class-page-jobs.php:584
|
3418 |
-
#, php-format
|
3419 |
msgid "%s › Jobs"
|
3420 |
msgstr ""
|
3421 |
|
3422 |
#: inc/class-page-jobs.php:604
|
3423 |
-
#, php-format
|
3424 |
msgid "Job currently running: %s"
|
3425 |
msgstr ""
|
3426 |
|
@@ -3453,8 +3446,9 @@ msgid "Job completed"
|
|
3453 |
msgstr ""
|
3454 |
|
3455 |
#: inc/class-page-jobs.php:786
|
3456 |
-
|
3457 |
-
|
|
|
3458 |
msgstr ""
|
3459 |
|
3460 |
#: inc/class-page-logs.php:113
|
@@ -3474,14 +3468,12 @@ msgid "View"
|
|
3474 |
msgstr ""
|
3475 |
|
3476 |
#: inc/class-page-logs.php:222
|
3477 |
-
#, php-format
|
3478 |
msgid "1 ERROR"
|
3479 |
msgid_plural "%d ERRORS"
|
3480 |
msgstr[0] ""
|
3481 |
msgstr[1] ""
|
3482 |
|
3483 |
#: inc/class-page-logs.php:225
|
3484 |
-
#, php-format
|
3485 |
msgid "1 WARNING"
|
3486 |
msgid_plural "%d WARNINGS"
|
3487 |
msgstr[0] ""
|
@@ -3496,7 +3488,6 @@ msgid "Log only"
|
|
3496 |
msgstr ""
|
3497 |
|
3498 |
#: inc/class-page-logs.php:391
|
3499 |
-
#, php-format
|
3500 |
msgid "%s › Logs"
|
3501 |
msgstr ""
|
3502 |
|
@@ -3504,451 +3495,477 @@ msgstr ""
|
|
3504 |
msgid "Logfile not found!"
|
3505 |
msgstr ""
|
3506 |
|
3507 |
-
#: inc/class-page-settings.php:
|
3508 |
msgid "Settings reset to default"
|
3509 |
msgstr ""
|
3510 |
|
3511 |
-
#: inc/class-page-settings.php:
|
3512 |
msgid "Settings saved"
|
3513 |
msgstr ""
|
3514 |
|
3515 |
-
#: inc/class-page-settings.php:
|
3516 |
-
#, php-format
|
3517 |
msgid "%s › Settings"
|
3518 |
msgstr ""
|
3519 |
|
3520 |
-
#: inc/class-page-settings.php:
|
3521 |
msgid "Network"
|
3522 |
msgstr ""
|
3523 |
|
3524 |
-
#: inc/class-page-settings.php:
|
3525 |
msgid "API Keys"
|
3526 |
msgstr ""
|
3527 |
|
3528 |
-
#: inc/class-page-settings.php:
|
3529 |
msgid "Information"
|
3530 |
msgstr ""
|
3531 |
|
3532 |
-
#: inc/class-page-settings.php:
|
3533 |
msgid "Display Settings"
|
3534 |
msgstr ""
|
3535 |
|
3536 |
-
#: inc/class-page-settings.php:
|
3537 |
msgid "Do you want to see BackWPup in the WordPress admin bar?"
|
3538 |
msgstr ""
|
3539 |
|
3540 |
-
#: inc/class-page-settings.php:
|
3541 |
msgid "Admin bar"
|
3542 |
msgstr ""
|
3543 |
|
3544 |
-
#: inc/class-page-settings.php:
|
3545 |
msgid "Admin Bar"
|
3546 |
msgstr ""
|
3547 |
|
3548 |
-
#: inc/class-page-settings.php:
|
3549 |
msgid "Show BackWPup links in admin bar."
|
3550 |
msgstr ""
|
3551 |
|
3552 |
-
#: inc/class-page-settings.php:
|
3553 |
msgid "Folder sizes"
|
3554 |
msgstr ""
|
3555 |
|
3556 |
-
#: inc/class-page-settings.php:
|
3557 |
-
msgid "
|
|
|
|
|
3558 |
msgstr ""
|
3559 |
|
3560 |
-
#: inc/class-page-settings.php:
|
3561 |
msgid "Security"
|
3562 |
msgstr ""
|
3563 |
|
3564 |
-
#: inc/class-page-settings.php:
|
3565 |
msgid "Security option for BackWPup"
|
3566 |
msgstr ""
|
3567 |
|
3568 |
-
#: inc/class-page-settings.php:
|
3569 |
msgid "Protect folders"
|
3570 |
msgstr ""
|
3571 |
|
3572 |
-
#: inc/class-page-settings.php:
|
3573 |
-
msgid "
|
|
|
|
|
3574 |
msgstr ""
|
3575 |
|
3576 |
-
#: inc/class-page-settings.php:
|
3577 |
-
msgid "
|
|
|
|
|
3578 |
msgstr ""
|
3579 |
|
3580 |
-
#: inc/class-page-settings.php:
|
3581 |
msgid "Log file folder"
|
3582 |
msgstr ""
|
3583 |
|
3584 |
-
#: inc/class-page-settings.php:
|
3585 |
-
#, php-format
|
3586 |
msgid "You can use absolute or relative path! Relative path is relative to %s."
|
3587 |
msgstr ""
|
3588 |
|
3589 |
-
#: inc/class-page-settings.php:
|
3590 |
msgid "Maximum log files"
|
3591 |
msgstr ""
|
3592 |
|
3593 |
-
#: inc/class-page-settings.php:
|
3594 |
msgid "Maximum log files in folder."
|
3595 |
msgstr ""
|
3596 |
|
3597 |
-
#: inc/class-page-settings.php:
|
3598 |
msgid "Compression"
|
3599 |
msgstr ""
|
3600 |
|
3601 |
-
#: inc/class-page-settings.php:
|
3602 |
msgid "Compress log files with GZip."
|
3603 |
msgstr ""
|
3604 |
|
3605 |
-
#: inc/class-page-settings.php:
|
3606 |
msgid "Logging Level"
|
3607 |
msgstr ""
|
3608 |
|
3609 |
-
#: inc/class-page-settings.php:
|
3610 |
msgid "Normal (translated)"
|
3611 |
msgstr ""
|
3612 |
|
3613 |
-
#: inc/class-page-settings.php:
|
3614 |
msgid "Normal (not translated)"
|
3615 |
msgstr ""
|
3616 |
|
3617 |
-
#: inc/class-page-settings.php:
|
3618 |
msgid "Debug (translated)"
|
3619 |
msgstr ""
|
3620 |
|
3621 |
-
#: inc/class-page-settings.php:
|
3622 |
msgid "Debug (not translated)"
|
3623 |
msgstr ""
|
3624 |
|
3625 |
-
#: inc/class-page-settings.php:
|
3626 |
-
msgid "
|
|
|
|
|
|
|
3627 |
msgstr ""
|
3628 |
|
3629 |
-
#: inc/class-page-settings.php:
|
3630 |
msgid "There are a couple of general options for backup jobs. Set them here."
|
3631 |
msgstr ""
|
3632 |
|
3633 |
-
#: inc/class-page-settings.php:
|
3634 |
msgid "Maximum number of retries for job steps"
|
3635 |
msgstr ""
|
3636 |
|
3637 |
-
#: inc/class-page-settings.php:
|
3638 |
msgid "Maximum script execution time"
|
3639 |
msgstr ""
|
3640 |
|
3641 |
-
#: inc/class-page-settings.php:
|
3642 |
msgid "Maximum PHP Script execution time"
|
3643 |
msgstr ""
|
3644 |
|
3645 |
-
#: inc/class-page-settings.php:
|
3646 |
msgid "seconds."
|
3647 |
msgstr ""
|
3648 |
|
3649 |
-
#: inc/class-page-settings.php:
|
3650 |
-
msgid "
|
|
|
|
|
|
|
|
|
3651 |
msgstr ""
|
3652 |
|
3653 |
-
#: inc/class-page-settings.php:
|
3654 |
msgid "Key to start jobs externally with an URL"
|
3655 |
msgstr ""
|
3656 |
|
3657 |
-
#: inc/class-page-settings.php:
|
3658 |
msgid "Will be used to protect job starts from unauthorized person."
|
3659 |
msgstr ""
|
3660 |
|
3661 |
-
#: inc/class-page-settings.php:
|
3662 |
msgid "Reduce server load"
|
3663 |
msgstr ""
|
3664 |
|
3665 |
-
#: inc/class-page-settings.php:
|
3666 |
msgid "disabled"
|
3667 |
msgstr ""
|
3668 |
|
3669 |
-
#: inc/class-page-settings.php:
|
3670 |
msgid "minimum"
|
3671 |
msgstr ""
|
3672 |
|
3673 |
-
#: inc/class-page-settings.php:
|
3674 |
msgid "medium"
|
3675 |
msgstr ""
|
3676 |
|
3677 |
-
#: inc/class-page-settings.php:
|
3678 |
msgid "maximum"
|
3679 |
msgstr ""
|
3680 |
|
3681 |
-
#: inc/class-page-settings.php:
|
3682 |
-
msgid "
|
|
|
3683 |
msgstr ""
|
3684 |
|
3685 |
-
#: inc/class-page-settings.php:
|
3686 |
msgid "Empty output on working"
|
3687 |
msgstr ""
|
3688 |
|
3689 |
-
#: inc/class-page-settings.php:
|
3690 |
msgid "Enable an empty Output on backup working."
|
3691 |
msgstr ""
|
3692 |
|
3693 |
-
#: inc/class-page-settings.php:
|
3694 |
-
msgid "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3695 |
msgstr ""
|
3696 |
|
3697 |
-
#: inc/class-page-settings.php:
|
3698 |
-
#, php-format
|
3699 |
msgid "Authentication for <code>%s</code>"
|
3700 |
msgstr ""
|
3701 |
|
3702 |
-
#: inc/class-page-settings.php:
|
3703 |
-
msgid "
|
|
|
|
|
|
|
3704 |
msgstr ""
|
3705 |
|
3706 |
-
#: inc/class-page-settings.php:
|
3707 |
msgid "Authentication method"
|
3708 |
msgstr ""
|
3709 |
|
3710 |
-
#: inc/class-page-settings.php:
|
3711 |
msgid "Basic auth"
|
3712 |
msgstr ""
|
3713 |
|
3714 |
-
#: inc/class-page-settings.php:
|
3715 |
msgid "WordPress User"
|
3716 |
msgstr ""
|
3717 |
|
3718 |
-
#: inc/class-page-settings.php:
|
3719 |
msgid "Query argument"
|
3720 |
msgstr ""
|
3721 |
|
3722 |
-
#: inc/class-page-settings.php:
|
3723 |
msgid "Basic Auth Username:"
|
3724 |
msgstr ""
|
3725 |
|
3726 |
-
#: inc/class-page-settings.php:
|
3727 |
msgid "Basic Auth Password:"
|
3728 |
msgstr ""
|
3729 |
|
3730 |
-
#: inc/class-page-settings.php:
|
3731 |
msgid "Select WordPress User"
|
3732 |
msgstr ""
|
3733 |
|
3734 |
-
#: inc/class-page-settings.php:
|
3735 |
msgid "Query arg key=value:"
|
3736 |
msgstr ""
|
3737 |
|
3738 |
-
#: inc/class-page-settings.php:
|
3739 |
msgid "Setting"
|
3740 |
msgstr ""
|
3741 |
|
3742 |
-
#: inc/class-page-settings.php:
|
3743 |
msgid "Value"
|
3744 |
msgstr ""
|
3745 |
|
3746 |
-
#: inc/class-page-settings.php:
|
3747 |
msgid "WordPress version"
|
3748 |
msgstr ""
|
3749 |
|
3750 |
-
#: inc/class-page-settings.php:
|
3751 |
msgid "BackWPup version"
|
3752 |
msgstr ""
|
3753 |
|
3754 |
-
#: inc/class-page-settings.php:
|
3755 |
msgid "Get pro."
|
3756 |
msgstr ""
|
3757 |
|
3758 |
-
#: inc/class-page-settings.php:
|
3759 |
msgid "BackWPup Pro version"
|
3760 |
msgstr ""
|
3761 |
|
3762 |
-
#: inc/class-page-settings.php:
|
3763 |
msgid "PHP version"
|
3764 |
msgstr ""
|
3765 |
|
3766 |
-
#: inc/class-page-settings.php:
|
3767 |
msgid "MySQL version"
|
3768 |
msgstr ""
|
3769 |
|
3770 |
-
#: inc/class-page-settings.php:
|
3771 |
msgid "cURL version"
|
3772 |
msgstr ""
|
3773 |
|
3774 |
-
#: inc/class-page-settings.php:
|
3775 |
msgid "cURL SSL version"
|
3776 |
msgstr ""
|
3777 |
|
3778 |
-
#: inc/class-page-settings.php:
|
3779 |
msgid "unavailable"
|
3780 |
msgstr ""
|
3781 |
|
3782 |
-
#: inc/class-page-settings.php:
|
3783 |
msgid "WP-Cron url:"
|
3784 |
msgstr ""
|
3785 |
|
3786 |
-
#: inc/class-page-settings.php:
|
3787 |
msgid "Server self connect:"
|
3788 |
msgstr ""
|
3789 |
|
3790 |
-
#: inc/class-page-settings.php:
|
3791 |
msgid "<strong>Not expected HTTP response:</strong><br>"
|
3792 |
msgstr ""
|
3793 |
|
3794 |
-
#: inc/class-page-settings.php:
|
3795 |
-
#, php-format
|
3796 |
msgid "WP Http Error: <code>%s</code>"
|
3797 |
msgstr ""
|
3798 |
|
3799 |
-
#: inc/class-page-settings.php:
|
3800 |
-
#, php-format
|
3801 |
msgid "Status-Code: <code>%d</code>"
|
3802 |
msgstr ""
|
3803 |
|
3804 |
-
#: inc/class-page-settings.php:
|
3805 |
-
#, php-format
|
3806 |
msgid "Content: <code>%s</code>"
|
3807 |
msgstr ""
|
3808 |
|
3809 |
-
#: inc/class-page-settings.php:
|
3810 |
msgid "Response Test O.K."
|
3811 |
msgstr ""
|
3812 |
|
3813 |
-
#: inc/class-page-settings.php:
|
3814 |
msgid "Temp folder:"
|
3815 |
msgstr ""
|
3816 |
|
3817 |
-
#: inc/class-page-settings.php:
|
3818 |
-
#, php-format
|
3819 |
msgid "Temp folder %s doesn't exist."
|
3820 |
msgstr ""
|
3821 |
|
3822 |
-
#: inc/class-page-settings.php:
|
3823 |
-
#, php-format
|
3824 |
msgid "Temporary folder %s is not writable."
|
3825 |
msgstr ""
|
3826 |
|
3827 |
-
#: inc/class-page-settings.php:
|
3828 |
msgid "Log folder:"
|
3829 |
msgstr ""
|
3830 |
|
3831 |
-
#: inc/class-page-settings.php:
|
3832 |
-
#, php-format
|
3833 |
msgid "Logs folder %s not exist."
|
3834 |
msgstr ""
|
3835 |
|
3836 |
-
#: inc/class-page-settings.php:
|
3837 |
-
#, php-format
|
3838 |
msgid "Log folder %s is not writable."
|
3839 |
msgstr ""
|
3840 |
|
3841 |
-
#: inc/class-page-settings.php:
|
3842 |
msgid "Server"
|
3843 |
msgstr ""
|
3844 |
|
3845 |
-
#: inc/class-page-settings.php:
|
3846 |
msgid "Operating System"
|
3847 |
msgstr ""
|
3848 |
|
3849 |
-
#: inc/class-page-settings.php:
|
3850 |
msgid "PHP SAPI"
|
3851 |
msgstr ""
|
3852 |
|
3853 |
-
#: inc/class-page-settings.php:
|
3854 |
msgid "Function Disabled"
|
3855 |
msgstr ""
|
3856 |
|
3857 |
-
#: inc/class-page-settings.php:
|
3858 |
msgid "Current PHP user"
|
3859 |
msgstr ""
|
3860 |
|
3861 |
-
#: inc/class-page-settings.php:
|
3862 |
msgid "Maximum execution time"
|
3863 |
msgstr ""
|
3864 |
|
3865 |
-
#: inc/class-page-settings.php:
|
3866 |
msgid "Alternative WP Cron"
|
3867 |
msgstr ""
|
3868 |
|
3869 |
-
#: inc/class-page-settings.php:
|
3870 |
msgid "On"
|
3871 |
msgstr ""
|
3872 |
|
3873 |
-
#: inc/class-page-settings.php:
|
3874 |
msgid "Off"
|
3875 |
msgstr ""
|
3876 |
|
3877 |
-
#: inc/class-page-settings.php:
|
3878 |
msgid "Disabled WP Cron"
|
3879 |
msgstr ""
|
3880 |
|
3881 |
-
#: inc/class-page-settings.php:
|
3882 |
msgid "CHMOD Dir"
|
3883 |
msgstr ""
|
3884 |
|
3885 |
-
#: inc/class-page-settings.php:
|
3886 |
msgid "Server Time"
|
3887 |
msgstr ""
|
3888 |
|
3889 |
-
#: inc/class-page-settings.php:
|
3890 |
msgid "Blog Time"
|
3891 |
msgstr ""
|
3892 |
|
3893 |
-
#: inc/class-page-settings.php:
|
3894 |
msgid "Blog Timezone"
|
3895 |
msgstr ""
|
3896 |
|
3897 |
-
#: inc/class-page-settings.php:
|
3898 |
msgid "Blog Time offset"
|
3899 |
msgstr ""
|
3900 |
|
3901 |
-
#: inc/class-page-settings.php:
|
3902 |
-
#, php-format
|
3903 |
msgid "%s hours"
|
3904 |
msgstr ""
|
3905 |
|
3906 |
-
#: inc/class-page-settings.php:
|
3907 |
msgid "Blog language"
|
3908 |
msgstr ""
|
3909 |
|
3910 |
-
#: inc/class-page-settings.php:
|
3911 |
msgid "MySQL Client encoding"
|
3912 |
msgstr ""
|
3913 |
|
3914 |
-
#: inc/class-page-settings.php:
|
3915 |
msgid "Blog charset"
|
3916 |
msgstr ""
|
3917 |
|
3918 |
-
#: inc/class-page-settings.php:
|
3919 |
msgid "PHP Memory limit"
|
3920 |
msgstr ""
|
3921 |
|
3922 |
-
#: inc/class-page-settings.php:
|
3923 |
msgid "WP memory limit"
|
3924 |
msgstr ""
|
3925 |
|
3926 |
-
#: inc/class-page-settings.php:
|
3927 |
msgid "WP maximum memory limit"
|
3928 |
msgstr ""
|
3929 |
|
3930 |
-
#: inc/class-page-settings.php:
|
3931 |
msgid "Memory in use"
|
3932 |
msgstr ""
|
3933 |
|
3934 |
-
#: inc/class-page-settings.php:
|
3935 |
msgid "Disabled PHP Functions:"
|
3936 |
msgstr ""
|
3937 |
|
3938 |
-
#: inc/class-page-settings.php:
|
3939 |
msgid "Loaded PHP Extensions:"
|
3940 |
msgstr ""
|
3941 |
|
3942 |
-
#: inc/class-page-settings.php:
|
3943 |
msgid "Save Changes"
|
3944 |
msgstr ""
|
3945 |
|
3946 |
-
#: inc/class-page-settings.php:
|
3947 |
msgid "Reset all settings to default"
|
3948 |
msgstr ""
|
3949 |
|
3950 |
#: inc/class-php-admin-notice.php:123
|
3951 |
-
msgid "
|
|
|
|
|
3952 |
msgstr ""
|
3953 |
|
3954 |
#: inc/class-php-admin-notice.php:125
|
@@ -3964,23 +3981,33 @@ msgid "Don't show again."
|
|
3964 |
msgstr ""
|
3965 |
|
3966 |
#: inc/class-php-admin-notice.php:164
|
3967 |
-
msgid "
|
|
|
|
|
3968 |
msgstr ""
|
3969 |
|
3970 |
#: inc/class-php-admin-notice.php:167
|
3971 |
-
msgid "
|
|
|
|
|
3972 |
msgstr ""
|
3973 |
|
3974 |
#: inc/class-php-admin-notice.php:168
|
3975 |
-
msgid "
|
|
|
|
|
3976 |
msgstr ""
|
3977 |
|
3978 |
#: inc/class-php-admin-notice.php:169
|
3979 |
-
msgid "
|
|
|
|
|
3980 |
msgstr ""
|
3981 |
|
3982 |
#: inc/class-php-admin-notice.php:173
|
3983 |
-
msgid "
|
|
|
|
|
3984 |
msgstr ""
|
3985 |
|
3986 |
#: inc/class-php-admin-notice.php:176
|
@@ -3991,14 +4018,15 @@ msgstr ""
|
|
3991 |
msgid "Your BackWPup Team!"
|
3992 |
msgstr ""
|
3993 |
|
3994 |
-
#.
|
|
|
3995 |
#: inc/class-php-admin-notice.php:205
|
3996 |
msgid "contact us"
|
3997 |
msgstr ""
|
3998 |
|
3999 |
-
#.
|
|
|
4000 |
#: inc/class-php-admin-notice.php:207
|
4001 |
-
#, php-format
|
4002 |
msgid "If you would like to have PHP 5.2 supported, please %s."
|
4003 |
msgstr ""
|
4004 |
|
@@ -4026,61 +4054,52 @@ msgstr ""
|
|
4026 |
msgid "No job running"
|
4027 |
msgstr ""
|
4028 |
|
4029 |
-
#: inc/pro/class-destination-dropbox.php:
|
4030 |
msgid "Auth Code:"
|
4031 |
msgstr ""
|
4032 |
|
4033 |
-
#: inc/pro/class-destination-dropbox.php:
|
4034 |
msgid "Get auth code"
|
4035 |
msgstr ""
|
4036 |
|
4037 |
-
#: inc/pro/class-destination-dropbox.php:
|
4038 |
-
#: inc/pro/class-destination-gdrive.php:
|
4039 |
-
#: inc/pro/class-destination-gdrive.php:
|
4040 |
#: inc/pro/class-destination-sugarsync.php:30
|
4041 |
msgid "Login:"
|
4042 |
msgstr ""
|
4043 |
|
4044 |
-
#: inc/pro/class-destination-dropbox.php:
|
4045 |
-
#: inc/pro/class-destination-gdrive.php:
|
4046 |
#: inc/pro/class-destination-sugarsync.php:56
|
4047 |
msgid "Folder:"
|
4048 |
msgstr ""
|
4049 |
|
4050 |
-
#: inc/pro/class-destination-dropbox.php:
|
4051 |
-
#, php-format
|
4052 |
msgid "%d. Try to sync files to Dropbox …"
|
4053 |
msgstr ""
|
4054 |
|
4055 |
-
#: inc/pro/class-destination-dropbox.php:
|
4056 |
msgid "Retrieving file list from Dropbox"
|
4057 |
msgstr ""
|
4058 |
|
4059 |
-
#: inc/pro/class-destination-dropbox.php:
|
4060 |
msgid "Upload changed files to Dropbox"
|
4061 |
msgstr ""
|
4062 |
|
4063 |
-
#: inc/pro/class-destination-dropbox.php:
|
4064 |
-
#, php-format
|
4065 |
msgid "File %s uploaded to Dropbox"
|
4066 |
msgstr ""
|
4067 |
|
4068 |
-
#: inc/pro/class-destination-dropbox.php:
|
4069 |
-
#, php-format
|
4070 |
msgid "Extra file %s uploaded to Dropbox"
|
4071 |
msgstr ""
|
4072 |
|
4073 |
-
#: inc/pro/class-destination-dropbox.php:
|
4074 |
-
msgid "Delete not existing files from Dropbox"
|
4075 |
-
msgstr ""
|
4076 |
-
|
4077 |
-
#: inc/pro/class-destination-dropbox.php:237
|
4078 |
-
#, php-format
|
4079 |
msgid "Folder %s deleted from Dropbox"
|
4080 |
msgstr ""
|
4081 |
|
4082 |
-
#: inc/pro/class-destination-dropbox.php:
|
4083 |
-
#, php-format
|
4084 |
msgid "File %s deleted from Dropbox"
|
4085 |
msgstr ""
|
4086 |
|
@@ -4089,12 +4108,11 @@ msgid "Absolute path to folder for backup files:"
|
|
4089 |
msgstr ""
|
4090 |
|
4091 |
#: inc/pro/class-destination-folder.php:41
|
4092 |
-
#: inc/pro/class-destination-gdrive.php:
|
4093 |
msgid "Oldest files will be deleted first."
|
4094 |
msgstr ""
|
4095 |
|
4096 |
#: inc/pro/class-destination-folder.php:87
|
4097 |
-
#, php-format
|
4098 |
msgid "%d. Try to sync files to folder …"
|
4099 |
msgstr ""
|
4100 |
|
@@ -4102,31 +4120,27 @@ msgstr ""
|
|
4102 |
msgid "Retrieving file list from folder"
|
4103 |
msgstr ""
|
4104 |
|
4105 |
-
#: inc/pro/class-destination-folder.php:
|
4106 |
msgid "Copy changed files to folder"
|
4107 |
msgstr ""
|
4108 |
|
4109 |
-
#: inc/pro/class-destination-folder.php:
|
4110 |
-
#, php-format
|
4111 |
msgid "File %s copied"
|
4112 |
msgstr ""
|
4113 |
|
4114 |
-
#: inc/pro/class-destination-folder.php:
|
4115 |
msgid "Delete not existing files from folder"
|
4116 |
msgstr ""
|
4117 |
|
4118 |
-
#: inc/pro/class-destination-folder.php:
|
4119 |
-
#, php-format
|
4120 |
msgid "Extra file %s copied"
|
4121 |
msgstr ""
|
4122 |
|
4123 |
-
#: inc/pro/class-destination-folder.php:
|
4124 |
-
#, php-format
|
4125 |
msgid "File %s deleted from folder"
|
4126 |
msgstr ""
|
4127 |
|
4128 |
-
#: inc/pro/class-destination-folder.php:
|
4129 |
-
#, php-format
|
4130 |
msgid "Empty folder %s deleted"
|
4131 |
msgstr ""
|
4132 |
|
@@ -4148,18 +4162,20 @@ msgid "Maximum number of backup files to keep in folder:"
|
|
4148 |
msgstr ""
|
4149 |
|
4150 |
#: inc/pro/class-destination-gdrive.php:41
|
4151 |
-
#: inc/pro/class-destination-gdrive.php:
|
4152 |
-
|
4153 |
-
|
|
|
|
|
4154 |
msgstr ""
|
4155 |
|
4156 |
#: inc/pro/class-destination-gdrive.php:55
|
4157 |
-
#: inc/pro/class-destination-gdrive.php:
|
4158 |
msgid "Authenticate"
|
4159 |
msgstr ""
|
4160 |
|
4161 |
#: inc/pro/class-destination-gdrive.php:62
|
4162 |
-
#: inc/pro/class-destination-gdrive.php:
|
4163 |
msgid "Reauthenticate"
|
4164 |
msgstr ""
|
4165 |
|
@@ -4167,104 +4183,94 @@ msgstr ""
|
|
4167 |
msgid "Folder in Google Drive"
|
4168 |
msgstr ""
|
4169 |
|
4170 |
-
#: inc/pro/class-destination-gdrive.php:
|
4171 |
-
msgid "
|
|
|
|
|
4172 |
msgstr ""
|
4173 |
|
4174 |
-
#: inc/pro/class-destination-gdrive.php:
|
4175 |
-
#: inc/pro/class-destination-gdrive.php:
|
4176 |
msgid "GDrive: Authenticated."
|
4177 |
msgstr ""
|
4178 |
|
4179 |
-
#: inc/pro/class-destination-gdrive.php:
|
4180 |
-
#: inc/pro/class-destination-gdrive.php:
|
4181 |
msgid "GDrive: No refresh token received. Try to Authenticate again!"
|
4182 |
msgstr ""
|
4183 |
|
4184 |
-
#: inc/pro/class-destination-gdrive.php:
|
4185 |
-
#: inc/pro/class-destination-gdrive.php:
|
4186 |
-
#: inc/pro/class-destination-gdrive.php:
|
4187 |
-
#: inc/pro/class-destination-gdrive.php:
|
4188 |
-
#, php-format
|
4189 |
msgid "GDrive API: %s"
|
4190 |
msgstr ""
|
4191 |
|
4192 |
-
#: inc/pro/class-destination-gdrive.php:
|
4193 |
-
#, php-format
|
4194 |
msgid "%d. Try to send backup file to Google Drive …"
|
4195 |
msgstr ""
|
4196 |
|
4197 |
-
#: inc/pro/class-destination-gdrive.php:
|
4198 |
msgid "Uploading to Google Drive …"
|
4199 |
msgstr ""
|
4200 |
|
4201 |
-
#: inc/pro/class-destination-gdrive.php:
|
4202 |
msgid "Could not create resumable file transfer to Google Drive"
|
4203 |
msgstr ""
|
4204 |
|
4205 |
-
#: inc/pro/class-destination-gdrive.php:
|
4206 |
msgid "Can not resume transfer backup to Google Drive!"
|
4207 |
msgstr ""
|
4208 |
|
4209 |
-
#: inc/pro/class-destination-gdrive.php:
|
4210 |
-
#, php-format
|
4211 |
msgid "Error transfering file chunks to %s."
|
4212 |
msgstr ""
|
4213 |
|
4214 |
-
#: inc/pro/class-destination-gdrive.php:
|
4215 |
-
#: inc/pro/class-destination-gdrive.php:
|
4216 |
msgid "Google Drive"
|
4217 |
msgstr ""
|
4218 |
|
4219 |
-
#: inc/pro/class-destination-gdrive.php:
|
4220 |
-
#, php-format
|
4221 |
msgid "One file deleted from Google Drive"
|
4222 |
msgid_plural "%d files deleted on Google Drive"
|
4223 |
msgstr[0] ""
|
4224 |
msgstr[1] ""
|
4225 |
|
4226 |
-
#: inc/pro/class-destination-gdrive.php:
|
4227 |
-
#: inc/pro/class-destination-gdrive.php:
|
4228 |
-
#, php-format
|
4229 |
msgid "Google Drive API: %s"
|
4230 |
msgstr ""
|
4231 |
|
4232 |
-
#: inc/pro/class-destination-gdrive.php:
|
4233 |
-
#, php-format
|
4234 |
msgid "%d. Try to sync files to Google Drive …"
|
4235 |
msgstr ""
|
4236 |
|
4237 |
-
#: inc/pro/class-destination-gdrive.php:
|
4238 |
msgid "Syncing changed files to Google Drive"
|
4239 |
msgstr ""
|
4240 |
|
4241 |
-
#: inc/pro/class-destination-gdrive.php:
|
4242 |
-
#, php-format
|
4243 |
msgid "File %s updated on Google Drive"
|
4244 |
msgstr ""
|
4245 |
|
4246 |
-
#: inc/pro/class-destination-gdrive.php:
|
4247 |
-
#, php-format
|
4248 |
msgid "File %s uploaded to Google Drive"
|
4249 |
msgstr ""
|
4250 |
|
4251 |
-
#: inc/pro/class-destination-gdrive.php:
|
4252 |
-
#, php-format
|
4253 |
msgid "File %s moved to trash in Google Drive"
|
4254 |
msgstr ""
|
4255 |
|
4256 |
-
#: inc/pro/class-destination-gdrive.php:
|
4257 |
-
#, php-format
|
4258 |
msgid "File %s deleted permanently in Google Drive"
|
4259 |
msgstr ""
|
4260 |
|
4261 |
-
#: inc/pro/class-destination-gdrive.php:
|
4262 |
-
#, php-format
|
4263 |
msgid "Extra file %s updated on Google Drive"
|
4264 |
msgstr ""
|
4265 |
|
4266 |
-
#: inc/pro/class-destination-gdrive.php:
|
4267 |
-
#, php-format
|
4268 |
msgid "Extra file %s uploaded to Google Drive"
|
4269 |
msgstr ""
|
4270 |
|
@@ -4277,42 +4283,42 @@ msgid "Select a region:"
|
|
4277 |
msgstr ""
|
4278 |
|
4279 |
#: inc/pro/class-destination-glacier.php:33
|
4280 |
-
#: inc/pro/class-destination-glacier.php:
|
4281 |
msgid "Amazon Glacier Region"
|
4282 |
msgstr ""
|
4283 |
|
4284 |
#: inc/pro/class-destination-glacier.php:34
|
4285 |
-
#: inc/pro/class-destination-glacier.php:
|
4286 |
msgid "US Standard"
|
4287 |
msgstr ""
|
4288 |
|
4289 |
#: inc/pro/class-destination-glacier.php:35
|
4290 |
-
#: inc/pro/class-destination-glacier.php:
|
4291 |
msgid "US West (Northern California)"
|
4292 |
msgstr ""
|
4293 |
|
4294 |
#: inc/pro/class-destination-glacier.php:36
|
4295 |
-
#: inc/pro/class-destination-glacier.php:
|
4296 |
msgid "US West (Oregon)"
|
4297 |
msgstr ""
|
4298 |
|
4299 |
#: inc/pro/class-destination-glacier.php:37
|
4300 |
-
#: inc/pro/class-destination-glacier.php:
|
4301 |
msgid "EU (Ireland)"
|
4302 |
msgstr ""
|
4303 |
|
4304 |
#: inc/pro/class-destination-glacier.php:38
|
4305 |
-
#: inc/pro/class-destination-glacier.php:
|
4306 |
msgid "EU (Germany)"
|
4307 |
msgstr ""
|
4308 |
|
4309 |
#: inc/pro/class-destination-glacier.php:39
|
4310 |
-
#: inc/pro/class-destination-glacier.php:
|
4311 |
msgid "Asia Pacific (Tokyo)"
|
4312 |
msgstr ""
|
4313 |
|
4314 |
#: inc/pro/class-destination-glacier.php:40
|
4315 |
-
#: inc/pro/class-destination-glacier.php:
|
4316 |
msgid "Asia Pacific (Seoul)"
|
4317 |
msgstr ""
|
4318 |
|
@@ -4321,17 +4327,17 @@ msgid "Asia Pacific (Mumbai)"
|
|
4321 |
msgstr ""
|
4322 |
|
4323 |
#: inc/pro/class-destination-glacier.php:42
|
4324 |
-
#: inc/pro/class-destination-glacier.php:
|
4325 |
msgid "Asia Pacific (Sydney)"
|
4326 |
msgstr ""
|
4327 |
|
4328 |
#: inc/pro/class-destination-glacier.php:43
|
4329 |
-
#: inc/pro/class-destination-glacier.php:
|
4330 |
msgid "South America (Sao Paulo)"
|
4331 |
msgstr ""
|
4332 |
|
4333 |
#: inc/pro/class-destination-glacier.php:44
|
4334 |
-
#: inc/pro/class-destination-glacier.php:
|
4335 |
msgid "China (Beijing)"
|
4336 |
msgstr ""
|
4337 |
|
@@ -4356,96 +4362,89 @@ msgid "Glacier Backup settings"
|
|
4356 |
msgstr ""
|
4357 |
|
4358 |
#: inc/pro/class-destination-glacier.php:108
|
4359 |
-
#: inc/pro/class-destination-glacier.php:
|
4360 |
-
msgid "
|
|
|
|
|
4361 |
msgstr ""
|
4362 |
|
4363 |
-
#: inc/pro/class-destination-glacier.php:
|
4364 |
msgid "No vault found!"
|
4365 |
msgstr ""
|
4366 |
|
4367 |
-
#: inc/pro/class-destination-glacier.php:
|
4368 |
-
#: inc/pro/class-destination-glacier.php:
|
4369 |
-
#, php-format
|
4370 |
msgid "Vault %1$s created."
|
4371 |
msgstr ""
|
4372 |
|
4373 |
-
#: inc/pro/class-destination-glacier.php:
|
4374 |
-
#: inc/pro/class-destination-glacier.php:
|
4375 |
-
#, php-format
|
4376 |
msgid "Vault %s could not be created."
|
4377 |
msgstr ""
|
4378 |
|
4379 |
-
#: inc/pro/class-destination-glacier.php:
|
4380 |
msgid "Select an Amazon Glacier region:"
|
4381 |
msgstr ""
|
4382 |
|
4383 |
-
#: inc/pro/class-destination-glacier.php:
|
4384 |
msgid "Asia Pacific (Singapore)"
|
4385 |
msgstr ""
|
4386 |
|
4387 |
-
#: inc/pro/class-destination-glacier.php:
|
4388 |
#: inc/pro/class-destination-msazure.php:19
|
4389 |
-
#: inc/pro/class-destination-s3.php:
|
4390 |
msgid "Access Key:"
|
4391 |
msgstr ""
|
4392 |
|
4393 |
-
#: inc/pro/class-destination-glacier.php:
|
4394 |
-
#: inc/pro/class-destination-s3.php:
|
4395 |
msgid "Secret Key:"
|
4396 |
msgstr ""
|
4397 |
|
4398 |
-
#: inc/pro/class-destination-glacier.php:
|
4399 |
msgid "Vault:"
|
4400 |
msgstr ""
|
4401 |
|
4402 |
-
#: inc/pro/class-destination-glacier.php:
|
4403 |
msgid "New Vault:"
|
4404 |
msgstr ""
|
4405 |
|
4406 |
-
#: inc/pro/class-destination-glacier.php:
|
4407 |
-
#: inc/pro/class-destination-glacier.php:
|
4408 |
-
#: inc/pro/class-destination-glacier.php:
|
4409 |
-
#: inc/pro/class-destination-glacier.php:
|
4410 |
-
#, php-format
|
4411 |
msgid "AWS API: %s"
|
4412 |
msgstr ""
|
4413 |
|
4414 |
-
#: inc/pro/class-destination-glacier.php:
|
4415 |
-
#, php-format
|
4416 |
msgid "%d. Trying to send backup file to Amazon Glacier …"
|
4417 |
msgstr ""
|
4418 |
|
4419 |
-
#: inc/pro/class-destination-glacier.php:
|
4420 |
-
#, php-format
|
4421 |
msgid "Connected to Glacier vault \"%1$s\" with %2$d archives and size of %3$d"
|
4422 |
msgstr ""
|
4423 |
|
4424 |
-
#: inc/pro/class-destination-glacier.php:
|
4425 |
-
#, php-format
|
4426 |
msgid "Glacier vault \"%s\" does not exist!"
|
4427 |
msgstr ""
|
4428 |
|
4429 |
-
#: inc/pro/class-destination-glacier.php:
|
4430 |
msgid "Starting upload to Amazon Glacier …"
|
4431 |
msgstr ""
|
4432 |
|
4433 |
-
#: inc/pro/class-destination-glacier.php:
|
4434 |
-
#, php-format
|
4435 |
msgid "Archive ID: %s"
|
4436 |
msgstr ""
|
4437 |
|
4438 |
-
#: inc/pro/class-destination-glacier.php:
|
4439 |
msgid "Glacier"
|
4440 |
msgstr ""
|
4441 |
|
4442 |
-
#: inc/pro/class-destination-glacier.php:
|
4443 |
-
#, php-format
|
4444 |
msgid "Cannot delete archive from %s."
|
4445 |
msgstr ""
|
4446 |
|
4447 |
-
#: inc/pro/class-destination-glacier.php:
|
4448 |
-
#, php-format
|
4449 |
msgid "One file deleted on vault."
|
4450 |
msgid_plural "%d files deleted on vault"
|
4451 |
msgstr[0] ""
|
@@ -4471,7 +4470,6 @@ msgid "Folder in container:"
|
|
4471 |
msgstr ""
|
4472 |
|
4473 |
#: inc/pro/class-destination-msazure.php:119
|
4474 |
-
#, php-format
|
4475 |
msgid "%d. Trying to sync files with Microsoft Azure (Blob) …"
|
4476 |
msgstr ""
|
4477 |
|
@@ -4484,12 +4482,10 @@ msgid "Upload changed files to MS Azure."
|
|
4484 |
msgstr ""
|
4485 |
|
4486 |
#: inc/pro/class-destination-msazure.php:182
|
4487 |
-
#, php-format
|
4488 |
msgid "File %s uploaded to MS Azure."
|
4489 |
msgstr ""
|
4490 |
|
4491 |
#: inc/pro/class-destination-msazure.php:208
|
4492 |
-
#, php-format
|
4493 |
msgid "Extra file %s uploaded to MS Azure."
|
4494 |
msgstr ""
|
4495 |
|
@@ -4498,7 +4494,6 @@ msgid "Delete nonexistent files on MS Azure."
|
|
4498 |
msgstr ""
|
4499 |
|
4500 |
#: inc/pro/class-destination-msazure.php:224
|
4501 |
-
#, php-format
|
4502 |
msgid "File %s deleted from MS Azure."
|
4503 |
msgstr ""
|
4504 |
|
@@ -4511,12 +4506,10 @@ msgid "Select region:"
|
|
4511 |
msgstr ""
|
4512 |
|
4513 |
#: inc/pro/class-destination-rsc.php:147
|
4514 |
-
#, php-format
|
4515 |
msgid "%d. Trying to sync files to Rackspace cloud …"
|
4516 |
msgstr ""
|
4517 |
|
4518 |
#: inc/pro/class-destination-rsc.php:167
|
4519 |
-
#, php-format
|
4520 |
msgid "Connected to Rackspace cloud files container %s."
|
4521 |
msgstr ""
|
4522 |
|
@@ -4529,12 +4522,10 @@ msgid "Upload changed files to Rackspace Cloud."
|
|
4529 |
msgstr ""
|
4530 |
|
4531 |
#: inc/pro/class-destination-rsc.php:230
|
4532 |
-
#, php-format
|
4533 |
msgid "File %s uploaded to Rackspace Cloud."
|
4534 |
msgstr ""
|
4535 |
|
4536 |
#: inc/pro/class-destination-rsc.php:263
|
4537 |
-
#, php-format
|
4538 |
msgid "Extra file %s uploaded to Rackspace Cloud."
|
4539 |
msgstr ""
|
4540 |
|
@@ -4543,7 +4534,6 @@ msgid "Delete nonexistent files on Rackspace Cloud."
|
|
4543 |
msgstr ""
|
4544 |
|
4545 |
#: inc/pro/class-destination-rsc.php:280
|
4546 |
-
#, php-format
|
4547 |
msgid "File %s deleted from Rackspace Cloud."
|
4548 |
msgstr ""
|
4549 |
|
@@ -4551,56 +4541,51 @@ msgstr ""
|
|
4551 |
msgid "Select a S3 service:"
|
4552 |
msgstr ""
|
4553 |
|
4554 |
-
#: inc/pro/class-destination-s3.php:
|
4555 |
msgid "or set an S3 Server URL:"
|
4556 |
msgstr ""
|
4557 |
|
4558 |
-
#: inc/pro/class-destination-s3.php:
|
4559 |
msgid "Bucket:"
|
4560 |
msgstr ""
|
4561 |
|
4562 |
-
#: inc/pro/class-destination-s3.php:
|
4563 |
msgid "New Bucket:"
|
4564 |
msgstr ""
|
4565 |
|
4566 |
-
#: inc/pro/class-destination-s3.php:
|
4567 |
msgid "Folder in bucket:"
|
4568 |
msgstr ""
|
4569 |
|
4570 |
-
#: inc/pro/class-destination-s3.php:
|
4571 |
-
#, php-format
|
4572 |
msgid "Bucket %1$s created in %2$s."
|
4573 |
msgstr ""
|
4574 |
|
4575 |
-
#: inc/pro/class-destination-s3.php:
|
4576 |
-
#, php-format
|
4577 |
msgid "%d. Trying to sync files to S3 Service …"
|
4578 |
msgstr ""
|
4579 |
|
4580 |
-
#: inc/pro/class-destination-s3.php:
|
4581 |
msgid "Retrieving file list from S3."
|
4582 |
msgstr ""
|
4583 |
|
4584 |
-
#: inc/pro/class-destination-s3.php:
|
4585 |
msgid "Upload changed files to S3."
|
4586 |
msgstr ""
|
4587 |
|
4588 |
-
#: inc/pro/class-destination-s3.php:
|
4589 |
-
#, php-format
|
4590 |
msgid "File %s uploaded to S3."
|
4591 |
msgstr ""
|
4592 |
|
4593 |
-
#: inc/pro/class-destination-s3.php:
|
4594 |
-
#, php-format
|
4595 |
msgid "Extra file %s uploaded to S3."
|
4596 |
msgstr ""
|
4597 |
|
4598 |
-
#: inc/pro/class-destination-s3.php:
|
4599 |
msgid "Delete nonexistent files on S3"
|
4600 |
msgstr ""
|
4601 |
|
4602 |
-
#: inc/pro/class-destination-s3.php:
|
4603 |
-
#, php-format
|
4604 |
msgid "File %s deleted from S3."
|
4605 |
msgstr ""
|
4606 |
|
@@ -4670,35 +4655,34 @@ msgid "Path to <em>mysqldump</em> file"
|
|
4670 |
msgstr ""
|
4671 |
|
4672 |
#: inc/pro/class-jobtype-dbdump.php:190
|
4673 |
-
msgid "
|
|
|
|
|
|
|
4674 |
msgstr ""
|
4675 |
|
4676 |
#: inc/pro/class-jobtype-dbdump.php:580
|
4677 |
-
#, php-format
|
4678 |
msgid "Added database backup \"%1$s\" with %2$s to backup file list"
|
4679 |
msgstr ""
|
4680 |
|
4681 |
#: inc/pro/class-jobtype-dbdump.php:601
|
4682 |
-
#, php-format
|
4683 |
msgid "%d. Try to backup MySQL system …"
|
4684 |
msgstr ""
|
4685 |
|
4686 |
#: inc/pro/class-jobtype-dbdump.php:608
|
4687 |
-
msgid "
|
|
|
4688 |
msgstr ""
|
4689 |
|
4690 |
#: inc/pro/class-jobtype-dbdump.php:613
|
4691 |
-
#, php-format
|
4692 |
msgid "%s file not in open basedir of PHP."
|
4693 |
msgstr ""
|
4694 |
|
4695 |
#: inc/pro/class-jobtype-dbdump.php:618
|
4696 |
-
#, php-format
|
4697 |
msgid "%s file not found. Please correct the path for the mysqldump file."
|
4698 |
msgstr ""
|
4699 |
|
4700 |
#: inc/pro/class-jobtype-dbdump.php:702
|
4701 |
-
#, php-format
|
4702 |
msgctxt "Executed exec() command"
|
4703 |
msgid "CLI Exec: %s"
|
4704 |
msgstr ""
|
@@ -4708,7 +4692,9 @@ msgid "Usage error."
|
|
4708 |
msgstr ""
|
4709 |
|
4710 |
#: inc/pro/class-jobtype-dbdump.php:713
|
4711 |
-
msgid "
|
|
|
|
|
4712 |
msgstr ""
|
4713 |
|
4714 |
#: inc/pro/class-jobtype-dbdump.php:714
|
@@ -4728,7 +4714,6 @@ msgid "Illegal table"
|
|
4728 |
msgstr ""
|
4729 |
|
4730 |
#: inc/pro/class-jobtype-dbdump.php:722
|
4731 |
-
#, php-format
|
4732 |
msgid "mysqldump returned: (%d) %s"
|
4733 |
msgstr ""
|
4734 |
|
@@ -4737,12 +4722,10 @@ msgid "Can not create mysql backup with mysqldump command"
|
|
4737 |
msgstr ""
|
4738 |
|
4739 |
#: inc/pro/class-jobtype-dbdump.php:781
|
4740 |
-
#, php-format
|
4741 |
msgid "%d. Try to backup database as XML …"
|
4742 |
msgstr ""
|
4743 |
|
4744 |
#: inc/pro/class-jobtype-dbdump.php:851
|
4745 |
-
#, php-format
|
4746 |
msgctxt "Database Charset"
|
4747 |
msgid "Cannot set DB charset to %s"
|
4748 |
msgstr ""
|
@@ -4752,22 +4735,18 @@ msgid "No tables for XML backup"
|
|
4752 |
msgstr ""
|
4753 |
|
4754 |
#: inc/pro/class-jobtype-dbdump.php:916
|
4755 |
-
#, php-format
|
4756 |
msgid "Dump database create view \"%s\""
|
4757 |
msgstr ""
|
4758 |
|
4759 |
#: inc/pro/class-jobtype-dbdump.php:934
|
4760 |
-
#, php-format
|
4761 |
msgid "Backup database structure \"%s\" to XML"
|
4762 |
msgstr ""
|
4763 |
|
4764 |
#: inc/pro/class-jobtype-dbdump.php:976
|
4765 |
-
#, php-format
|
4766 |
msgid "Backup table \"%s\" data to XML"
|
4767 |
msgstr ""
|
4768 |
|
4769 |
#: inc/pro/class-jobtype-dbdump.php:1044
|
4770 |
-
#, php-format
|
4771 |
msgid "Added database XML dump \"%1$s\" with %2$s to backup file list"
|
4772 |
msgstr ""
|
4773 |
|
@@ -4813,21 +4792,19 @@ msgstr ""
|
|
4813 |
|
4814 |
#: inc/pro/class-page-wizard.php:179 inc/pro/class-page-wizard.php:456
|
4815 |
#: inc/pro/class-page-wizard.php:488
|
4816 |
-
msgid "Next "
|
4817 |
msgstr ""
|
4818 |
|
4819 |
#: inc/pro/class-page-wizard.php:196 inc/pro/class-page-wizard.php:452
|
4820 |
-
msgid " Previous"
|
4821 |
msgstr ""
|
4822 |
|
4823 |
#: inc/pro/class-page-wizard.php:349
|
4824 |
-
#, php-format
|
4825 |
msgctxt "Plugin Name"
|
4826 |
msgid "%s › Wizards"
|
4827 |
msgstr ""
|
4828 |
|
4829 |
#: inc/pro/class-page-wizard.php:388
|
4830 |
-
#, php-format
|
4831 |
msgctxt "Plugin Name"
|
4832 |
msgid "%s Wizard:"
|
4833 |
msgstr ""
|
@@ -4849,7 +4826,9 @@ msgid "Hash key"
|
|
4849 |
msgstr ""
|
4850 |
|
4851 |
#: inc/pro/class-settings-apikeys.php:46
|
4852 |
-
msgid "
|
|
|
|
|
4853 |
msgstr ""
|
4854 |
|
4855 |
#: inc/pro/class-settings-apikeys.php:49
|
@@ -4861,7 +4840,9 @@ msgid "Dropbox API Keys"
|
|
4861 |
msgstr ""
|
4862 |
|
4863 |
#: inc/pro/class-settings-apikeys.php:74
|
4864 |
-
msgid "
|
|
|
|
|
4865 |
msgstr ""
|
4866 |
|
4867 |
#: inc/pro/class-settings-apikeys.php:77
|
@@ -4885,7 +4866,9 @@ msgid "SugarSync API Keys"
|
|
4885 |
msgstr ""
|
4886 |
|
4887 |
#: inc/pro/class-settings-apikeys.php:132
|
4888 |
-
msgid "
|
|
|
|
|
4889 |
msgstr ""
|
4890 |
|
4891 |
#: inc/pro/class-settings-apikeys.php:135
|
@@ -4977,7 +4960,9 @@ msgid "Archive compression type"
|
|
4977 |
msgstr ""
|
4978 |
|
4979 |
#: inc/pro/class-wizard-job.php:427
|
4980 |
-
msgid "
|
|
|
|
|
4981 |
msgstr ""
|
4982 |
|
4983 |
#: inc/pro/class-wizard-job.php:430 inc/pro/class-wizard-job.php:441
|
@@ -5002,12 +4987,10 @@ msgid "Where to store the files"
|
|
5002 |
msgstr ""
|
5003 |
|
5004 |
#: inc/pro/class-wizard-job.php:661
|
5005 |
-
#, php-format
|
5006 |
msgid "Wizard: %1$s"
|
5007 |
msgstr ""
|
5008 |
|
5009 |
#: inc/pro/class-wizard-job.php:680
|
5010 |
-
#, php-format
|
5011 |
msgid "New job %s generated."
|
5012 |
msgstr ""
|
5013 |
|
@@ -5069,7 +5052,9 @@ msgid "Select which job should be imported or overwritten."
|
|
5069 |
msgstr ""
|
5070 |
|
5071 |
#: inc/pro/class-wizard-jobimport.php:67
|
5072 |
-
msgid "
|
|
|
|
|
5073 |
msgstr ""
|
5074 |
|
5075 |
#: inc/pro/class-wizard-jobimport.php:69
|
@@ -5077,7 +5062,6 @@ msgid "Choose a file from your computer:"
|
|
5077 |
msgstr ""
|
5078 |
|
5079 |
#: inc/pro/class-wizard-jobimport.php:69
|
5080 |
-
#, php-format
|
5081 |
msgid "Maximum size: %s"
|
5082 |
msgstr ""
|
5083 |
|
@@ -5110,12 +5094,16 @@ msgid "Import BackWPup configuration"
|
|
5110 |
msgstr ""
|
5111 |
|
5112 |
#: inc/pro/class-wizard-jobimport.php:142
|
5113 |
-
msgid "
|
|
|
|
|
|
|
5114 |
msgstr ""
|
5115 |
|
5116 |
#: inc/pro/class-wizard-jobimport.php:157
|
5117 |
-
|
5118 |
-
|
|
|
5119 |
msgstr ""
|
5120 |
|
5121 |
#: inc/pro/class-wizard-jobimport.php:164
|
@@ -5123,8 +5111,9 @@ msgid "Sorry, there has been a phrase error."
|
|
5123 |
msgstr ""
|
5124 |
|
5125 |
#: inc/pro/class-wizard-jobimport.php:171
|
5126 |
-
|
5127 |
-
|
|
|
5128 |
msgstr ""
|
5129 |
|
5130 |
#: inc/pro/class-wizard-jobimport.php:177
|
@@ -5132,7 +5121,6 @@ msgid "This is not a BackWPup XML file"
|
|
5132 |
msgstr ""
|
5133 |
|
5134 |
#: inc/pro/class-wizard-jobimport.php:243
|
5135 |
-
#, php-format
|
5136 |
msgid "Job %1$s with id %2$d imported"
|
5137 |
msgstr ""
|
5138 |
|
@@ -5165,53 +5153,58 @@ msgid "Test if BackWPup can work without problems."
|
|
5165 |
msgstr ""
|
5166 |
|
5167 |
#: inc/pro/class-wizard-systemtest.php:99
|
5168 |
-
|
5169 |
-
|
|
|
5170 |
msgstr ""
|
5171 |
|
5172 |
#: inc/pro/class-wizard-systemtest.php:104
|
5173 |
-
|
5174 |
-
|
|
|
5175 |
msgstr ""
|
5176 |
|
5177 |
#: inc/pro/class-wizard-systemtest.php:108
|
5178 |
-
|
5179 |
-
|
|
|
5180 |
msgstr ""
|
5181 |
|
5182 |
#: inc/pro/class-wizard-systemtest.php:113
|
5183 |
-
|
5184 |
-
|
|
|
5185 |
msgstr ""
|
5186 |
|
5187 |
#: inc/pro/class-wizard-systemtest.php:118
|
5188 |
-
msgid "
|
|
|
5189 |
msgstr ""
|
5190 |
|
5191 |
-
#: inc/pro/class-wizard-systemtest.php:
|
5192 |
-
#, php-format
|
5193 |
msgctxt "%1 = extension name, %2 = file suffix"
|
5194 |
msgid "We recommend to install the %1$s extension to generate %2$s archives."
|
5195 |
msgstr ""
|
5196 |
|
5197 |
#: inc/pro/class-wizard-systemtest.php:146
|
5198 |
-
#, php-format
|
5199 |
msgctxt "Link to PHP manual"
|
5200 |
msgid "Please disable the deprecated <a href=\"%s\">PHP safe mode</a>."
|
5201 |
msgstr ""
|
5202 |
|
5203 |
#: inc/pro/class-wizard-systemtest.php:154
|
5204 |
-
msgid "
|
|
|
|
|
5205 |
msgstr ""
|
5206 |
|
5207 |
#: inc/pro/class-wizard-systemtest.php:174
|
5208 |
-
#, php-format
|
5209 |
msgid "The HTTP response test result is an error: \"%s\"."
|
5210 |
msgstr ""
|
5211 |
|
5212 |
#: inc/pro/class-wizard-systemtest.php:178
|
5213 |
-
|
5214 |
-
|
|
|
5215 |
msgstr ""
|
5216 |
|
5217 |
#: inc/pro/class-wizard-systemtest.php:191
|
@@ -5223,9 +5216,51 @@ msgid "All tests passed without errors."
|
|
5223 |
msgstr ""
|
5224 |
|
5225 |
#: inc/pro/class-wizard-systemtest.php:199
|
5226 |
-
msgid "
|
|
|
|
|
5227 |
msgstr ""
|
5228 |
|
5229 |
#: inc/pro/class-wizard-systemtest.php:202
|
5230 |
msgid "There are errors. Please correct them, or BackWPup cannot work."
|
5231 |
-
msgstr ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2017 BackWPup Pro
|
2 |
+
# This file is distributed under the same license as the BackWPup Pro package.
|
|
|
|
|
|
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
+
"Project-Id-Version: BackWPup Pro 3.3.7\n"
|
6 |
+
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/backwpup-pro\n"
|
7 |
+
"POT-Creation-Date: 2017-05-22 17:29:48+00:00\n"
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2017-MO-DA HO:MI+ZONE\n"
|
12 |
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
|
15 |
#: backwpup.php:333 inc/class-page-backups.php:271
|
16 |
msgid "Folder"
|
36 |
msgid "Backup to FTP"
|
37 |
msgstr ""
|
38 |
|
39 |
+
#: backwpup.php:381 inc/class-destination-dropbox.php:293
|
40 |
msgid "Dropbox"
|
41 |
msgstr ""
|
42 |
|
77 |
msgstr ""
|
78 |
|
79 |
#: backwpup.php:470
|
|
|
80 |
msgid "PHP Version %1$s is to low, you need Version %2$s or above."
|
81 |
msgstr ""
|
82 |
|
83 |
#: backwpup.php:477
|
|
|
84 |
msgid "Missing function \"%s\"."
|
85 |
msgstr ""
|
86 |
|
87 |
#: backwpup.php:486
|
|
|
88 |
msgid "Missing class \"%s\"."
|
89 |
msgstr ""
|
90 |
|
105 |
msgstr ""
|
106 |
|
107 |
#: inc/class-admin.php:243 inc/class-adminbar.php:82
|
108 |
+
#: inc/class-page-settings.php:117
|
109 |
msgid "Jobs"
|
110 |
msgstr ""
|
111 |
|
114 |
msgstr ""
|
115 |
|
116 |
#: inc/class-admin.php:273 inc/class-adminbar.php:98
|
117 |
+
#: inc/class-page-logs.php:328 inc/class-page-settings.php:117
|
118 |
msgid "Logs"
|
119 |
msgstr ""
|
120 |
|
135 |
msgstr ""
|
136 |
|
137 |
#: inc/class-admin.php:381
|
|
|
138 |
msgid "<a class=\"backwpup-get-pro\" href=\"%s\">Get BackWPup Pro now.</a>"
|
139 |
msgstr ""
|
140 |
|
141 |
+
#. #-#-#-#-# backwpup.pot (BackWPup Pro 3.3.7) #-#-#-#-#
|
142 |
+
#. Plugin URI of the plugin/theme
|
143 |
#: inc/class-admin.php:381 inc/class-admin.php:401 inc/class-help.php:17
|
144 |
#: inc/class-help.php:22 inc/class-job.php:394
|
145 |
#: inc/class-jobtype-dbcheck.php:15 inc/class-jobtype-dbdump.php:15
|
146 |
#: inc/class-jobtype-file.php:15 inc/class-jobtype-wpexp.php:15
|
147 |
#: inc/class-jobtype-wpplugin.php:15 inc/class-page-about.php:624
|
148 |
#: inc/class-page-backwpup.php:260 inc/class-page-backwpup.php:262
|
149 |
+
#: inc/class-page-settings.php:391 inc/pro/class-wizard-job.php:17
|
150 |
#: inc/pro/class-wizard-jobimport.php:16
|
151 |
#: inc/pro/class-wizard-systemtest.php:16
|
152 |
msgid "http://backwpup.com"
|
153 |
msgstr ""
|
154 |
|
155 |
#: inc/class-admin.php:401
|
|
|
156 |
msgid "version %s"
|
157 |
msgstr ""
|
158 |
|
189 |
msgid "Make BackWPup better!"
|
190 |
msgstr ""
|
191 |
|
192 |
+
#: inc/class-become-inpsyder-widget.php:104
|
193 |
+
msgid ""
|
194 |
+
"https://inpsyde.com/en/jobs/?"
|
195 |
+
"utm_source=BackWPup&utm_medium=Link&utm_campaign=BecomeAnInpsyder"
|
196 |
msgstr ""
|
197 |
|
198 |
+
#: inc/class-become-inpsyder-widget.php:114
|
199 |
msgid "We want to make BackWPup even stronger and its support much faster."
|
200 |
msgstr ""
|
201 |
|
202 |
+
#: inc/class-become-inpsyder-widget.php:122
|
203 |
+
msgid ""
|
204 |
+
"This is why we are looking for a talented developer who can work remotely "
|
205 |
+
"and support us in BackWPup"
|
206 |
msgstr ""
|
207 |
|
208 |
+
#: inc/class-become-inpsyder-widget.php:129
|
209 |
msgid "and other exciting WordPress projects at our VIP partner agency."
|
210 |
msgstr ""
|
211 |
|
230 |
msgid "https://backwpup.com/become-backwpup-beta-tester/"
|
231 |
msgstr ""
|
232 |
|
233 |
+
#: inc/class-betatester-admin-notice.php:77
|
234 |
+
msgid ""
|
235 |
+
"To ensure that our releases are as bug-free as possible, we need you as a "
|
236 |
+
"beta tester!"
|
237 |
msgstr ""
|
238 |
|
239 |
#: inc/class-create-archive.php:64
|
241 |
msgstr ""
|
242 |
|
243 |
#: inc/class-create-archive.php:72
|
|
|
244 |
msgctxt "%s = Folder name"
|
245 |
msgid "Folder %s for archive not found"
|
246 |
msgstr ""
|
255 |
msgstr ""
|
256 |
|
257 |
#: inc/class-create-archive.php:106
|
|
|
258 |
msgctxt "ZipArchive open() result"
|
259 |
msgid "Cannot create zip archive: %d"
|
260 |
msgstr ""
|
261 |
|
262 |
#: inc/class-create-archive.php:135
|
|
|
263 |
msgctxt "%s = file name"
|
264 |
msgid "Method to archive file %s not detected"
|
265 |
msgstr ""
|
269 |
msgstr ""
|
270 |
|
271 |
#: inc/class-create-archive.php:155 inc/class-create-archive.php:349
|
|
|
272 |
msgid "PclZip archive add error: %s"
|
273 |
msgstr ""
|
274 |
|
281 |
msgstr ""
|
282 |
|
283 |
#: inc/class-create-archive.php:228
|
|
|
284 |
msgctxt "File to add to archive"
|
285 |
msgid "File %s does not exist or is not readable"
|
286 |
msgstr ""
|
291 |
msgstr ""
|
292 |
|
293 |
#: inc/class-create-archive.php:247 inc/class-create-archive.php:263
|
|
|
294 |
msgid "Cannot open source file %s to archive"
|
295 |
msgstr ""
|
296 |
|
300 |
|
301 |
#: inc/class-create-archive.php:329 inc/class-create-archive.php:338
|
302 |
#: inc/class-create-archive.php:407
|
|
|
303 |
msgid "Cannot add \"%s\" to zip archive!"
|
304 |
msgstr ""
|
305 |
|
308 |
msgstr ""
|
309 |
|
310 |
#: inc/class-create-archive.php:379
|
|
|
311 |
msgctxt "Folder path to add to archive"
|
312 |
msgid "Folder %s does not exist or is not readable"
|
313 |
msgstr ""
|
314 |
|
315 |
#: inc/class-create-archive.php:429
|
|
|
316 |
msgctxt "Text of ZipArchive status Message"
|
317 |
msgid "ZipArchive returns status: %s"
|
318 |
msgstr ""
|
319 |
|
320 |
#: inc/class-create-archive.php:459
|
|
|
321 |
msgid "File name \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
322 |
msgstr ""
|
323 |
|
324 |
#: inc/class-create-archive.php:462
|
|
|
325 |
msgid "File path \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
326 |
msgstr ""
|
327 |
|
328 |
#: inc/class-create-archive.php:474
|
|
|
329 |
msgid "Cannot open source file %s for archiving"
|
330 |
msgstr ""
|
331 |
|
335 |
msgstr ""
|
336 |
|
337 |
#: inc/class-create-archive.php:570
|
|
|
338 |
msgid "Folder name \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
339 |
msgstr ""
|
340 |
|
341 |
#: inc/class-create-archive.php:573
|
|
|
342 |
msgid "Folder path \"%1$s\" is too long to be saved correctly in %2$s archive!"
|
343 |
msgstr ""
|
344 |
|
345 |
#: inc/class-create-archive.php:654
|
346 |
+
msgid ""
|
347 |
+
"If %s will be added to your backup archive, the archive will be too large "
|
348 |
+
"for operations with this PHP Version. You might want to consider splitting "
|
349 |
+
"the backup job in multiple jobs with less files each."
|
350 |
msgstr ""
|
351 |
|
352 |
#: inc/class-cron.php:69
|
353 |
msgid "Aborted, because no progress for one hour!"
|
354 |
msgstr ""
|
355 |
|
356 |
+
#: inc/class-cron.php:101 inc/class-destination-folder.php:209
|
357 |
+
#: inc/class-job.php:1003 inc/class-job.php:1141 inc/class-job.php:1739
|
358 |
+
#: inc/class-jobtype-file.php:444
|
359 |
+
msgid "Could not open path: %s"
|
360 |
+
msgstr ""
|
361 |
+
|
362 |
+
#: inc/class-destination-dropbox.php:41 inc/class-destination-dropbox.php:344
|
363 |
+
#: inc/pro/class-destination-dropbox.php:253
|
364 |
msgid "Dropbox API: %s"
|
365 |
msgstr ""
|
366 |
|
367 |
+
#: inc/class-destination-dropbox.php:55
|
368 |
#: inc/pro/class-destination-gdrive.php:51
|
369 |
msgid "Login"
|
370 |
msgstr ""
|
371 |
|
372 |
+
#: inc/class-destination-dropbox.php:59 inc/class-destination-sugarsync.php:28
|
373 |
#: inc/class-destination-sugarsync.php:43
|
374 |
msgid "Authentication"
|
375 |
msgstr ""
|
376 |
|
377 |
+
#: inc/class-destination-dropbox.php:61
|
378 |
#: inc/pro/class-destination-gdrive.php:57
|
379 |
+
#: inc/pro/class-destination-gdrive.php:295
|
380 |
msgid "Not authenticated!"
|
381 |
msgstr ""
|
382 |
|
383 |
+
#: inc/class-destination-dropbox.php:63
|
384 |
+
#: inc/pro/class-destination-dropbox.php:28
|
385 |
msgid "Create Account"
|
386 |
msgstr ""
|
387 |
|
388 |
+
#: inc/class-destination-dropbox.php:65 inc/class-destination-sugarsync.php:45
|
389 |
+
#: inc/pro/class-destination-dropbox.php:34
|
390 |
#: inc/pro/class-destination-gdrive.php:59
|
391 |
+
#: inc/pro/class-destination-gdrive.php:300
|
392 |
#: inc/pro/class-destination-sugarsync.php:31
|
393 |
msgid "Authenticated!"
|
394 |
msgstr ""
|
395 |
|
396 |
+
#: inc/class-destination-dropbox.php:68
|
397 |
msgid "Delete Dropbox Authentication"
|
398 |
msgstr ""
|
399 |
|
400 |
+
#: inc/class-destination-dropbox.php:75
|
401 |
msgid "App Access to Dropbox"
|
402 |
msgstr ""
|
403 |
|
404 |
+
#: inc/class-destination-dropbox.php:78
|
405 |
msgid "Get Dropbox App auth code"
|
406 |
msgstr ""
|
407 |
|
408 |
+
#: inc/class-destination-dropbox.php:79
|
409 |
+
msgid ""
|
410 |
+
"A dedicated folder named BackWPup will be created inside of the Apps folder "
|
411 |
+
"in your Dropbox. BackWPup will get read and write access to that folder "
|
412 |
+
"only. You can specify a subfolder as your backup destination for this job in "
|
413 |
+
"the destination field below."
|
414 |
msgstr ""
|
415 |
|
416 |
+
#: inc/class-destination-dropbox.php:84
|
417 |
+
msgid "— OR —"
|
418 |
msgstr ""
|
419 |
|
420 |
+
#: inc/class-destination-dropbox.php:87
|
421 |
msgid "Full Access to Dropbox"
|
422 |
msgstr ""
|
423 |
|
424 |
+
#: inc/class-destination-dropbox.php:90
|
425 |
msgid "Get full Dropbox auth code "
|
426 |
msgstr ""
|
427 |
|
428 |
+
#: inc/class-destination-dropbox.php:91
|
429 |
+
msgid ""
|
430 |
+
"BackWPup will have full read and write access to your entire Dropbox. You "
|
431 |
+
"can specify your backup destination wherever you want, just be aware that "
|
432 |
+
"ANY files or folders inside of your Dropbox can be overridden or deleted by "
|
433 |
+
"BackWPup."
|
434 |
msgstr ""
|
435 |
|
436 |
+
#: inc/class-destination-dropbox.php:98 inc/class-destination-folder.php:29
|
437 |
#: inc/class-destination-ftp.php:49 inc/class-destination-msazure.php:66
|
438 |
#: inc/class-destination-rsc.php:95 inc/class-destination-sugarsync.php:81
|
439 |
#: inc/pro/class-destination-gdrive.php:68
|
440 |
msgid "Backup settings"
|
441 |
msgstr ""
|
442 |
|
443 |
+
#: inc/class-destination-dropbox.php:102
|
444 |
msgid "Destination Folder"
|
445 |
msgstr ""
|
446 |
|
447 |
+
#: inc/class-destination-dropbox.php:106
|
448 |
+
msgid ""
|
449 |
+
"Specify a subfolder where your backup archives will be stored. If you use "
|
450 |
+
"the App option from above, this folder will be created inside of Apps/"
|
451 |
+
"BackWPup. Otherwise it will be created at the root of your Dropbox. Already "
|
452 |
+
"exisiting folders with the same name will not be overriden."
|
453 |
msgstr ""
|
454 |
|
455 |
+
#: inc/class-destination-dropbox.php:111 inc/class-destination-folder.php:39
|
456 |
#: inc/class-destination-ftp.php:59 inc/class-destination-sugarsync.php:91
|
457 |
#: inc/pro/class-destination-gdrive.php:81
|
458 |
msgid "File Deletion"
|
459 |
msgstr ""
|
460 |
|
461 |
+
#: inc/class-destination-dropbox.php:118 inc/class-destination-folder.php:46
|
462 |
#: inc/class-destination-ftp.php:66 inc/class-destination-msazure.php:83
|
463 |
+
#: inc/class-destination-rsc.php:112 inc/class-destination-s3.php:121
|
464 |
#: inc/class-destination-sugarsync.php:98
|
465 |
+
#: inc/pro/class-destination-dropbox.php:51
|
466 |
#: inc/pro/class-destination-folder.php:43
|
467 |
#: inc/pro/class-destination-gdrive.php:90
|
468 |
+
#: inc/pro/class-destination-gdrive.php:323
|
469 |
#: inc/pro/class-destination-msazure.php:45
|
470 |
+
#: inc/pro/class-destination-rsc.php:65 inc/pro/class-destination-s3.php:73
|
471 |
msgid "Number of files to keep in folder."
|
472 |
msgstr ""
|
473 |
|
474 |
+
#: inc/class-destination-dropbox.php:120 inc/class-destination-folder.php:48
|
475 |
+
#: inc/class-destination-ftp.php:68 inc/class-destination-msazure.php:85
|
476 |
+
#: inc/class-destination-rsc.php:114 inc/class-destination-s3.php:123
|
477 |
+
#: inc/class-destination-sugarsync.php:100
|
478 |
+
#: inc/pro/class-destination-gdrive.php:92
|
479 |
+
#: inc/pro/class-destination-glacier.php:109
|
480 |
+
msgid ""
|
481 |
+
"<strong>Warning</strong>: Files belonging to this job are now tracked. Old "
|
482 |
+
"backup archives which are untracked will not be automatically deleted."
|
483 |
+
msgstr ""
|
484 |
+
|
485 |
+
#: inc/class-destination-dropbox.php:124 inc/class-destination-folder.php:52
|
486 |
+
#: inc/class-destination-ftp.php:72 inc/class-destination-msazure.php:89
|
487 |
+
#: inc/class-destination-rsc.php:118 inc/class-destination-s3.php:127
|
488 |
+
#: inc/class-destination-sugarsync.php:104
|
489 |
+
#: inc/pro/class-destination-dropbox.php:54
|
490 |
#: inc/pro/class-destination-folder.php:48
|
491 |
#: inc/pro/class-destination-ftp.php:44
|
492 |
+
#: inc/pro/class-destination-gdrive.php:98
|
493 |
+
#: inc/pro/class-destination-gdrive.php:328
|
494 |
#: inc/pro/class-destination-msazure.php:56
|
495 |
+
#: inc/pro/class-destination-rsc.php:70 inc/pro/class-destination-s3.php:78
|
496 |
#: inc/pro/class-destination-sugarsync.php:65
|
497 |
msgid "Do not delete files while syncing to destination!"
|
498 |
msgstr ""
|
499 |
|
500 |
+
#: inc/class-destination-dropbox.php:239
|
|
|
501 |
msgid "%d. Try to send backup file to Dropbox …"
|
502 |
msgstr ""
|
503 |
|
504 |
+
#: inc/class-destination-dropbox.php:256
|
505 |
+
#: inc/pro/class-destination-dropbox.php:127
|
|
|
506 |
msgid "Authenticated with Dropbox of user: %s"
|
507 |
msgstr ""
|
508 |
|
509 |
+
#: inc/class-destination-dropbox.php:262
|
510 |
+
#: inc/pro/class-destination-dropbox.php:133
|
|
|
511 |
msgid "%s available on your Dropbox"
|
512 |
msgstr ""
|
513 |
|
514 |
+
#: inc/class-destination-dropbox.php:266
|
515 |
+
#: inc/pro/class-destination-dropbox.php:137
|
516 |
msgid "Not Authenticated with Dropbox!"
|
517 |
msgstr ""
|
518 |
|
519 |
+
#: inc/class-destination-dropbox.php:270
|
520 |
msgid "Uploading to Dropbox …"
|
521 |
msgstr ""
|
522 |
|
523 |
+
#: inc/class-destination-dropbox.php:283 inc/class-destination-msazure.php:286
|
524 |
+
#: inc/class-destination-sugarsync.php:260
|
525 |
+
#: inc/pro/class-destination-gdrive.php:663
|
|
|
526 |
msgid "Backup transferred to %s"
|
527 |
msgstr ""
|
528 |
|
529 |
+
#: inc/class-destination-dropbox.php:287
|
530 |
+
#: inc/pro/class-destination-gdrive.php:666
|
531 |
msgid "Uploaded file size and local file size don't match."
|
532 |
msgstr ""
|
533 |
|
534 |
+
#: inc/class-destination-dropbox.php:292
|
535 |
+
#: inc/pro/class-destination-gdrive.php:668
|
536 |
+
#: inc/pro/class-destination-glacier.php:448
|
|
|
537 |
msgid "Error transfering backup to %s."
|
538 |
msgstr ""
|
539 |
|
540 |
+
#: inc/class-destination-dropbox.php:337
|
|
|
|
|
|
|
|
|
|
|
|
|
541 |
msgid "One file deleted from Dropbox"
|
542 |
msgid_plural "%d files deleted on Dropbox"
|
543 |
msgstr[0] ""
|
544 |
msgstr[1] ""
|
545 |
|
546 |
+
#: inc/class-destination-dropbox.php:520
|
547 |
+
msgid "Beginning new file upload session"
|
548 |
+
msgstr ""
|
549 |
+
|
550 |
+
#: inc/class-destination-dropbox.php:539
|
551 |
+
msgid "Uploading %s of data"
|
552 |
+
msgstr ""
|
553 |
+
|
554 |
+
#: inc/class-destination-dropbox.php:575
|
555 |
+
msgid "Finishing upload session with a total of %s uploaded"
|
556 |
+
msgstr ""
|
557 |
+
|
558 |
#: inc/class-destination-email.php:38 inc/pro/class-destination-email.php:16
|
559 |
#: inc/pro/class-destination-email.php:18
|
560 |
msgid "Email address"
|
561 |
msgstr ""
|
562 |
|
563 |
#: inc/class-destination-email.php:41
|
564 |
+
msgid "To email address (separate with commas for multiple addresses)"
|
565 |
msgstr ""
|
566 |
|
567 |
#: inc/class-destination-email.php:47 inc/class-destination-email.php:49
|
634 |
#: inc/class-destination-email.php:106 inc/class-jobtype-dbdump.php:67
|
635 |
#: inc/class-jobtype-dbdump.php:103 inc/class-jobtype-wpexp.php:73
|
636 |
#: inc/class-jobtype-wpplugin.php:57 inc/class-page-backwpup.php:329
|
637 |
+
#: inc/class-page-backwpup.php:404 inc/class-page-settings.php:328
|
638 |
#: inc/pro/class-jobtype-dbdump.php:157 inc/pro/class-jobtype-dbdump.php:205
|
639 |
msgid "none"
|
640 |
msgstr ""
|
656 |
msgstr ""
|
657 |
|
658 |
#: inc/class-destination-email.php:199
|
|
|
659 |
msgid "%d. Try to send backup with email …"
|
660 |
msgstr ""
|
661 |
|
664 |
msgstr ""
|
665 |
|
666 |
#: inc/class-destination-email.php:211
|
|
|
667 |
msgid "Sending email to %s…"
|
668 |
msgstr ""
|
669 |
|
670 |
#: inc/class-destination-email.php:289
|
|
|
671 |
msgid "BackWPup archive from %1$s: %2$s"
|
672 |
msgstr ""
|
673 |
|
674 |
#: inc/class-destination-email.php:292
|
|
|
675 |
msgid "Backup archive: %s"
|
676 |
msgstr ""
|
677 |
|
688 |
msgstr ""
|
689 |
|
690 |
#: inc/class-destination-email.php:417
|
691 |
+
msgid ""
|
692 |
+
"If this message reaches your inbox, sending backup archives via email should "
|
693 |
+
"work for you."
|
694 |
msgstr ""
|
695 |
|
696 |
#: inc/class-destination-folder.php:33
|
697 |
msgid "Folder to store backups in"
|
698 |
msgstr ""
|
699 |
|
700 |
+
#: inc/class-destination-folder.php:229
|
|
|
701 |
msgid "One backup file deleted"
|
702 |
msgid_plural "%d backup files deleted"
|
703 |
msgstr[0] ""
|
723 |
msgid "Folder to store files in"
|
724 |
msgstr ""
|
725 |
|
726 |
+
#: inc/class-destination-ftp.php:79
|
727 |
msgid "FTP specific settings"
|
728 |
msgstr ""
|
729 |
|
730 |
+
#: inc/class-destination-ftp.php:83
|
731 |
msgid "Timeout for FTP connection"
|
732 |
msgstr ""
|
733 |
|
734 |
+
#: inc/class-destination-ftp.php:87 inc/class-page-logs.php:257
|
735 |
+
#: inc/class-page-settings.php:466
|
736 |
msgid "seconds"
|
737 |
msgstr ""
|
738 |
|
739 |
+
#: inc/class-destination-ftp.php:91
|
740 |
msgid "SSL-FTP connection"
|
741 |
msgstr ""
|
742 |
|
743 |
+
#: inc/class-destination-ftp.php:94
|
744 |
msgid "Use explicit SSL-FTP connection."
|
745 |
msgstr ""
|
746 |
|
747 |
+
#: inc/class-destination-ftp.php:99
|
748 |
msgid "FTP Passive Mode"
|
749 |
msgstr ""
|
750 |
|
751 |
+
#: inc/class-destination-ftp.php:101
|
752 |
msgid "Use FTP Passive Mode."
|
753 |
msgstr ""
|
754 |
|
755 |
+
#: inc/class-destination-ftp.php:179
|
756 |
msgid "FTP: Login failure!"
|
757 |
msgstr ""
|
758 |
|
759 |
+
#: inc/class-destination-ftp.php:203
|
|
|
760 |
msgid "%d. Try to send backup file to an FTP server …"
|
761 |
msgstr ""
|
762 |
|
763 |
+
#: inc/class-destination-ftp.php:209
|
|
|
764 |
msgid "Connected via explicit SSL-FTP to server: %s"
|
765 |
msgstr ""
|
766 |
|
767 |
+
#: inc/class-destination-ftp.php:211
|
|
|
768 |
msgid "Cannot connect via explicit SSL-FTP to server: %s"
|
769 |
msgstr ""
|
770 |
|
771 |
+
#: inc/class-destination-ftp.php:217
|
772 |
msgid "PHP function to connect with explicit SSL-FTP to server does not exist!"
|
773 |
msgstr ""
|
774 |
|
775 |
+
#: inc/class-destination-ftp.php:225
|
|
|
776 |
msgid "Connected to FTP server: %s"
|
777 |
msgstr ""
|
778 |
|
779 |
+
#: inc/class-destination-ftp.php:227
|
|
|
780 |
msgid "Cannot connect to FTP server: %s"
|
781 |
msgstr ""
|
782 |
|
783 |
+
#: inc/class-destination-ftp.php:234 inc/class-destination-ftp.php:242
|
784 |
+
#: inc/class-destination-ftp.php:258 inc/class-destination-ftp.php:305
|
|
|
785 |
msgid "FTP client command: %s"
|
786 |
msgstr ""
|
787 |
|
788 |
+
#: inc/class-destination-ftp.php:236
|
|
|
789 |
msgid "FTP server response: %s"
|
790 |
msgstr ""
|
791 |
|
792 |
+
#: inc/class-destination-ftp.php:240 inc/class-destination-ftp.php:245
|
793 |
+
#: inc/class-destination-ftp.php:248 inc/class-destination-ftp.php:261
|
794 |
+
#: inc/class-destination-ftp.php:263 inc/class-destination-ftp.php:308
|
795 |
+
#: inc/class-destination-ftp.php:310 inc/class-destination-ftp.php:314
|
796 |
+
#: inc/class-destination-ftp.php:316
|
|
|
797 |
msgid "FTP server reply: %s"
|
798 |
msgstr ""
|
799 |
|
800 |
+
#: inc/class-destination-ftp.php:263
|
801 |
msgid "Error getting SYSTYPE"
|
802 |
msgstr ""
|
803 |
|
804 |
+
#: inc/class-destination-ftp.php:281
|
|
|
805 |
msgid "FTP Folder \"%s\" created!"
|
806 |
msgstr ""
|
807 |
|
808 |
+
#: inc/class-destination-ftp.php:285
|
|
|
809 |
msgid "FTP Folder \"%s\" cannot be created!"
|
810 |
msgstr ""
|
811 |
|
812 |
+
#: inc/class-destination-ftp.php:296
|
|
|
813 |
msgid "FTP current folder is: %s"
|
814 |
msgstr ""
|
815 |
|
816 |
+
#: inc/class-destination-ftp.php:308
|
817 |
msgid "Entering passive mode"
|
818 |
msgstr ""
|
819 |
|
820 |
+
#: inc/class-destination-ftp.php:310
|
821 |
msgid "Cannot enter passive mode"
|
822 |
msgstr ""
|
823 |
|
824 |
+
#: inc/class-destination-ftp.php:314
|
825 |
msgid "Entering normal mode"
|
826 |
msgstr ""
|
827 |
|
828 |
+
#: inc/class-destination-ftp.php:316
|
829 |
msgid "Cannot enter normal mode"
|
830 |
msgstr ""
|
831 |
|
832 |
+
#: inc/class-destination-ftp.php:320
|
833 |
msgid "Starting upload to FTP  …"
|
834 |
msgstr ""
|
835 |
|
836 |
+
#: inc/class-destination-ftp.php:332
|
837 |
msgid "Cannot transfer backup to FTP server!"
|
838 |
msgstr ""
|
839 |
|
840 |
+
#: inc/class-destination-ftp.php:337
|
|
|
841 |
msgid "Backup transferred to FTP server: %s"
|
842 |
msgstr ""
|
843 |
|
844 |
+
#: inc/class-destination-ftp.php:344 inc/class-destination-msazure.php:271
|
845 |
+
#: inc/class-destination-rsc.php:289 inc/class-destination-s3.php:499
|
846 |
+
#: inc/class-destination-s3.php:591 inc/pro/class-destination-gdrive.php:653
|
847 |
+
#: inc/pro/class-destination-glacier.php:468
|
848 |
#: inc/pro/class-destination-rsc.php:226 inc/pro/class-destination-rsc.php:259
|
849 |
msgid "Can not open source file for transfer."
|
850 |
msgstr ""
|
851 |
|
852 |
+
#: inc/class-destination-ftp.php:388
|
|
|
853 |
msgid "Cannot delete \"%s\" on FTP server!"
|
854 |
msgstr ""
|
855 |
|
856 |
+
#: inc/class-destination-ftp.php:391
|
|
|
857 |
msgid "One file deleted on FTP server"
|
858 |
msgid_plural "%d files deleted on FTP server"
|
859 |
msgstr[0] ""
|
888 |
msgstr ""
|
889 |
|
890 |
#: inc/class-destination-msazure.php:76 inc/class-destination-rsc.php:105
|
891 |
+
#: inc/class-destination-s3.php:114 inc/pro/class-destination-glacier.php:96
|
892 |
msgid "File deletion"
|
893 |
msgstr ""
|
894 |
|
895 |
+
#: inc/class-destination-msazure.php:128
|
896 |
#: inc/pro/class-destination-msazure.php:99
|
|
|
897 |
msgid "MS Azure container \"%s\" created."
|
898 |
msgstr ""
|
899 |
|
900 |
+
#: inc/class-destination-msazure.php:131
|
901 |
#: inc/pro/class-destination-msazure.php:102
|
|
|
902 |
msgid "MS Azure container create: %s"
|
903 |
msgstr ""
|
904 |
|
905 |
+
#: inc/class-destination-msazure.php:211
|
|
|
906 |
msgid "%d. Try sending backup to a Microsoft Azure (Blob) …"
|
907 |
msgstr ""
|
908 |
|
909 |
+
#: inc/class-destination-msazure.php:233
|
910 |
#: inc/pro/class-destination-msazure.php:144
|
|
|
911 |
msgid "MS Azure container \"%s\" does not exist!"
|
912 |
msgstr ""
|
913 |
|
914 |
+
#: inc/class-destination-msazure.php:237
|
915 |
#: inc/pro/class-destination-msazure.php:148
|
|
|
916 |
msgid "Connected to MS Azure container \"%s\"."
|
917 |
msgstr ""
|
918 |
|
919 |
+
#: inc/class-destination-msazure.php:240
|
920 |
msgid "Starting upload to MS Azure …"
|
921 |
msgstr ""
|
922 |
|
923 |
+
#: inc/class-destination-msazure.php:292 inc/class-destination-msazure.php:348
|
924 |
#: inc/pro/class-destination-msazure.php:233
|
|
|
925 |
msgid "Microsoft Azure API: %s"
|
926 |
msgstr ""
|
927 |
|
928 |
+
#: inc/class-destination-msazure.php:341
|
|
|
929 |
msgid "One file deleted on Microsoft Azure container."
|
930 |
msgid_plural "%d files deleted on Microsoft Azure container."
|
931 |
msgstr[0] ""
|
932 |
msgstr[1] ""
|
933 |
|
934 |
+
#: inc/class-destination-msazure.php:442
|
935 |
msgid "Missing account name!"
|
936 |
msgstr ""
|
937 |
|
938 |
+
#: inc/class-destination-msazure.php:444 inc/class-destination-s3.php:222
|
939 |
+
#: inc/pro/class-destination-glacier.php:166
|
940 |
msgid "Missing access key!"
|
941 |
msgstr ""
|
942 |
|
943 |
+
#: inc/class-destination-msazure.php:448
|
944 |
msgid "No container found!"
|
945 |
msgstr ""
|
946 |
|
985 |
msgid "Hong Kong (HKG)"
|
986 |
msgstr ""
|
987 |
|
988 |
+
#: inc/class-destination-rsc.php:99 inc/class-destination-s3.php:108
|
989 |
msgid "Folder in bucket"
|
990 |
msgstr ""
|
991 |
|
992 |
+
#: inc/class-destination-rsc.php:158 inc/pro/class-destination-rsc.php:116
|
|
|
993 |
msgid "Rackspace Cloud container \"%s\" created."
|
994 |
msgstr ""
|
995 |
|
996 |
+
#: inc/class-destination-rsc.php:162 inc/class-destination-rsc.php:274
|
997 |
+
#: inc/class-destination-rsc.php:314 inc/class-destination-rsc.php:359
|
998 |
#: inc/pro/class-destination-rsc.php:120 inc/pro/class-destination-rsc.php:170
|
999 |
#: inc/pro/class-destination-rsc.php:290
|
|
|
1000 |
msgid "Rackspace Cloud API: %s"
|
1001 |
msgstr ""
|
1002 |
|
1003 |
+
#: inc/class-destination-rsc.php:257
|
|
|
1004 |
msgid "%d. Trying to send backup file to Rackspace cloud …"
|
1005 |
msgstr ""
|
1006 |
|
1007 |
+
#: inc/class-destination-rsc.php:271
|
|
|
1008 |
msgid "Connected to Rackspace cloud files container %s"
|
1009 |
msgstr ""
|
1010 |
|
1011 |
+
#: inc/class-destination-rsc.php:283
|
1012 |
msgid "Upload to Rackspace cloud started …"
|
1013 |
msgstr ""
|
1014 |
|
1015 |
+
#: inc/class-destination-rsc.php:302
|
1016 |
msgid "Backup File transferred to RSC://"
|
1017 |
msgstr ""
|
1018 |
|
1019 |
+
#: inc/class-destination-rsc.php:308
|
1020 |
msgid "Cannot transfer backup to Rackspace cloud."
|
1021 |
msgstr ""
|
1022 |
|
1023 |
+
#: inc/class-destination-rsc.php:353
|
|
|
1024 |
msgid "One file deleted on Rackspace cloud container."
|
1025 |
msgid_plural "%d files deleted on Rackspace cloud container."
|
1026 |
msgstr[0] ""
|
1027 |
msgstr[1] ""
|
1028 |
|
1029 |
+
#: inc/class-destination-rsc.php:466
|
1030 |
msgid "Missing username!"
|
1031 |
msgstr ""
|
1032 |
|
1033 |
+
#: inc/class-destination-rsc.php:468
|
1034 |
msgid "Missing API Key!"
|
1035 |
msgstr ""
|
1036 |
|
1037 |
+
#: inc/class-destination-rsc.php:472
|
1038 |
msgid "A container could not be found!"
|
1039 |
msgstr ""
|
1040 |
|
1110 |
msgid "Dream Host Cloud Storage"
|
1111 |
msgstr ""
|
1112 |
|
1113 |
+
#: inc/class-destination-s3.php:54
|
|
|
|
|
|
|
|
|
1114 |
msgid "Or a S3 Server URL"
|
1115 |
msgstr ""
|
1116 |
|
1117 |
+
#: inc/class-destination-s3.php:61
|
1118 |
msgid "S3 Access Keys"
|
1119 |
msgstr ""
|
1120 |
|
1121 |
+
#: inc/class-destination-s3.php:65 inc/pro/class-destination-glacier.php:54
|
1122 |
msgid "Access Key"
|
1123 |
msgstr ""
|
1124 |
|
1125 |
+
#: inc/class-destination-s3.php:72 inc/pro/class-destination-glacier.php:61
|
1126 |
msgid "Secret Key"
|
1127 |
msgstr ""
|
1128 |
|
1129 |
+
#: inc/class-destination-s3.php:80
|
1130 |
msgid "S3 Bucket"
|
1131 |
msgstr ""
|
1132 |
|
1133 |
+
#: inc/class-destination-s3.php:84
|
1134 |
msgid "Bucket selection"
|
1135 |
msgstr ""
|
1136 |
|
1137 |
+
#: inc/class-destination-s3.php:97
|
1138 |
msgid "Create a new bucket"
|
1139 |
msgstr ""
|
1140 |
|
1141 |
+
#: inc/class-destination-s3.php:104
|
1142 |
msgid "S3 Backup settings"
|
1143 |
msgstr ""
|
1144 |
|
1151 |
msgstr ""
|
1152 |
|
1153 |
#: inc/class-destination-s3.php:137
|
1154 |
+
msgid ""
|
1155 |
+
"Multipart splits file into multiple chunks while uploading. This is "
|
1156 |
+
"necessary for displaying the upload process and to transfer bigger files. "
|
1157 |
+
"Works without a problem on Amazon. Other services might have issues."
|
1158 |
msgstr ""
|
1159 |
|
1160 |
#: inc/class-destination-s3.php:143
|
1185 |
msgid "Save files encrypted (AES256) on server."
|
1186 |
msgstr ""
|
1187 |
|
1188 |
+
#: inc/class-destination-s3.php:224 inc/pro/class-destination-glacier.php:168
|
1189 |
msgid "Missing secret access key!"
|
1190 |
msgstr ""
|
1191 |
|
1192 |
+
#: inc/class-destination-s3.php:230
|
1193 |
msgid "No bucket found!"
|
1194 |
msgstr ""
|
1195 |
|
1196 |
+
#: inc/class-destination-s3.php:346
|
|
|
1197 |
msgid "Bucket %1$s created."
|
1198 |
msgstr ""
|
1199 |
|
1200 |
+
#: inc/class-destination-s3.php:348 inc/pro/class-destination-s3.php:147
|
|
|
1201 |
msgid " %s is not a valid bucket name."
|
1202 |
msgstr ""
|
1203 |
|
1204 |
+
#: inc/class-destination-s3.php:389 inc/class-destination-s3.php:522
|
1205 |
+
#: inc/class-destination-s3.php:576 inc/class-destination-s3.php:610
|
1206 |
+
#: inc/class-destination-s3.php:670 inc/pro/class-destination-s3.php:337
|
|
|
1207 |
msgid "S3 Service API: %s"
|
1208 |
msgstr ""
|
1209 |
|
1210 |
+
#: inc/class-destination-s3.php:457
|
|
|
1211 |
msgid "%d. Trying to send backup file to S3 Service …"
|
1212 |
msgstr ""
|
1213 |
|
1214 |
+
#: inc/class-destination-s3.php:470 inc/pro/class-destination-s3.php:188
|
|
|
1215 |
msgid "Connected to S3 Bucket \"%1$s\" in %2$s"
|
1216 |
msgstr ""
|
1217 |
|
1218 |
+
#: inc/class-destination-s3.php:473 inc/pro/class-destination-s3.php:191
|
|
|
1219 |
msgid "S3 Bucket \"%s\" does not exist!"
|
1220 |
msgstr ""
|
1221 |
|
1222 |
+
#: inc/class-destination-s3.php:480
|
1223 |
msgid "Checking for not aborted multipart Uploads …"
|
1224 |
msgstr ""
|
1225 |
|
1226 |
+
#: inc/class-destination-s3.php:486
|
|
|
1227 |
msgid "Upload for %s aborted."
|
1228 |
msgstr ""
|
1229 |
|
1230 |
+
#: inc/class-destination-s3.php:492
|
1231 |
msgid "Starting upload to S3 Service …"
|
1232 |
msgstr ""
|
1233 |
|
1234 |
+
#: inc/class-destination-s3.php:601 inc/pro/class-destination-glacier.php:444
|
|
|
1235 |
msgid "Backup transferred to %s."
|
1236 |
msgstr ""
|
1237 |
|
1238 |
+
#: inc/class-destination-s3.php:606
|
|
|
1239 |
msgid "Cannot transfer backup to S3! (%1$d) %2$s"
|
1240 |
msgstr ""
|
1241 |
|
1242 |
+
#: inc/class-destination-s3.php:634
|
|
|
1243 |
msgid "Storage Class: %s"
|
1244 |
msgstr ""
|
1245 |
|
1246 |
+
#: inc/class-destination-s3.php:660
|
|
|
1247 |
msgid "Cannot delete backup from %s."
|
1248 |
msgstr ""
|
1249 |
|
1250 |
+
#: inc/class-destination-s3.php:664
|
|
|
1251 |
msgid "One file deleted on S3 Bucket."
|
1252 |
msgid_plural "%d files deleted on S3 Bucket"
|
1253 |
msgstr[0] ""
|
1269 |
msgstr ""
|
1270 |
|
1271 |
#: inc/class-destination-sugarsync.php:37
|
1272 |
+
#: inc/class-destination-sugarsync.php:120
|
1273 |
msgid "Authenticate with Sugarsync!"
|
1274 |
msgstr ""
|
1275 |
|
1276 |
#: inc/class-destination-sugarsync.php:38
|
1277 |
+
#: inc/class-destination-sugarsync.php:136
|
1278 |
#: inc/pro/class-destination-sugarsync.php:26
|
1279 |
#: inc/pro/class-destination-sugarsync.php:98
|
1280 |
msgid "Create Sugarsync account"
|
1281 |
msgstr ""
|
1282 |
|
1283 |
#: inc/class-destination-sugarsync.php:46
|
1284 |
+
#: inc/class-destination-sugarsync.php:132
|
1285 |
#: inc/pro/class-destination-sugarsync.php:32
|
1286 |
#: inc/pro/class-destination-sugarsync.php:94
|
1287 |
msgid "Delete Sugarsync authentication!"
|
1304 |
msgid "Folder in root"
|
1305 |
msgstr ""
|
1306 |
|
1307 |
+
#: inc/class-destination-sugarsync.php:230
|
|
|
1308 |
msgid "%d. Try to send backup to SugarSync …"
|
1309 |
msgstr ""
|
1310 |
|
1311 |
+
#: inc/class-destination-sugarsync.php:237
|
|
|
1312 |
msgid "Authenticated to SugarSync with nickname %s"
|
1313 |
msgstr ""
|
1314 |
|
1315 |
+
#: inc/class-destination-sugarsync.php:240
|
|
|
1316 |
msgctxt "Available space on SugarSync"
|
1317 |
msgid "Not enough disk space available on SugarSync. Available: %s."
|
1318 |
msgstr ""
|
1319 |
|
1320 |
+
#: inc/class-destination-sugarsync.php:246
|
|
|
1321 |
msgid "%s available at SugarSync"
|
1322 |
msgstr ""
|
1323 |
|
1324 |
+
#: inc/class-destination-sugarsync.php:253
|
1325 |
msgid "Starting upload to SugarSync …"
|
1326 |
msgstr ""
|
1327 |
|
1328 |
+
#: inc/class-destination-sugarsync.php:263
|
1329 |
msgid "Cannot transfer backup to SugarSync!"
|
1330 |
msgstr ""
|
1331 |
|
1332 |
+
#: inc/class-destination-sugarsync.php:302
|
|
|
1333 |
msgid "One file deleted on SugarSync folder"
|
1334 |
msgid_plural "%d files deleted on SugarSync folder"
|
1335 |
msgstr[0] ""
|
1336 |
msgstr[1] ""
|
1337 |
|
1338 |
+
#: inc/class-destination-sugarsync.php:308
|
|
|
1339 |
msgid "SugarSync API: %s"
|
1340 |
msgstr ""
|
1341 |
|
1342 |
#: inc/class-easycron.php:179
|
|
|
1343 |
msgid "EasyCron.com API returns (%s): %s"
|
1344 |
msgstr ""
|
1345 |
|
1348 |
msgstr ""
|
1349 |
|
1350 |
#: inc/class-easycron.php:189
|
1351 |
+
msgid ""
|
1352 |
+
"Here you can setup your <a href=\"https://www.easycron.com/user/token?"
|
1353 |
+
"ref=36673\" title=\"Affiliate Link!\">EasyCron.com API key</a> to use this "
|
1354 |
+
"service."
|
1355 |
msgstr ""
|
1356 |
|
1357 |
#: inc/class-easycron.php:192
|
1363 |
msgstr ""
|
1364 |
|
1365 |
#: inc/class-easycron.php:203
|
1366 |
+
msgid ""
|
1367 |
+
"If you check this box, a cron job will be created on EasyCron that all 5 "
|
1368 |
+
"Minutes calls the WordPress cron."
|
1369 |
msgstr ""
|
1370 |
|
1371 |
+
#: inc/class-file.php:138
|
|
|
1372 |
msgid "Folder %1$s not allowed, please use another folder."
|
1373 |
msgstr ""
|
1374 |
|
1375 |
+
#: inc/class-file.php:143
|
|
|
1376 |
msgid "Folder %1$s is not in open basedir, please use another folder."
|
1377 |
msgstr ""
|
1378 |
|
1379 |
+
#: inc/class-file.php:149
|
|
|
1380 |
msgid "Cannot create folder: %1$s"
|
1381 |
msgstr ""
|
1382 |
|
1383 |
+
#: inc/class-file.php:155
|
|
|
1384 |
msgid "Folder \"%1$s\" is not writable"
|
1385 |
msgstr ""
|
1386 |
|
1387 |
+
#: inc/class-file.php:191
|
1388 |
+
msgid ""
|
1389 |
+
"BackWPup will not backup folders and its sub folders when this file is "
|
1390 |
+
"inside."
|
1391 |
msgstr ""
|
1392 |
|
1393 |
#: inc/class-help.php:15
|
1395 |
msgstr ""
|
1396 |
|
1397 |
#: inc/class-help.php:17
|
|
|
1398 |
msgctxt "Plugin name and link; Plugin Version"
|
1399 |
+
msgid ""
|
1400 |
+
"%1$s version %2$s. A project by <a href=\"http://inpsyde.com\">Inpsyde GmbH</"
|
1401 |
+
"a>."
|
1402 |
msgstr ""
|
1403 |
|
1404 |
#: inc/class-help.php:18
|
1405 |
+
msgid ""
|
1406 |
+
"BackWPup comes with ABSOLUTELY NO WARRANTY. This is a free software, and you "
|
1407 |
+
"are welcome to redistribute it under certain conditions."
|
1408 |
msgstr ""
|
1409 |
|
1410 |
#: inc/class-help.php:21
|
1452 |
msgstr ""
|
1453 |
|
1454 |
#: inc/class-job.php:377
|
|
|
1455 |
msgid "BackWPup log for %1$s from %2$s at %3$s"
|
1456 |
msgstr ""
|
1457 |
|
1458 |
#: inc/class-job.php:394
|
|
|
1459 |
msgctxt "Plugin name; Plugin Version; plugin url"
|
1460 |
msgid "[INFO] %1$s %2$s; A project of Inpsyde GmbH"
|
1461 |
msgstr ""
|
1462 |
|
1463 |
#: inc/class-job.php:395
|
|
|
1464 |
msgctxt "WordPress Version; Blog url"
|
1465 |
msgid "[INFO] WordPress %1$s on %2$s"
|
1466 |
msgstr ""
|
1478 |
msgstr ""
|
1479 |
|
1480 |
#: inc/class-job.php:404
|
|
|
1481 |
msgid "[INFO] Log Level: %1$s %2$s"
|
1482 |
msgstr ""
|
1483 |
|
1484 |
#: inc/class-job.php:409
|
|
|
1485 |
msgid "[INFO] BackWPup job: %1$s"
|
1486 |
msgstr ""
|
1487 |
|
1488 |
#: inc/class-job.php:412
|
|
|
1489 |
msgid "[INFO] Runs with user: %1$s (%2$d) "
|
1490 |
msgstr ""
|
1491 |
|
1495 |
msgstr ""
|
1496 |
|
1497 |
#: inc/class-job.php:430 inc/class-job.php:440
|
|
|
1498 |
msgid "[INFO] Cron: %s; Next: %s "
|
1499 |
msgstr ""
|
1500 |
|
1531 |
msgstr ""
|
1532 |
|
1533 |
#: inc/class-job.php:463
|
|
|
1534 |
msgid "[INFO] Maximum PHP script execution time is %1$d seconds"
|
1535 |
msgstr ""
|
1536 |
|
1537 |
#: inc/class-job.php:467
|
|
|
1538 |
msgid "[INFO] Script restart time is configured to %1$d seconds"
|
1539 |
msgstr ""
|
1540 |
|
1541 |
#: inc/class-job.php:470
|
|
|
1542 |
msgid "[INFO] MySQL ver.: %s"
|
1543 |
msgstr ""
|
1544 |
|
1545 |
#: inc/class-job.php:472
|
|
|
1546 |
msgid "[INFO] Web Server: %s"
|
1547 |
msgstr ""
|
1548 |
|
1549 |
#: inc/class-job.php:476
|
|
|
1550 |
msgid "[INFO] curl ver.: %1$s; %2$s"
|
1551 |
msgstr ""
|
1552 |
|
1553 |
#: inc/class-job.php:478
|
|
|
1554 |
msgid "[INFO] Temp folder is: %s"
|
1555 |
msgstr ""
|
1556 |
|
1557 |
#: inc/class-job.php:485
|
|
|
1558 |
msgid "[INFO] Logfile is: %s"
|
1559 |
msgstr ""
|
1560 |
|
1561 |
#: inc/class-job.php:492
|
|
|
1562 |
msgid "[INFO] Backup file is: %s"
|
1563 |
msgstr ""
|
1564 |
|
1565 |
#: inc/class-job.php:494
|
|
|
1566 |
msgid "[INFO] Backup type is: %s"
|
1567 |
msgstr ""
|
1568 |
|
1571 |
msgstr ""
|
1572 |
|
1573 |
#: inc/class-job.php:514
|
1574 |
+
msgid ""
|
1575 |
+
"No destination correctly defined for backup! Please correct job settings."
|
1576 |
msgstr ""
|
1577 |
|
1578 |
+
#: inc/class-job.php:644
|
1579 |
msgid "Cannot write progress to working file. Job will be aborted."
|
1580 |
msgstr ""
|
1581 |
|
1582 |
+
#: inc/class-job.php:716 inc/class-page-jobs.php:786
|
1583 |
msgid "WARNING:"
|
1584 |
msgstr ""
|
1585 |
|
1586 |
+
#: inc/class-job.php:725 inc/class-page-jobs.php:784
|
1587 |
msgid "ERROR:"
|
1588 |
msgstr ""
|
1589 |
|
1590 |
+
#: inc/class-job.php:729
|
1591 |
msgid "DEPRECATED:"
|
1592 |
msgstr ""
|
1593 |
|
1594 |
+
#: inc/class-job.php:732
|
1595 |
msgid "STRICT NOTICE:"
|
1596 |
msgstr ""
|
1597 |
|
1598 |
+
#: inc/class-job.php:737
|
1599 |
msgid "RECOVERABLE ERROR:"
|
1600 |
msgstr ""
|
1601 |
|
1602 |
+
#: inc/class-job.php:985
|
1603 |
msgid "Aborted by user!"
|
1604 |
msgstr ""
|
1605 |
|
1606 |
+
#: inc/class-job.php:1019
|
|
|
1607 |
msgid "One old log deleted"
|
1608 |
msgid_plural "%d old logs deleted"
|
1609 |
msgstr[0] ""
|
1610 |
msgstr[1] ""
|
1611 |
|
1612 |
+
#: inc/class-job.php:1026 inc/class-page-jobs.php:784
|
1613 |
+
msgid ""
|
1614 |
+
"Job has ended with errors in %s seconds. You must resolve the errors for "
|
1615 |
+
"correct execution."
|
1616 |
msgstr ""
|
1617 |
|
1618 |
+
#: inc/class-job.php:1028
|
1619 |
+
msgid ""
|
1620 |
+
"Job finished with warnings in %s seconds. Please resolve them for correct "
|
1621 |
+
"execution."
|
1622 |
msgstr ""
|
1623 |
|
1624 |
+
#: inc/class-job.php:1030 inc/class-page-jobs.php:788
|
|
|
1625 |
msgid "Job done in %s seconds."
|
1626 |
msgstr ""
|
1627 |
|
1628 |
+
#: inc/class-job.php:1074
|
1629 |
msgid "SUCCESSFUL"
|
1630 |
msgstr ""
|
1631 |
|
1632 |
+
#: inc/class-job.php:1076
|
1633 |
msgid "WARNING"
|
1634 |
msgstr ""
|
1635 |
|
1636 |
+
#: inc/class-job.php:1079
|
1637 |
msgid "ERROR"
|
1638 |
msgstr ""
|
1639 |
|
1640 |
+
#: inc/class-job.php:1082
|
|
|
1641 |
msgid "[%3$s] BackWPup log %1$s: %2$s"
|
1642 |
msgstr ""
|
1643 |
|
1644 |
+
#: inc/class-job.php:1188
|
|
|
1645 |
msgid "Restart after %1$d seconds."
|
1646 |
msgstr ""
|
1647 |
|
1648 |
+
#: inc/class-job.php:1190
|
1649 |
msgid "Restart after getting signal."
|
1650 |
msgstr ""
|
1651 |
|
1652 |
+
#: inc/class-job.php:1363
|
1653 |
msgid "Job restarts due to inactivity for more than 5 minutes."
|
1654 |
msgstr ""
|
1655 |
|
1656 |
+
#: inc/class-job.php:1461
|
1657 |
msgid "Step aborted: too many attempts!"
|
1658 |
msgstr ""
|
1659 |
|
1660 |
+
#: inc/class-job.php:1532
|
|
|
1661 |
msgid "%d. Trying to create backup archive …"
|
1662 |
msgstr ""
|
1663 |
|
1664 |
+
#: inc/class-job.php:1540
|
|
|
1665 |
msgctxt "Archive compression method"
|
1666 |
msgid "Compressing files as %s. Please be patient, this may take a moment."
|
1667 |
msgstr ""
|
1668 |
|
1669 |
+
#: inc/class-job.php:1547
|
1670 |
msgid "Adding Extra files to Archive"
|
1671 |
msgstr ""
|
1672 |
|
1673 |
+
#: inc/class-job.php:1559 inc/class-job.php:1619
|
1674 |
msgid "Cannot create backup archive correctly. Aborting creation."
|
1675 |
msgstr ""
|
1676 |
|
1677 |
+
#: inc/class-job.php:1575
|
|
|
1678 |
msgid "Archiving Folder: %s"
|
1679 |
msgstr ""
|
1680 |
|
1681 |
+
#: inc/class-job.php:1629
|
1682 |
msgid "Backup archive created."
|
1683 |
msgstr ""
|
1684 |
|
1685 |
+
#: inc/class-job.php:1643
|
1686 |
+
msgid ""
|
1687 |
+
"The Backup archive will be too large for file operations with this PHP "
|
1688 |
+
"Version. You might want to consider splitting the backup job in multiple "
|
1689 |
+
"jobs with less files each."
|
1690 |
msgstr ""
|
1691 |
|
1692 |
+
#: inc/class-job.php:1646
|
|
|
1693 |
msgid "Archive size is %s."
|
1694 |
msgstr ""
|
1695 |
|
1696 |
+
#: inc/class-job.php:1649
|
|
|
1697 |
msgid "%1$d Files with %2$s in Archive."
|
1698 |
msgstr ""
|
1699 |
|
1700 |
+
#: inc/class-job.php:1698
|
|
|
1701 |
msgctxt "Folder name"
|
1702 |
+
msgid "Folder %s does not exist"
|
1703 |
msgstr ""
|
1704 |
|
1705 |
+
#: inc/class-job.php:1703
|
|
|
1706 |
msgctxt "Folder name"
|
1707 |
+
msgid "Folder %s is not readable"
|
1708 |
msgstr ""
|
1709 |
|
1710 |
+
#: inc/class-job.php:1724
|
|
|
1711 |
msgid "Link \"%s\" not following."
|
1712 |
msgstr ""
|
1713 |
|
1714 |
+
#: inc/class-job.php:1726
|
|
|
1715 |
msgid "File \"%s\" is not readable!"
|
1716 |
msgstr ""
|
1717 |
|
1718 |
+
#: inc/class-job.php:1730
|
1719 |
+
msgid ""
|
1720 |
+
"File size of “%s” cannot be retrieved. File might be too large and will not "
|
1721 |
+
"be added to queue."
|
1722 |
msgstr ""
|
1723 |
|
1724 |
+
#: inc/class-job.php:1813
|
|
|
1725 |
msgid "%d. Trying to generate a manifest file …"
|
1726 |
msgstr ""
|
1727 |
|
1728 |
+
#: inc/class-job.php:1869
|
1729 |
msgid "You may have noticed the manifest.json file in this archive."
|
1730 |
msgstr ""
|
1731 |
|
1732 |
+
#: inc/class-job.php:1870
|
1733 |
+
msgid ""
|
1734 |
+
"manifest.json might be needed for later restoring a backup from this archive."
|
1735 |
msgstr ""
|
1736 |
|
1737 |
+
#: inc/class-job.php:1871
|
1738 |
+
msgid ""
|
1739 |
+
"Please leave manifest.json untouched and in place. Otherwise it is safe to "
|
1740 |
+
"be ignored."
|
1741 |
msgstr ""
|
1742 |
|
1743 |
+
#: inc/class-job.php:1881
|
|
|
1744 |
msgid "Added manifest.json file with %1$s to backup file list."
|
1745 |
msgstr ""
|
1746 |
|
1747 |
+
#: inc/class-job.php:1920
|
1748 |
msgid "Wrong BackWPup JobID"
|
1749 |
msgstr ""
|
1750 |
|
1751 |
+
#: inc/class-job.php:1933
|
1752 |
msgid "A BackWPup job is already running"
|
1753 |
msgstr ""
|
1754 |
|
1755 |
+
#: inc/class-job.php:2301
|
1756 |
+
msgctxt ""
|
1757 |
+
"SIGHUP: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1758 |
+
"details"
|
1759 |
msgid "Hangup detected on controlling terminal or death of controlling process"
|
1760 |
msgstr ""
|
1761 |
|
1762 |
+
#: inc/class-job.php:2305
|
1763 |
+
msgctxt ""
|
1764 |
+
"SIGINT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1765 |
+
"details"
|
1766 |
msgid "Interrupt from keyboard"
|
1767 |
msgstr ""
|
1768 |
|
1769 |
+
#: inc/class-job.php:2309
|
1770 |
+
msgctxt ""
|
1771 |
+
"SIGQUIT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1772 |
+
"details"
|
1773 |
msgid "Quit from keyboard"
|
1774 |
msgstr ""
|
1775 |
|
1776 |
+
#: inc/class-job.php:2313
|
1777 |
+
msgctxt ""
|
1778 |
+
"SIGILL: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1779 |
+
"details"
|
1780 |
msgid "Illegal Instruction"
|
1781 |
msgstr ""
|
1782 |
|
1783 |
+
#: inc/class-job.php:2317
|
1784 |
+
msgctxt ""
|
1785 |
+
"SIGABRT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1786 |
+
"details"
|
1787 |
msgid "Abort signal from abort(3)"
|
1788 |
msgstr ""
|
1789 |
|
1790 |
+
#: inc/class-job.php:2321
|
1791 |
+
msgctxt ""
|
1792 |
+
"SIGBUS: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1793 |
+
"details"
|
1794 |
msgid "Bus error (bad memory access)"
|
1795 |
msgstr ""
|
1796 |
|
1797 |
+
#: inc/class-job.php:2325
|
1798 |
+
msgctxt ""
|
1799 |
+
"SIGFPE: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1800 |
+
"details"
|
1801 |
msgid "Floating point exception"
|
1802 |
msgstr ""
|
1803 |
|
1804 |
+
#: inc/class-job.php:2329
|
1805 |
+
msgctxt ""
|
1806 |
+
"SIGSEGV: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1807 |
+
"details"
|
1808 |
msgid "Invalid memory reference"
|
1809 |
msgstr ""
|
1810 |
|
1811 |
+
#: inc/class-job.php:2333
|
1812 |
+
msgctxt ""
|
1813 |
+
"SIGTERM: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1814 |
+
"details"
|
1815 |
msgid "Termination signal"
|
1816 |
msgstr ""
|
1817 |
|
1818 |
+
#: inc/class-job.php:2337
|
1819 |
+
msgctxt ""
|
1820 |
+
"SIGSTKFLT: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1821 |
+
"details"
|
1822 |
msgid "Stack fault on coprocessor"
|
1823 |
msgstr ""
|
1824 |
|
1825 |
+
#: inc/class-job.php:2341
|
1826 |
+
msgctxt ""
|
1827 |
+
"SIGUSR1: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1828 |
+
"details"
|
1829 |
msgid "User-defined signal 1"
|
1830 |
msgstr ""
|
1831 |
|
1832 |
+
#: inc/class-job.php:2345
|
1833 |
+
msgctxt ""
|
1834 |
+
"SIGUSR2: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1835 |
+
"details"
|
1836 |
msgid "User-defined signal 2"
|
1837 |
msgstr ""
|
1838 |
|
1839 |
+
#: inc/class-job.php:2349
|
1840 |
+
msgctxt ""
|
1841 |
+
"SIGURG: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1842 |
+
"details"
|
1843 |
msgid "Urgent condition on socket"
|
1844 |
msgstr ""
|
1845 |
|
1846 |
+
#: inc/class-job.php:2353
|
1847 |
+
msgctxt ""
|
1848 |
+
"SIGXCPU: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1849 |
+
"details"
|
1850 |
msgid "CPU time limit exceeded"
|
1851 |
msgstr ""
|
1852 |
|
1853 |
+
#: inc/class-job.php:2357
|
1854 |
+
msgctxt ""
|
1855 |
+
"SIGXFSZ: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1856 |
+
"details"
|
1857 |
msgid "File size limit exceeded"
|
1858 |
msgstr ""
|
1859 |
|
1860 |
+
#: inc/class-job.php:2361
|
1861 |
+
msgctxt ""
|
1862 |
+
"SIGPWR: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1863 |
+
"details"
|
1864 |
msgid "Power failure"
|
1865 |
msgstr ""
|
1866 |
|
1867 |
+
#: inc/class-job.php:2365
|
1868 |
+
msgctxt ""
|
1869 |
+
"SIGSYS: Please see http://man7.org/linux/man-pages/man7/signal.7.html for "
|
1870 |
+
"details"
|
1871 |
msgid "Bad argument to routine"
|
1872 |
msgstr ""
|
1873 |
|
1874 |
+
#: inc/class-job.php:2372
|
|
|
1875 |
msgid "Signal \"%1$s\" (%2$s) is sent to script!"
|
1876 |
msgstr ""
|
1877 |
|
1878 |
+
#: inc/class-job.php:2406 inc/class-job.php:2419
|
|
|
1879 |
msgid "System: %s"
|
1880 |
msgstr ""
|
1881 |
|
1882 |
+
#: inc/class-job.php:2434
|
|
|
1883 |
msgid "Exception caught in %1$s: %2$s"
|
1884 |
msgstr ""
|
1885 |
|
1891 |
msgid "Check database tables"
|
1892 |
msgstr ""
|
1893 |
|
1894 |
+
#. #-#-#-#-# backwpup.pot (BackWPup Pro 3.3.7) #-#-#-#-#
|
1895 |
+
#. Author URI of the plugin/theme
|
1896 |
#: inc/class-jobtype-dbcheck.php:17 inc/class-jobtype-dbdump.php:17
|
1897 |
#: inc/class-jobtype-file.php:17 inc/class-jobtype-wpexp.php:17
|
1898 |
#: inc/class-jobtype-wpplugin.php:17 inc/pro/class-wizard-job.php:19
|
1922 |
msgstr ""
|
1923 |
|
1924 |
#: inc/class-jobtype-dbcheck.php:79
|
|
|
1925 |
msgid "%d. Trying to check database …"
|
1926 |
msgstr ""
|
1927 |
|
1928 |
#: inc/class-jobtype-dbcheck.php:111
|
|
|
1929 |
msgid "Table %1$s is a view. Not checked."
|
1930 |
msgstr ""
|
1931 |
|
1932 |
#: inc/class-jobtype-dbcheck.php:116
|
|
|
1933 |
msgid "Table %1$s is not a MyISAM/InnoDB table. Not checked."
|
1934 |
msgstr ""
|
1935 |
|
1936 |
#: inc/class-jobtype-dbcheck.php:124 inc/class-jobtype-dbcheck.php:127
|
1937 |
#: inc/class-jobtype-dbcheck.php:129
|
|
|
1938 |
msgid "Result of table check for %1$s is: %2$s"
|
1939 |
msgstr ""
|
1940 |
|
1941 |
#: inc/class-jobtype-dbcheck.php:135 inc/class-jobtype-dbcheck.php:137
|
1942 |
#: inc/class-jobtype-dbcheck.php:139
|
|
|
1943 |
msgid "Result of table repair for %1$s is: %2$s"
|
1944 |
msgstr ""
|
1945 |
|
1988 |
msgstr ""
|
1989 |
|
1990 |
#: inc/class-jobtype-dbdump.php:159 inc/pro/class-jobtype-dbdump.php:475
|
|
|
1991 |
msgid "%d. Try to backup database …"
|
1992 |
msgstr ""
|
1993 |
|
1994 |
#: inc/class-jobtype-dbdump.php:173 inc/pro/class-jobtype-dbdump.php:495
|
|
|
1995 |
msgid "Connected to database %1$s on %2$s"
|
1996 |
msgstr ""
|
1997 |
|
2000 |
msgstr ""
|
2001 |
|
2002 |
#: inc/class-jobtype-dbdump.php:210 inc/pro/class-jobtype-dbdump.php:536
|
|
|
2003 |
msgid "Backup database table \"%s\" with \"%s\" records"
|
2004 |
msgstr ""
|
2005 |
|
2008 |
msgstr ""
|
2009 |
|
2010 |
#: inc/class-jobtype-dbdump.php:254 inc/pro/class-jobtype-dbdump.php:763
|
|
|
2011 |
msgid "Added database dump \"%1$s\" with %2$s to backup file list"
|
2012 |
msgstr ""
|
2013 |
|
2032 |
msgid "Backup WordPress install folder"
|
2033 |
msgstr ""
|
2034 |
|
2035 |
+
#: inc/class-jobtype-file.php:83
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2036 |
msgid "Backup content folder"
|
2037 |
msgstr ""
|
2038 |
|
2039 |
+
#: inc/class-jobtype-file.php:91
|
2040 |
msgid "Backup plugins"
|
2041 |
msgstr ""
|
2042 |
|
2043 |
+
#: inc/class-jobtype-file.php:99
|
2044 |
msgid "Backup themes"
|
2045 |
msgstr ""
|
2046 |
|
2047 |
+
#: inc/class-jobtype-file.php:107 inc/pro/class-wizard-job.php:745
|
2048 |
#: inc/pro/class-wizard-job.php:746
|
2049 |
msgid "Backup uploads folder"
|
2050 |
msgstr ""
|
2051 |
|
2052 |
+
#: inc/class-jobtype-file.php:115
|
2053 |
msgid "Extra folders to backup"
|
2054 |
msgstr ""
|
2055 |
|
2056 |
+
#: inc/class-jobtype-file.php:118
|
2057 |
+
msgid ""
|
2058 |
+
"Separate folder names with a line-break or a comma. Folders must be set with "
|
2059 |
+
"their absolute path!"
|
2060 |
msgstr ""
|
2061 |
|
2062 |
+
#: inc/class-jobtype-file.php:123
|
2063 |
msgid "Exclude from backup"
|
2064 |
msgstr ""
|
2065 |
|
2066 |
+
#: inc/class-jobtype-file.php:127
|
2067 |
msgid "Thumbnails in uploads"
|
2068 |
msgstr ""
|
2069 |
|
2070 |
+
#: inc/class-jobtype-file.php:129
|
2071 |
msgid "Don't backup thumbnails from the site's uploads folder."
|
2072 |
msgstr ""
|
2073 |
|
2074 |
+
#: inc/class-jobtype-file.php:133
|
2075 |
msgid "Exclude files/folders from backup"
|
2076 |
msgstr ""
|
2077 |
|
2078 |
+
#: inc/class-jobtype-file.php:136
|
2079 |
+
msgid ""
|
2080 |
+
"Separate file / folder name parts with a line-break or a comma. For example /"
|
2081 |
+
"logs/,.log,.tmp"
|
2082 |
msgstr ""
|
2083 |
|
2084 |
+
#: inc/class-jobtype-file.php:141
|
2085 |
msgid "Special options"
|
2086 |
msgstr ""
|
2087 |
|
2088 |
+
#: inc/class-jobtype-file.php:145
|
2089 |
msgid "Include special files"
|
2090 |
msgstr ""
|
2091 |
|
2092 |
+
#: inc/class-jobtype-file.php:147
|
2093 |
+
msgid ""
|
2094 |
+
"Backup wp-config.php, robots.txt, nginx.conf, .htaccess, .htpasswd, favicon."
|
2095 |
+
"ico, and Web.config from root if it is not included in backup."
|
2096 |
msgstr ""
|
2097 |
|
2098 |
+
#: inc/class-jobtype-file.php:151
|
2099 |
msgid "Use one folder above as WP install folder"
|
2100 |
msgstr ""
|
2101 |
|
2102 |
+
#: inc/class-jobtype-file.php:154
|
2103 |
+
msgid ""
|
2104 |
+
"Use one folder above as WordPress install folder! That can be helpful, if "
|
2105 |
+
"you would backup files and folder that are not in the WordPress installation "
|
2106 |
+
"folder. Or if you made a \"<a href=\"https://codex.wordpress.org/"
|
2107 |
+
"Giving_WordPress_Its_Own_Directory\">Giving WordPress Its Own Directory</a>"
|
2108 |
+
"\" installation. Excludes must be configured again."
|
2109 |
msgstr ""
|
2110 |
|
2111 |
+
#: inc/class-jobtype-file.php:237
|
|
|
2112 |
msgid "%d. Trying to make a list of folders to back up …"
|
2113 |
msgstr ""
|
2114 |
|
2115 |
+
#: inc/class-jobtype-file.php:357 inc/class-jobtype-file.php:361
|
2116 |
+
#: inc/class-jobtype-file.php:378
|
|
|
|
|
|
|
2117 |
msgid "Added \"%s\" to backup file list"
|
2118 |
msgstr ""
|
2119 |
|
2120 |
+
#: inc/class-jobtype-file.php:384
|
2121 |
msgid "No files/folder for the backup."
|
2122 |
msgstr ""
|
2123 |
|
2124 |
+
#: inc/class-jobtype-file.php:386
|
|
|
2125 |
msgid "%1$d folders to backup."
|
2126 |
msgstr ""
|
2127 |
|
2128 |
+
#: inc/class-jobtype-file.php:433
|
|
|
2129 |
msgid "Folder \"%s\" is not readable!"
|
2130 |
msgstr ""
|
2131 |
|
2132 |
+
#: inc/class-jobtype-file.php:493
|
2133 |
+
msgid "Path as set by user (symlink?): %s"
|
2134 |
+
msgstr ""
|
2135 |
+
|
2136 |
+
#: inc/class-jobtype-file.php:496
|
2137 |
+
msgid "Exclude:"
|
2138 |
+
msgstr ""
|
2139 |
+
|
2140 |
+
#: inc/class-jobtype-file.php:508
|
2141 |
+
msgid "Excluded by .donotbackup file!"
|
2142 |
+
msgstr ""
|
2143 |
+
|
2144 |
#: inc/class-jobtype-wpexp.php:13
|
2145 |
msgid "XML export"
|
2146 |
msgstr ""
|
2179 |
msgstr ""
|
2180 |
|
2181 |
#: inc/class-jobtype-wpexp.php:112
|
|
|
2182 |
msgid "%d. Trying to create a WordPress export to XML file …"
|
2183 |
msgstr ""
|
2184 |
|
2185 |
#: inc/class-jobtype-wpexp.php:127
|
2186 |
+
msgid "WP Export: Post type “%s” does not allow export."
|
|
|
2187 |
msgstr ""
|
2188 |
|
2189 |
#: inc/class-jobtype-wpexp.php:172 inc/class-jobtype-wpexp.php:186
|
2198 |
msgstr ""
|
2199 |
|
2200 |
#: inc/class-jobtype-wpexp.php:422
|
|
|
2201 |
msgid "XML WARNING (%s): %s"
|
2202 |
msgstr ""
|
2203 |
|
2204 |
#: inc/class-jobtype-wpexp.php:425
|
|
|
2205 |
msgid "XML RECOVERABLE (%s): %s"
|
2206 |
msgstr ""
|
2207 |
|
2208 |
#: inc/class-jobtype-wpexp.php:428
|
|
|
2209 |
msgid "XML ERROR (%s): %s"
|
2210 |
msgstr ""
|
2211 |
|
2214 |
msgstr ""
|
2215 |
|
2216 |
#: inc/class-jobtype-wpexp.php:444 inc/class-jobtype-wpexp.php:451
|
2217 |
+
msgid ""
|
2218 |
+
"This does not appear to be a WXR file, missing/invalid WXR version number"
|
2219 |
msgstr ""
|
2220 |
|
2221 |
#: inc/class-jobtype-wpexp.php:460
|
2223 |
msgstr ""
|
2224 |
|
2225 |
#: inc/class-jobtype-wpexp.php:462
|
2226 |
+
msgid ""
|
2227 |
+
"WP Export file can not be checked, because no XML extension is loaded, to "
|
2228 |
+
"ensure the file verification."
|
2229 |
msgstr ""
|
2230 |
|
2231 |
#: inc/class-jobtype-wpexp.php:474 inc/pro/class-jobtype-dbdump.php:741
|
2237 |
msgstr ""
|
2238 |
|
2239 |
#: inc/class-jobtype-wpexp.php:500
|
|
|
2240 |
msgid "Added XML export \"%1$s\" with %2$s to backup file list."
|
2241 |
msgstr ""
|
2242 |
|
2253 |
msgstr ""
|
2254 |
|
2255 |
#: inc/class-jobtype-wpplugin.php:96
|
|
|
2256 |
msgid "%d. Trying to generate a file with installed plugin names …"
|
2257 |
msgstr ""
|
2258 |
|
2261 |
msgstr ""
|
2262 |
|
2263 |
#: inc/class-jobtype-wpplugin.php:126
|
|
|
2264 |
msgid "from %s"
|
2265 |
msgstr ""
|
2266 |
|
2277 |
msgstr ""
|
2278 |
|
2279 |
#: inc/class-jobtype-wpplugin.php:148
|
|
|
2280 |
msgid "Added plugin list file \"%1$s\" with %2$s to backup file list."
|
2281 |
msgstr ""
|
2282 |
|
2297 |
msgstr ""
|
2298 |
|
2299 |
#: inc/class-mysqldump.php:110 inc/pro/class-jobtype-dbdump.php:843
|
|
|
2300 |
msgid "Cannot connect to MySQL database %1$d: %2$s"
|
2301 |
msgstr ""
|
2302 |
|
2303 |
#: inc/class-mysqldump.php:117
|
|
|
2304 |
msgctxt "Database Charset"
|
2305 |
msgid "Cannot set DB charset to %s error: %s"
|
2306 |
msgstr ""
|
2318 |
#: inc/pro/class-jobtype-dbdump.php:859 inc/pro/class-jobtype-dbdump.php:873
|
2319 |
#: inc/pro/class-jobtype-dbdump.php:921 inc/pro/class-jobtype-dbdump.php:940
|
2320 |
#: inc/pro/class-jobtype-dbdump.php:983
|
|
|
2321 |
msgid "Database error %1$s for query %2$s"
|
2322 |
msgstr ""
|
2323 |
|
2324 |
#: inc/class-mysqldump.php:479
|
|
|
2325 |
msgid "Start for table backup is not correctly set: %1$s"
|
2326 |
msgstr ""
|
2327 |
|
2328 |
#: inc/class-mysqldump.php:483
|
|
|
2329 |
msgid "Length for table backup is not correctly set: %1$s"
|
2330 |
msgstr ""
|
2331 |
|
2332 |
+
#: inc/class-mysqldump.php:561
|
2333 |
msgid "Error while writing file!"
|
2334 |
msgstr ""
|
2335 |
|
2336 |
+
#: inc/class-option.php:167 inc/class-page-editjob.php:97
|
2337 |
+
#: inc/class-page-editjob.php:383
|
2338 |
msgid "New Job"
|
2339 |
msgstr ""
|
2340 |
|
2343 |
msgstr ""
|
2344 |
|
2345 |
#: inc/class-page-about.php:370 inc/class-page-backwpup.php:75
|
2346 |
+
msgid ""
|
2347 |
+
"BackWPup’s job wizards make planning and scheduling your backup jobs a "
|
2348 |
+
"breeze."
|
2349 |
msgstr ""
|
2350 |
|
2351 |
#: inc/class-page-about.php:371 inc/class-page-about.php:384
|
2352 |
+
msgid ""
|
2353 |
+
"Use your backup archives to save your entire WordPress installation "
|
2354 |
+
"including <code>/wp-content/</code>. Push them to an external storage "
|
2355 |
+
"service if you don’t want to save the backups on the same server. With a "
|
2356 |
+
"single backup archive you are able to restore an installation. Use a tool "
|
2357 |
+
"like phpMyAdmin to restore your database backup files."
|
2358 |
msgstr ""
|
2359 |
|
2360 |
#: inc/class-page-about.php:372
|
2361 |
+
msgid ""
|
2362 |
+
"Ready to <a href=\"%1$s\">set up a backup job</a>? You can <a href=\"%2$s"
|
2363 |
+
"\">use the wizards</a> or plan your backup in expert mode."
|
2364 |
msgstr ""
|
2365 |
|
2366 |
#: inc/class-page-about.php:382
|
2368 |
msgstr ""
|
2369 |
|
2370 |
#: inc/class-page-about.php:385
|
2371 |
+
msgid ""
|
2372 |
+
"Ready to set up a backup job? Use one of the wizards to plan what you want "
|
2373 |
+
"to save."
|
2374 |
msgstr ""
|
2375 |
|
2376 |
#: inc/class-page-about.php:398
|
2382 |
msgstr ""
|
2383 |
|
2384 |
#: inc/class-page-about.php:402
|
2385 |
+
msgid ""
|
2386 |
+
"With BackWPup you can schedule the database backup to run automatically. "
|
2387 |
+
"With a single backup file you can restore your database. You should <a href="
|
2388 |
+
"\"%s\">set up a backup job</a>, so you will never forget it. There is also "
|
2389 |
+
"an option to repair and optimize the database after each backup."
|
2390 |
msgstr ""
|
2391 |
|
2392 |
#: inc/class-page-about.php:407 inc/class-page-about.php:411
|
2394 |
msgstr ""
|
2395 |
|
2396 |
#: inc/class-page-about.php:408
|
2397 |
+
msgid ""
|
2398 |
+
"You can choose the built-in WordPress export format in addition or exclusive "
|
2399 |
+
"to save your data. This works in automated backups too of course. The "
|
2400 |
+
"advantage is: you can import these files into a blog with the regular "
|
2401 |
+
"WordPress importer."
|
2402 |
msgstr ""
|
2403 |
|
2404 |
#: inc/class-page-about.php:416
|
2410 |
msgstr ""
|
2411 |
|
2412 |
#: inc/class-page-about.php:420
|
2413 |
+
msgid ""
|
2414 |
+
"You can backup all your attachments, also all system files, plugins and "
|
2415 |
+
"themes in a single file. You can <a href=\"%s\">create a job</a> to update a "
|
2416 |
+
"backup copy of your file system only when files are changed."
|
2417 |
msgstr ""
|
2418 |
|
2419 |
#: inc/class-page-about.php:425 inc/class-page-about.php:429
|
2421 |
msgstr ""
|
2422 |
|
2423 |
#: inc/class-page-about.php:426
|
2424 |
+
msgid ""
|
2425 |
+
"By default everything is encrypted: connections to external services, local "
|
2426 |
+
"files and access to directories."
|
2427 |
msgstr ""
|
2428 |
|
2429 |
#: inc/class-page-about.php:434 inc/class-page-about.php:437
|
2431 |
msgstr ""
|
2432 |
|
2433 |
#: inc/class-page-about.php:438
|
2434 |
+
msgid ""
|
2435 |
+
"BackWPup supports multiple cloud services in parallel. This ensures backups "
|
2436 |
+
"are redundant."
|
2437 |
msgstr ""
|
2438 |
|
2439 |
#: inc/class-page-about.php:444
|
2619 |
msgstr ""
|
2620 |
|
2621 |
#: inc/class-page-backups.php:361 inc/class-page-backwpup.php:321
|
2622 |
+
#: inc/class-page-backwpup.php:384 inc/class-page-jobs.php:318
|
2623 |
#: inc/class-page-logs.php:164
|
|
|
2624 |
msgid "%1$s at %2$s"
|
2625 |
msgstr ""
|
2626 |
|
2634 |
msgstr ""
|
2635 |
|
2636 |
#: inc/class-page-backups.php:489
|
|
|
2637 |
msgid "%s › Manage Backup Archives"
|
2638 |
msgstr ""
|
2639 |
|
2640 |
#: inc/class-page-backwpup.php:67
|
|
|
2641 |
msgid "%s › Dashboard"
|
2642 |
msgstr ""
|
2643 |
|
2647 |
msgstr ""
|
2648 |
|
2649 |
#: inc/class-page-backwpup.php:75 inc/class-page-backwpup.php:84
|
2650 |
+
msgid ""
|
2651 |
+
"Use your backup archives to save your entire WordPress installation "
|
2652 |
+
"including <code>/wp-content/</code>. Push them to an external storage "
|
2653 |
+
"service if you don’t want to save the backups on the same server."
|
2654 |
msgstr ""
|
2655 |
|
2656 |
#: inc/class-page-backwpup.php:76 inc/class-page-backwpup.php:85
|
2659 |
msgstr ""
|
2660 |
|
2661 |
#: inc/class-page-backwpup.php:77 inc/class-page-backwpup.php:86
|
2662 |
+
msgid ""
|
2663 |
+
"With a single backup archive you are able to restore an installation. Use a "
|
2664 |
+
"tool like phpMyAdmin to restore your database backup files."
|
2665 |
msgstr ""
|
2666 |
|
2667 |
#: inc/class-page-backwpup.php:78 inc/class-page-backwpup.php:87
|
2670 |
msgstr ""
|
2671 |
|
2672 |
#: inc/class-page-backwpup.php:79
|
2673 |
+
msgid ""
|
2674 |
+
"Use one of the wizards to plan a backup, or use <a href=\"%s\">expert mode</"
|
2675 |
+
"a> for full control over all options."
|
2676 |
msgstr ""
|
2677 |
|
2678 |
#: inc/class-page-backwpup.php:79 inc/class-page-backwpup.php:89
|
2679 |
+
msgid ""
|
2680 |
+
"<strong>Please note: You are solely responsible for the security of your "
|
2681 |
+
"data; the authors of this plugin are not.</strong>"
|
2682 |
msgstr ""
|
2683 |
|
2684 |
#: inc/class-page-backwpup.php:84
|
2685 |
+
msgid ""
|
2686 |
+
"Use the short links in the <strong>First steps</strong> box to plan and "
|
2687 |
+
"schedule backup jobs."
|
2688 |
msgstr ""
|
2689 |
|
2690 |
#: inc/class-page-backwpup.php:88
|
|
|
2691 |
msgid "<a href=\"%s\">Add a new backup job</a> and plan what you want to save."
|
2692 |
msgstr ""
|
2693 |
|
2720 |
msgstr ""
|
2721 |
|
2722 |
#: inc/class-page-backwpup.php:117
|
2723 |
+
msgid ""
|
2724 |
+
"Generate a database backup of WordPress tables and download it right away!"
|
2725 |
msgstr ""
|
2726 |
|
2727 |
#: inc/class-page-backwpup.php:117
|
2738 |
msgstr ""
|
2739 |
|
2740 |
#: inc/class-page-backwpup.php:130
|
|
|
2741 |
msgid "<strong>RSS Error</strong>: %s"
|
2742 |
msgstr ""
|
2743 |
|
2744 |
#: inc/class-page-backwpup.php:132
|
2745 |
+
msgid ""
|
2746 |
+
"An error has occurred, which probably means the feed is down. Try again "
|
2747 |
+
"later."
|
2748 |
msgstr ""
|
2749 |
|
2750 |
#: inc/class-page-backwpup.php:146
|
2787 |
|
2788 |
#: inc/class-page-backwpup.php:257
|
2789 |
msgctxt "Pro teaser box"
|
2790 |
+
msgid "First-class <strong>dedicated support</strong> at backwpup.com."
|
2791 |
msgstr ""
|
2792 |
|
2793 |
#: inc/class-page-backwpup.php:258
|
2802 |
|
2803 |
#: inc/class-page-backwpup.php:260
|
2804 |
msgctxt "Pro teaser box, link text"
|
2805 |
+
msgid "And more…"
|
2806 |
msgstr ""
|
2807 |
|
2808 |
#: inc/class-page-backwpup.php:262
|
2825 |
msgstr ""
|
2826 |
|
2827 |
#: inc/class-page-backwpup.php:307
|
|
|
2828 |
msgid "working since %d seconds"
|
2829 |
msgstr ""
|
2830 |
|
2844 |
msgid "Result"
|
2845 |
msgstr ""
|
2846 |
|
2847 |
+
#: inc/class-page-backwpup.php:366
|
2848 |
+
msgid "Could not open log folder: %s"
|
2849 |
+
msgstr ""
|
2850 |
+
|
2851 |
+
#: inc/class-page-backwpup.php:389
|
2852 |
msgid "%d ERROR"
|
2853 |
msgid_plural "%d ERRORS"
|
2854 |
msgstr[0] ""
|
2855 |
msgstr[1] ""
|
2856 |
|
2857 |
+
#: inc/class-page-backwpup.php:392
|
|
|
2858 |
msgid "%d WARNING"
|
2859 |
msgid_plural "%d WARNINGS"
|
2860 |
msgstr[0] ""
|
2861 |
msgstr[1] ""
|
2862 |
|
2863 |
+
#: inc/class-page-backwpup.php:395
|
2864 |
msgid "OK"
|
2865 |
msgstr ""
|
2866 |
|
2867 |
#: inc/class-page-editjob.php:98
|
|
|
2868 |
msgid "Job with ID %d"
|
2869 |
msgstr ""
|
2870 |
|
2871 |
#: inc/class-page-editjob.php:222
|
|
|
2872 |
msgid "Changes for job <i>%s</i> saved."
|
2873 |
msgstr ""
|
2874 |
|
2880 |
msgid "Run now"
|
2881 |
msgstr ""
|
2882 |
|
2883 |
+
#: inc/class-page-editjob.php:325
|
|
|
2884 |
msgid "%1$s › Job: %2$s"
|
2885 |
msgstr ""
|
2886 |
|
2887 |
+
#: inc/class-page-editjob.php:328 inc/class-page-settings.php:117
|
2888 |
msgid "General"
|
2889 |
msgstr ""
|
2890 |
|
2891 |
+
#: inc/class-page-editjob.php:328
|
2892 |
msgid "Schedule"
|
2893 |
msgstr ""
|
2894 |
|
2895 |
+
#: inc/class-page-editjob.php:343
|
|
|
2896 |
msgid "To: %s"
|
2897 |
msgstr ""
|
2898 |
|
2899 |
+
#: inc/class-page-editjob.php:378 inc/class-page-editjob.php:383
|
2900 |
#: inc/class-page-jobs.php:125
|
2901 |
msgid "Job Name"
|
2902 |
msgstr ""
|
2903 |
|
2904 |
+
#: inc/class-page-editjob.php:381
|
2905 |
msgid "Please name this job."
|
2906 |
msgstr ""
|
2907 |
|
2908 |
+
#: inc/class-page-editjob.php:388
|
2909 |
msgid "Job Tasks"
|
2910 |
msgstr ""
|
2911 |
|
2912 |
+
#: inc/class-page-editjob.php:391 inc/pro/class-wizard-job.php:254
|
2913 |
msgid "This job is a …"
|
2914 |
msgstr ""
|
2915 |
|
2916 |
+
#: inc/class-page-editjob.php:394 inc/pro/class-wizard-job.php:257
|
2917 |
msgid "Job tasks"
|
2918 |
msgstr ""
|
2919 |
|
2920 |
+
#: inc/class-page-editjob.php:412
|
2921 |
msgid "Backup File Creation"
|
2922 |
msgstr ""
|
2923 |
|
2924 |
+
#: inc/class-page-editjob.php:417 inc/class-page-editjob.php:420
|
2925 |
#: inc/pro/class-wizard-job.php:402 inc/pro/class-wizard-job.php:405
|
2926 |
msgid "Backup type"
|
2927 |
msgstr ""
|
2928 |
|
2929 |
+
#: inc/class-page-editjob.php:423
|
2930 |
msgid "Synchronize file by file to destination"
|
2931 |
msgstr ""
|
2932 |
|
2933 |
+
#: inc/class-page-editjob.php:428 inc/pro/class-wizard-job.php:413
|
2934 |
msgid "Create a backup archive"
|
2935 |
msgstr ""
|
2936 |
|
2937 |
+
#: inc/class-page-editjob.php:436
|
2938 |
msgid "Archive name"
|
2939 |
msgstr ""
|
2940 |
|
2941 |
+
#: inc/class-page-editjob.php:439
|
2942 |
+
msgid ""
|
2943 |
+
"<em>Note</em>: In order for backup file tracking to work, the archive name "
|
2944 |
+
"must begin with %s."
|
2945 |
+
msgstr ""
|
2946 |
+
|
2947 |
+
#: inc/class-page-editjob.php:447
|
2948 |
msgid "Replacement patterns:"
|
2949 |
msgstr ""
|
2950 |
|
2951 |
+
#: inc/class-page-editjob.php:448
|
|
|
2952 |
msgid "%d = Two digit day of the month, with leading zeros"
|
2953 |
msgstr ""
|
2954 |
|
2955 |
+
#: inc/class-page-editjob.php:449
|
2956 |
msgid "%j = Day of the month, without leading zeros"
|
2957 |
msgstr ""
|
2958 |
|
2959 |
+
#: inc/class-page-editjob.php:450
|
2960 |
msgid "%m = Day of the month, with leading zeros"
|
2961 |
msgstr ""
|
2962 |
|
2963 |
+
#: inc/class-page-editjob.php:451
|
2964 |
msgid "%n = Representation of the month (without leading zeros)"
|
2965 |
msgstr ""
|
2966 |
|
2967 |
+
#: inc/class-page-editjob.php:452
|
2968 |
msgid "%Y = Four digit representation for the year"
|
2969 |
msgstr ""
|
2970 |
|
2971 |
+
#: inc/class-page-editjob.php:453
|
2972 |
msgid "%y = Two digit representation of the year"
|
2973 |
msgstr ""
|
2974 |
|
2975 |
+
#: inc/class-page-editjob.php:454
|
2976 |
msgid "%a = Lowercase ante meridiem (am) and post meridiem (pm)"
|
2977 |
msgstr ""
|
2978 |
|
2979 |
+
#: inc/class-page-editjob.php:455
|
2980 |
msgid "%A = Uppercase ante meridiem (AM) and post meridiem (PM)"
|
2981 |
msgstr ""
|
2982 |
|
2983 |
+
#: inc/class-page-editjob.php:456
|
2984 |
msgid "%B = Swatch Internet Time"
|
2985 |
msgstr ""
|
2986 |
|
2987 |
+
#: inc/class-page-editjob.php:457
|
2988 |
msgid "%g = Hour in 12-hour format, without leading zeros"
|
2989 |
msgstr ""
|
2990 |
|
2991 |
+
#: inc/class-page-editjob.php:458
|
2992 |
msgid "%G = Hour in 24-hour format, without leading zeros"
|
2993 |
msgstr ""
|
2994 |
|
2995 |
+
#: inc/class-page-editjob.php:459
|
2996 |
msgid "%h = Hour in 12-hour format, with leading zeros"
|
2997 |
msgstr ""
|
2998 |
|
2999 |
+
#: inc/class-page-editjob.php:460
|
3000 |
msgid "%H = Hour in 24-hour format, with leading zeros"
|
3001 |
msgstr ""
|
3002 |
|
3003 |
+
#: inc/class-page-editjob.php:461
|
3004 |
msgid "%i = Two digit representation of the minute"
|
3005 |
msgstr ""
|
3006 |
|
3007 |
+
#: inc/class-page-editjob.php:462
|
|
|
3008 |
msgid "%s = Two digit representation of the second"
|
3009 |
msgstr ""
|
3010 |
|
3011 |
+
#: inc/class-page-editjob.php:468 inc/class-page-editjob.php:471
|
3012 |
msgid "Archive Format"
|
3013 |
msgstr ""
|
3014 |
|
3015 |
+
#: inc/class-page-editjob.php:474 inc/class-page-editjob.php:476
|
3016 |
#: inc/pro/class-wizard-job.php:426 inc/pro/class-wizard-job.php:429
|
3017 |
msgid "Zip"
|
3018 |
msgstr ""
|
3019 |
|
3020 |
+
#: inc/class-page-editjob.php:477
|
|
|
3021 |
msgid "Disabled due to missing %s PHP class."
|
3022 |
msgstr ""
|
3023 |
|
3024 |
+
#: inc/class-page-editjob.php:479 inc/pro/class-wizard-job.php:433
|
3025 |
msgid "Tar"
|
3026 |
msgstr ""
|
3027 |
|
3028 |
+
#: inc/class-page-editjob.php:481 inc/class-page-editjob.php:483
|
3029 |
#: inc/pro/class-wizard-job.php:437 inc/pro/class-wizard-job.php:440
|
3030 |
msgid "Tar GZip"
|
3031 |
msgstr ""
|
3032 |
|
3033 |
+
#: inc/class-page-editjob.php:484 inc/class-page-editjob.php:490
|
|
|
3034 |
msgid "Disabled due to missing %s PHP function."
|
3035 |
msgstr ""
|
3036 |
|
3037 |
+
#: inc/class-page-editjob.php:487 inc/class-page-editjob.php:489
|
3038 |
#: inc/pro/class-wizard-job.php:444 inc/pro/class-wizard-job.php:447
|
3039 |
msgid "Tar BZip2"
|
3040 |
msgstr ""
|
3041 |
|
3042 |
+
#: inc/class-page-editjob.php:497
|
3043 |
msgid "Job Destination"
|
3044 |
msgstr ""
|
3045 |
|
3046 |
+
#: inc/class-page-editjob.php:501 inc/class-page-editjob.php:504
|
3047 |
msgid "Where should your backup file be stored?"
|
3048 |
msgstr ""
|
3049 |
|
3050 |
+
#: inc/class-page-editjob.php:522
|
3051 |
msgid "Log Files"
|
3052 |
msgstr ""
|
3053 |
|
3054 |
+
#: inc/class-page-editjob.php:526
|
3055 |
msgid "Send log to email address"
|
3056 |
msgstr ""
|
3057 |
|
3058 |
+
#: inc/class-page-editjob.php:529
|
3059 |
+
msgid ""
|
3060 |
+
"Leave empty to not have log sent. Or separate with , for more than one "
|
3061 |
+
"receiver."
|
3062 |
msgstr ""
|
3063 |
|
3064 |
+
#: inc/class-page-editjob.php:533
|
3065 |
msgid "Email FROM field"
|
3066 |
msgstr ""
|
3067 |
|
3068 |
+
#: inc/class-page-editjob.php:535
|
3069 |
msgid "Your Name <mail@domain.tld>"
|
3070 |
msgstr ""
|
3071 |
|
3072 |
+
#: inc/class-page-editjob.php:539
|
3073 |
msgid "Errors only"
|
3074 |
msgstr ""
|
3075 |
|
3076 |
+
#: inc/class-page-editjob.php:544
|
3077 |
msgid "Send email with log only when errors occur during job execution."
|
3078 |
msgstr ""
|
3079 |
|
3080 |
+
#: inc/class-page-editjob.php:555
|
3081 |
msgid "Job Schedule"
|
3082 |
msgstr ""
|
3083 |
|
3084 |
+
#: inc/class-page-editjob.php:559 inc/class-page-editjob.php:562
|
3085 |
msgid "Start job"
|
3086 |
msgstr ""
|
3087 |
|
3088 |
+
#: inc/class-page-editjob.php:566
|
3089 |
msgid "manually only"
|
3090 |
msgstr ""
|
3091 |
|
3092 |
+
#: inc/class-page-editjob.php:570
|
3093 |
msgid "with WordPress cron"
|
3094 |
msgstr ""
|
3095 |
|
3096 |
+
#: inc/class-page-editjob.php:579
|
3097 |
+
msgid ""
|
3098 |
+
"with <a href=\"https://www.easycron.com?ref=36673\" title=\"Affiliate Link!"
|
3099 |
+
"\">EasyCron.com</a>"
|
3100 |
msgstr ""
|
3101 |
|
3102 |
+
#: inc/class-page-editjob.php:581
|
|
|
3103 |
msgid "First setup <a href=\"%s\">API Key</a>."
|
3104 |
msgstr ""
|
3105 |
|
3106 |
+
#: inc/class-page-editjob.php:590
|
3107 |
msgid "with a link"
|
3108 |
msgstr ""
|
3109 |
|
3110 |
+
#: inc/class-page-editjob.php:591
|
3111 |
+
msgid ""
|
3112 |
+
"Copy the link for an external start. This option has to be activated to make "
|
3113 |
+
"the link work."
|
3114 |
msgstr ""
|
3115 |
|
3116 |
+
#: inc/class-page-editjob.php:598
|
3117 |
msgid "Start job with CLI"
|
3118 |
msgstr ""
|
3119 |
|
3120 |
+
#: inc/class-page-editjob.php:601
|
3121 |
+
msgid ""
|
3122 |
+
"Use <a href=\"http://wp-cli.org/\">WP-CLI</a> to run jobs from commandline."
|
3123 |
msgstr ""
|
3124 |
|
3125 |
+
#: inc/class-page-editjob.php:606
|
3126 |
msgid "Schedule execution time"
|
3127 |
msgstr ""
|
3128 |
|
3129 |
+
#: inc/class-page-editjob.php:610 inc/class-page-editjob.php:613
|
3130 |
msgid "Scheduler type"
|
3131 |
msgstr ""
|
3132 |
|
3133 |
+
#: inc/class-page-editjob.php:617
|
3134 |
msgid "basic"
|
3135 |
msgstr ""
|
3136 |
|
3137 |
+
#: inc/class-page-editjob.php:621
|
3138 |
msgid "advanced"
|
3139 |
msgstr ""
|
3140 |
|
3141 |
+
#: inc/class-page-editjob.php:650 inc/class-page-editjob.php:718
|
3142 |
#: inc/pro/class-wizard-job.php:320
|
3143 |
msgid "Scheduler"
|
3144 |
msgstr ""
|
3145 |
|
3146 |
+
#: inc/class-page-editjob.php:655 inc/class-page-jobs.php:126
|
3147 |
#: inc/class-page-logs.php:139 inc/pro/class-wizard-job.php:324
|
3148 |
msgid "Type"
|
3149 |
msgstr ""
|
3150 |
|
3151 |
+
#: inc/class-page-editjob.php:660 inc/pro/class-wizard-job.php:330
|
3152 |
msgid "Hour"
|
3153 |
msgstr ""
|
3154 |
|
3155 |
+
#: inc/class-page-editjob.php:663 inc/pro/class-wizard-job.php:333
|
3156 |
msgid "Minute"
|
3157 |
msgstr ""
|
3158 |
|
3159 |
+
#: inc/class-page-editjob.php:667 inc/pro/class-wizard-job.php:337
|
3160 |
msgid "monthly"
|
3161 |
msgstr ""
|
3162 |
|
3163 |
+
#: inc/class-page-editjob.php:669 inc/pro/class-wizard-job.php:339
|
3164 |
msgid "on"
|
3165 |
msgstr ""
|
3166 |
|
3167 |
+
#: inc/class-page-editjob.php:679 inc/pro/class-wizard-job.php:349
|
3168 |
msgid "weekly"
|
3169 |
msgstr ""
|
3170 |
|
3171 |
+
#: inc/class-page-editjob.php:681 inc/class-page-editjob.php:788
|
3172 |
#: inc/pro/class-wizard-job.php:351
|
3173 |
msgid "Sunday"
|
3174 |
msgstr ""
|
3175 |
|
3176 |
+
#: inc/class-page-editjob.php:682 inc/class-page-editjob.php:789
|
3177 |
#: inc/pro/class-wizard-job.php:352
|
3178 |
msgid "Monday"
|
3179 |
msgstr ""
|
3180 |
|
3181 |
+
#: inc/class-page-editjob.php:683 inc/class-page-editjob.php:790
|
3182 |
#: inc/pro/class-wizard-job.php:353
|
3183 |
msgid "Tuesday"
|
3184 |
msgstr ""
|
3185 |
|
3186 |
+
#: inc/class-page-editjob.php:684 inc/class-page-editjob.php:791
|
3187 |
#: inc/pro/class-wizard-job.php:354
|
3188 |
msgid "Wednesday"
|
3189 |
msgstr ""
|
3190 |
|
3191 |
+
#: inc/class-page-editjob.php:685 inc/class-page-editjob.php:792
|
3192 |
#: inc/pro/class-wizard-job.php:355
|
3193 |
msgid "Thursday"
|
3194 |
msgstr ""
|
3195 |
|
3196 |
+
#: inc/class-page-editjob.php:686 inc/class-page-editjob.php:793
|
3197 |
#: inc/pro/class-wizard-job.php:356
|
3198 |
msgid "Friday"
|
3199 |
msgstr ""
|
3200 |
|
3201 |
+
#: inc/class-page-editjob.php:687 inc/class-page-editjob.php:794
|
3202 |
#: inc/pro/class-wizard-job.php:357
|
3203 |
msgid "Saturday"
|
3204 |
msgstr ""
|
3205 |
|
3206 |
+
#: inc/class-page-editjob.php:697 inc/pro/class-wizard-job.php:367
|
3207 |
msgid "daily"
|
3208 |
msgstr ""
|
3209 |
|
3210 |
+
#: inc/class-page-editjob.php:707 inc/pro/class-wizard-job.php:377
|
3211 |
msgid "hourly"
|
3212 |
msgstr ""
|
3213 |
|
3214 |
+
#: inc/class-page-editjob.php:721
|
3215 |
msgid "Minutes:"
|
3216 |
msgstr ""
|
3217 |
|
3218 |
+
#: inc/class-page-editjob.php:723 inc/class-page-editjob.php:736
|
3219 |
+
#: inc/class-page-editjob.php:748 inc/class-page-editjob.php:762
|
3220 |
+
#: inc/class-page-editjob.php:784
|
3221 |
msgid "Any (*)"
|
3222 |
msgstr ""
|
3223 |
|
3224 |
+
#: inc/class-page-editjob.php:733
|
3225 |
msgid "Hours:"
|
3226 |
msgstr ""
|
3227 |
|
3228 |
+
#: inc/class-page-editjob.php:746
|
3229 |
msgid "Day of Month:"
|
3230 |
msgstr ""
|
3231 |
|
3232 |
+
#: inc/class-page-editjob.php:760
|
3233 |
msgid "Month:"
|
3234 |
msgstr ""
|
3235 |
|
3236 |
+
#: inc/class-page-editjob.php:766
|
3237 |
msgid "January"
|
3238 |
msgstr ""
|
3239 |
|
3240 |
+
#: inc/class-page-editjob.php:767
|
3241 |
msgid "February"
|
3242 |
msgstr ""
|
3243 |
|
3244 |
+
#: inc/class-page-editjob.php:768
|
3245 |
msgid "March"
|
3246 |
msgstr ""
|
3247 |
|
3248 |
+
#: inc/class-page-editjob.php:769
|
3249 |
msgid "April"
|
3250 |
msgstr ""
|
3251 |
|
3252 |
+
#: inc/class-page-editjob.php:770
|
3253 |
msgid "May"
|
3254 |
msgstr ""
|
3255 |
|
3256 |
+
#: inc/class-page-editjob.php:771
|
3257 |
msgid "June"
|
3258 |
msgstr ""
|
3259 |
|
3260 |
+
#: inc/class-page-editjob.php:772
|
3261 |
msgid "July"
|
3262 |
msgstr ""
|
3263 |
|
3264 |
+
#: inc/class-page-editjob.php:773
|
3265 |
msgid "August"
|
3266 |
msgstr ""
|
3267 |
|
3268 |
+
#: inc/class-page-editjob.php:774
|
3269 |
msgid "September"
|
3270 |
msgstr ""
|
3271 |
|
3272 |
+
#: inc/class-page-editjob.php:775
|
3273 |
msgid "October"
|
3274 |
msgstr ""
|
3275 |
|
3276 |
+
#: inc/class-page-editjob.php:776
|
3277 |
msgid "November"
|
3278 |
msgstr ""
|
3279 |
|
3280 |
+
#: inc/class-page-editjob.php:777
|
3281 |
msgid "December"
|
3282 |
msgstr ""
|
3283 |
|
3284 |
+
#: inc/class-page-editjob.php:782
|
3285 |
msgid "Day of Week:"
|
3286 |
msgstr ""
|
3287 |
|
3288 |
+
#: inc/class-page-editjob.php:818
|
3289 |
msgid "Save changes"
|
3290 |
msgstr ""
|
3291 |
|
3292 |
+
#: inc/class-page-editjob.php:905
|
3293 |
+
msgid ""
|
3294 |
+
"Working as <a href=\"http://wikipedia.org/wiki/Cron\">Cron</a> schedule:"
|
3295 |
msgstr ""
|
3296 |
|
3297 |
+
#: inc/class-page-editjob.php:914
|
|
|
3298 |
msgid "ATTENTION: Job runs every %d minutes!"
|
3299 |
msgstr ""
|
3300 |
|
3301 |
+
#: inc/class-page-editjob.php:918
|
3302 |
msgid "ATTENTION: Can't calculate cron!"
|
3303 |
msgstr ""
|
3304 |
|
3305 |
+
#: inc/class-page-editjob.php:921
|
3306 |
msgid "Next runtime:"
|
3307 |
msgstr ""
|
3308 |
|
3324 |
msgstr ""
|
3325 |
|
3326 |
#: inc/class-page-jobs.php:172 inc/class-page-logs.php:200
|
|
|
3327 |
msgid "Job ID: %d"
|
3328 |
msgstr ""
|
3329 |
|
3344 |
msgstr ""
|
3345 |
|
3346 |
#: inc/class-page-jobs.php:273
|
|
|
3347 |
msgid "Running for: %s seconds"
|
3348 |
msgstr ""
|
3349 |
|
3350 |
#: inc/class-page-jobs.php:280 inc/class-page-jobs.php:289
|
|
|
3351 |
msgid "Cron: %s"
|
3352 |
msgstr ""
|
3353 |
|
3354 |
#: inc/class-page-jobs.php:280
|
|
|
3355 |
msgid "%1$s at %2$s by WP-Cron"
|
3356 |
msgstr ""
|
3357 |
|
3358 |
#: inc/class-page-jobs.php:289
|
|
|
3359 |
msgid "%1$s at %2$s by EasyCron"
|
3360 |
msgstr ""
|
3361 |
|
3368 |
msgstr ""
|
3369 |
|
3370 |
#: inc/class-page-jobs.php:320
|
|
|
3371 |
msgid "Runtime: %d seconds"
|
3372 |
msgstr ""
|
3373 |
|
3388 |
msgstr ""
|
3389 |
|
3390 |
#: inc/class-page-jobs.php:431
|
|
|
3391 |
msgid "The job \"%s\" destination \"%s\" is not configured properly"
|
3392 |
msgstr ""
|
3393 |
|
3394 |
#: inc/class-page-jobs.php:436
|
|
|
3395 |
msgid "The job \"%s\" needs properly configured destinations to run!"
|
3396 |
msgstr ""
|
3397 |
|
3398 |
#: inc/class-page-jobs.php:454
|
3399 |
+
msgid ""
|
3400 |
+
"Job \"%s\" has started, but not responded for 10 seconds. Please check <a "
|
3401 |
+
"href=\"%s\">information</a>."
|
3402 |
msgstr ""
|
3403 |
|
3404 |
#: inc/class-page-jobs.php:459
|
|
|
3405 |
msgid "Job \"%s\" started."
|
3406 |
msgstr ""
|
3407 |
|
3410 |
msgstr ""
|
3411 |
|
3412 |
#: inc/class-page-jobs.php:584
|
|
|
3413 |
msgid "%s › Jobs"
|
3414 |
msgstr ""
|
3415 |
|
3416 |
#: inc/class-page-jobs.php:604
|
|
|
3417 |
msgid "Job currently running: %s"
|
3418 |
msgstr ""
|
3419 |
|
3446 |
msgstr ""
|
3447 |
|
3448 |
#: inc/class-page-jobs.php:786
|
3449 |
+
msgid ""
|
3450 |
+
"Job has done with warnings in %s seconds. Please resolve them for correct "
|
3451 |
+
"execution."
|
3452 |
msgstr ""
|
3453 |
|
3454 |
#: inc/class-page-logs.php:113
|
3468 |
msgstr ""
|
3469 |
|
3470 |
#: inc/class-page-logs.php:222
|
|
|
3471 |
msgid "1 ERROR"
|
3472 |
msgid_plural "%d ERRORS"
|
3473 |
msgstr[0] ""
|
3474 |
msgstr[1] ""
|
3475 |
|
3476 |
#: inc/class-page-logs.php:225
|
|
|
3477 |
msgid "1 WARNING"
|
3478 |
msgid_plural "%d WARNINGS"
|
3479 |
msgstr[0] ""
|
3488 |
msgstr ""
|
3489 |
|
3490 |
#: inc/class-page-logs.php:391
|
|
|
3491 |
msgid "%s › Logs"
|
3492 |
msgstr ""
|
3493 |
|
3495 |
msgid "Logfile not found!"
|
3496 |
msgstr ""
|
3497 |
|
3498 |
+
#: inc/class-page-settings.php:61
|
3499 |
msgid "Settings reset to default"
|
3500 |
msgstr ""
|
3501 |
|
3502 |
+
#: inc/class-page-settings.php:104
|
3503 |
msgid "Settings saved"
|
3504 |
msgstr ""
|
3505 |
|
3506 |
+
#: inc/class-page-settings.php:115
|
|
|
3507 |
msgid "%s › Settings"
|
3508 |
msgstr ""
|
3509 |
|
3510 |
+
#: inc/class-page-settings.php:117
|
3511 |
msgid "Network"
|
3512 |
msgstr ""
|
3513 |
|
3514 |
+
#: inc/class-page-settings.php:117
|
3515 |
msgid "API Keys"
|
3516 |
msgstr ""
|
3517 |
|
3518 |
+
#: inc/class-page-settings.php:117
|
3519 |
msgid "Information"
|
3520 |
msgstr ""
|
3521 |
|
3522 |
+
#: inc/class-page-settings.php:135
|
3523 |
msgid "Display Settings"
|
3524 |
msgstr ""
|
3525 |
|
3526 |
+
#: inc/class-page-settings.php:136
|
3527 |
msgid "Do you want to see BackWPup in the WordPress admin bar?"
|
3528 |
msgstr ""
|
3529 |
|
3530 |
+
#: inc/class-page-settings.php:139
|
3531 |
msgid "Admin bar"
|
3532 |
msgstr ""
|
3533 |
|
3534 |
+
#: inc/class-page-settings.php:142
|
3535 |
msgid "Admin Bar"
|
3536 |
msgstr ""
|
3537 |
|
3538 |
+
#: inc/class-page-settings.php:145
|
3539 |
msgid "Show BackWPup links in admin bar."
|
3540 |
msgstr ""
|
3541 |
|
3542 |
+
#: inc/class-page-settings.php:151 inc/class-page-settings.php:154
|
3543 |
msgid "Folder sizes"
|
3544 |
msgstr ""
|
3545 |
|
3546 |
+
#: inc/class-page-settings.php:157
|
3547 |
+
msgid ""
|
3548 |
+
"Display folder sizes in the files tab when editing a job. (Might increase "
|
3549 |
+
"loading time of files tab.)"
|
3550 |
msgstr ""
|
3551 |
|
3552 |
+
#: inc/class-page-settings.php:163
|
3553 |
msgid "Security"
|
3554 |
msgstr ""
|
3555 |
|
3556 |
+
#: inc/class-page-settings.php:164
|
3557 |
msgid "Security option for BackWPup"
|
3558 |
msgstr ""
|
3559 |
|
3560 |
+
#: inc/class-page-settings.php:167 inc/class-page-settings.php:170
|
3561 |
msgid "Protect folders"
|
3562 |
msgstr ""
|
3563 |
|
3564 |
+
#: inc/class-page-settings.php:173
|
3565 |
+
msgid ""
|
3566 |
+
"Protect BackWPup folders ( Temp, Log and Backups ) with <code>.htaccess</"
|
3567 |
+
"code> and <code>index.php</code>"
|
3568 |
msgstr ""
|
3569 |
|
3570 |
+
#: inc/class-page-settings.php:186
|
3571 |
+
msgid ""
|
3572 |
+
"Every time BackWPup runs a backup job, a log file is being generated. Choose "
|
3573 |
+
"where to store your log files and how many of them."
|
3574 |
msgstr ""
|
3575 |
|
3576 |
+
#: inc/class-page-settings.php:189
|
3577 |
msgid "Log file folder"
|
3578 |
msgstr ""
|
3579 |
|
3580 |
+
#: inc/class-page-settings.php:192
|
|
|
3581 |
msgid "You can use absolute or relative path! Relative path is relative to %s."
|
3582 |
msgstr ""
|
3583 |
|
3584 |
+
#: inc/class-page-settings.php:196
|
3585 |
msgid "Maximum log files"
|
3586 |
msgstr ""
|
3587 |
|
3588 |
+
#: inc/class-page-settings.php:199
|
3589 |
msgid "Maximum log files in folder."
|
3590 |
msgstr ""
|
3591 |
|
3592 |
+
#: inc/class-page-settings.php:203 inc/class-page-settings.php:206
|
3593 |
msgid "Compression"
|
3594 |
msgstr ""
|
3595 |
|
3596 |
+
#: inc/class-page-settings.php:209
|
3597 |
msgid "Compress log files with GZip."
|
3598 |
msgstr ""
|
3599 |
|
3600 |
+
#: inc/class-page-settings.php:215 inc/class-page-settings.php:218
|
3601 |
msgid "Logging Level"
|
3602 |
msgstr ""
|
3603 |
|
3604 |
+
#: inc/class-page-settings.php:221
|
3605 |
msgid "Normal (translated)"
|
3606 |
msgstr ""
|
3607 |
|
3608 |
+
#: inc/class-page-settings.php:222
|
3609 |
msgid "Normal (not translated)"
|
3610 |
msgstr ""
|
3611 |
|
3612 |
+
#: inc/class-page-settings.php:223
|
3613 |
msgid "Debug (translated)"
|
3614 |
msgstr ""
|
3615 |
|
3616 |
+
#: inc/class-page-settings.php:224
|
3617 |
msgid "Debug (not translated)"
|
3618 |
msgstr ""
|
3619 |
|
3620 |
+
#: inc/class-page-settings.php:227
|
3621 |
+
msgid ""
|
3622 |
+
"Debug log has much more informations than normal logs. It is for support and "
|
3623 |
+
"should be handled carefully. For support is the best to use a not translated "
|
3624 |
+
"log file. Usage of not translated logs can reduce the PHP memory usage too."
|
3625 |
msgstr ""
|
3626 |
|
3627 |
+
#: inc/class-page-settings.php:236
|
3628 |
msgid "There are a couple of general options for backup jobs. Set them here."
|
3629 |
msgstr ""
|
3630 |
|
3631 |
+
#: inc/class-page-settings.php:239
|
3632 |
msgid "Maximum number of retries for job steps"
|
3633 |
msgstr ""
|
3634 |
|
3635 |
+
#: inc/class-page-settings.php:245
|
3636 |
msgid "Maximum script execution time"
|
3637 |
msgstr ""
|
3638 |
|
3639 |
+
#: inc/class-page-settings.php:248
|
3640 |
msgid "Maximum PHP Script execution time"
|
3641 |
msgstr ""
|
3642 |
|
3643 |
+
#: inc/class-page-settings.php:251
|
3644 |
msgid "seconds."
|
3645 |
msgstr ""
|
3646 |
|
3647 |
+
#: inc/class-page-settings.php:252
|
3648 |
+
msgid ""
|
3649 |
+
"Job will restart before hitting maximum execution time. Restarts will be "
|
3650 |
+
"disabled on CLI usage. If <code>ALTERNATE_WP_CRON</code> has been defined, "
|
3651 |
+
"WordPress Cron will be used for restarts, so it can take a while. 0 means no "
|
3652 |
+
"maximum."
|
3653 |
msgstr ""
|
3654 |
|
3655 |
+
#: inc/class-page-settings.php:259
|
3656 |
msgid "Key to start jobs externally with an URL"
|
3657 |
msgstr ""
|
3658 |
|
3659 |
+
#: inc/class-page-settings.php:263
|
3660 |
msgid "Will be used to protect job starts from unauthorized person."
|
3661 |
msgstr ""
|
3662 |
|
3663 |
+
#: inc/class-page-settings.php:267 inc/class-page-settings.php:270
|
3664 |
msgid "Reduce server load"
|
3665 |
msgstr ""
|
3666 |
|
3667 |
+
#: inc/class-page-settings.php:273
|
3668 |
msgid "disabled"
|
3669 |
msgstr ""
|
3670 |
|
3671 |
+
#: inc/class-page-settings.php:274
|
3672 |
msgid "minimum"
|
3673 |
msgstr ""
|
3674 |
|
3675 |
+
#: inc/class-page-settings.php:275
|
3676 |
msgid "medium"
|
3677 |
msgstr ""
|
3678 |
|
3679 |
+
#: inc/class-page-settings.php:276
|
3680 |
msgid "maximum"
|
3681 |
msgstr ""
|
3682 |
|
3683 |
+
#: inc/class-page-settings.php:279
|
3684 |
+
msgid ""
|
3685 |
+
"This adds short pauses to the process. Can be used to reduce the CPU load."
|
3686 |
msgstr ""
|
3687 |
|
3688 |
+
#: inc/class-page-settings.php:284
|
3689 |
msgid "Empty output on working"
|
3690 |
msgstr ""
|
3691 |
|
3692 |
+
#: inc/class-page-settings.php:287 inc/class-page-settings.php:290
|
3693 |
msgid "Enable an empty Output on backup working."
|
3694 |
msgstr ""
|
3695 |
|
3696 |
+
#: inc/class-page-settings.php:292
|
3697 |
+
msgid ""
|
3698 |
+
"This do an empty output on job working. This can help in some situations or "
|
3699 |
+
"can brake the working. You must test it."
|
3700 |
+
msgstr ""
|
3701 |
+
|
3702 |
+
#: inc/class-page-settings.php:297
|
3703 |
+
msgid "Windows IIS compatibility"
|
3704 |
+
msgstr ""
|
3705 |
+
|
3706 |
+
#: inc/class-page-settings.php:300 inc/class-page-settings.php:303
|
3707 |
+
msgid "Enable compatibility with IIS on Windows."
|
3708 |
+
msgstr ""
|
3709 |
+
|
3710 |
+
#: inc/class-page-settings.php:305
|
3711 |
+
msgid ""
|
3712 |
+
"There is a PHP bug (<a href=\"https://bugs.php.net/43817\">bug #43817</a>), "
|
3713 |
+
"which is triggered on some versions of Windows and IIS. Checking this box "
|
3714 |
+
"will enable a workaround for that bug. Only enable if you are getting errors "
|
3715 |
+
"about “Permission denied” in your logs."
|
3716 |
msgstr ""
|
3717 |
|
3718 |
+
#: inc/class-page-settings.php:315
|
|
|
3719 |
msgid "Authentication for <code>%s</code>"
|
3720 |
msgstr ""
|
3721 |
|
3722 |
+
#: inc/class-page-settings.php:316
|
3723 |
+
msgid ""
|
3724 |
+
"If you protected your blog with HTTP basic authentication (.htaccess), or "
|
3725 |
+
"you use a Plugin to secure wp-cron.php, then use the authentication methods "
|
3726 |
+
"below."
|
3727 |
msgstr ""
|
3728 |
|
3729 |
+
#: inc/class-page-settings.php:322 inc/class-page-settings.php:325
|
3730 |
msgid "Authentication method"
|
3731 |
msgstr ""
|
3732 |
|
3733 |
+
#: inc/class-page-settings.php:329
|
3734 |
msgid "Basic auth"
|
3735 |
msgstr ""
|
3736 |
|
3737 |
+
#: inc/class-page-settings.php:330
|
3738 |
msgid "WordPress User"
|
3739 |
msgstr ""
|
3740 |
|
3741 |
+
#: inc/class-page-settings.php:331
|
3742 |
msgid "Query argument"
|
3743 |
msgstr ""
|
3744 |
|
3745 |
+
#: inc/class-page-settings.php:338
|
3746 |
msgid "Basic Auth Username:"
|
3747 |
msgstr ""
|
3748 |
|
3749 |
+
#: inc/class-page-settings.php:344
|
3750 |
msgid "Basic Auth Password:"
|
3751 |
msgstr ""
|
3752 |
|
3753 |
+
#: inc/class-page-settings.php:349 inc/class-page-settings.php:352
|
3754 |
msgid "Select WordPress User"
|
3755 |
msgstr ""
|
3756 |
|
3757 |
+
#: inc/class-page-settings.php:368
|
3758 |
msgid "Query arg key=value:"
|
3759 |
msgstr ""
|
3760 |
|
3761 |
+
#: inc/class-page-settings.php:387 inc/class-page-settings.php:388
|
3762 |
msgid "Setting"
|
3763 |
msgstr ""
|
3764 |
|
3765 |
+
#: inc/class-page-settings.php:387 inc/class-page-settings.php:388
|
3766 |
msgid "Value"
|
3767 |
msgstr ""
|
3768 |
|
3769 |
+
#: inc/class-page-settings.php:389
|
3770 |
msgid "WordPress version"
|
3771 |
msgstr ""
|
3772 |
|
3773 |
+
#: inc/class-page-settings.php:391
|
3774 |
msgid "BackWPup version"
|
3775 |
msgstr ""
|
3776 |
|
3777 |
+
#: inc/class-page-settings.php:391
|
3778 |
msgid "Get pro."
|
3779 |
msgstr ""
|
3780 |
|
3781 |
+
#: inc/class-page-settings.php:393
|
3782 |
msgid "BackWPup Pro version"
|
3783 |
msgstr ""
|
3784 |
|
3785 |
+
#: inc/class-page-settings.php:401
|
3786 |
msgid "PHP version"
|
3787 |
msgstr ""
|
3788 |
|
3789 |
+
#: inc/class-page-settings.php:402
|
3790 |
msgid "MySQL version"
|
3791 |
msgstr ""
|
3792 |
|
3793 |
+
#: inc/class-page-settings.php:405 inc/class-page-settings.php:409
|
3794 |
msgid "cURL version"
|
3795 |
msgstr ""
|
3796 |
|
3797 |
+
#: inc/class-page-settings.php:406
|
3798 |
msgid "cURL SSL version"
|
3799 |
msgstr ""
|
3800 |
|
3801 |
+
#: inc/class-page-settings.php:409
|
3802 |
msgid "unavailable"
|
3803 |
msgstr ""
|
3804 |
|
3805 |
+
#: inc/class-page-settings.php:411
|
3806 |
msgid "WP-Cron url:"
|
3807 |
msgstr ""
|
3808 |
|
3809 |
+
#: inc/class-page-settings.php:413
|
3810 |
msgid "Server self connect:"
|
3811 |
msgstr ""
|
3812 |
|
3813 |
+
#: inc/class-page-settings.php:418
|
3814 |
msgid "<strong>Not expected HTTP response:</strong><br>"
|
3815 |
msgstr ""
|
3816 |
|
3817 |
+
#: inc/class-page-settings.php:420
|
|
|
3818 |
msgid "WP Http Error: <code>%s</code>"
|
3819 |
msgstr ""
|
3820 |
|
3821 |
+
#: inc/class-page-settings.php:422
|
|
|
3822 |
msgid "Status-Code: <code>%d</code>"
|
3823 |
msgstr ""
|
3824 |
|
3825 |
+
#: inc/class-page-settings.php:430
|
|
|
3826 |
msgid "Content: <code>%s</code>"
|
3827 |
msgstr ""
|
3828 |
|
3829 |
+
#: inc/class-page-settings.php:434
|
3830 |
msgid "Response Test O.K."
|
3831 |
msgstr ""
|
3832 |
|
3833 |
+
#: inc/class-page-settings.php:438
|
3834 |
msgid "Temp folder:"
|
3835 |
msgstr ""
|
3836 |
|
3837 |
+
#: inc/class-page-settings.php:440
|
|
|
3838 |
msgid "Temp folder %s doesn't exist."
|
3839 |
msgstr ""
|
3840 |
|
3841 |
+
#: inc/class-page-settings.php:442
|
|
|
3842 |
msgid "Temporary folder %s is not writable."
|
3843 |
msgstr ""
|
3844 |
|
3845 |
+
#: inc/class-page-settings.php:449
|
3846 |
msgid "Log folder:"
|
3847 |
msgstr ""
|
3848 |
|
3849 |
+
#: inc/class-page-settings.php:451
|
|
|
3850 |
msgid "Logs folder %s not exist."
|
3851 |
msgstr ""
|
3852 |
|
3853 |
+
#: inc/class-page-settings.php:453
|
|
|
3854 |
msgid "Log folder %s is not writable."
|
3855 |
msgstr ""
|
3856 |
|
3857 |
+
#: inc/class-page-settings.php:458
|
3858 |
msgid "Server"
|
3859 |
msgstr ""
|
3860 |
|
3861 |
+
#: inc/class-page-settings.php:459
|
3862 |
msgid "Operating System"
|
3863 |
msgstr ""
|
3864 |
|
3865 |
+
#: inc/class-page-settings.php:460
|
3866 |
msgid "PHP SAPI"
|
3867 |
msgstr ""
|
3868 |
|
3869 |
+
#: inc/class-page-settings.php:461
|
3870 |
msgid "Function Disabled"
|
3871 |
msgstr ""
|
3872 |
|
3873 |
+
#: inc/class-page-settings.php:465
|
3874 |
msgid "Current PHP user"
|
3875 |
msgstr ""
|
3876 |
|
3877 |
+
#: inc/class-page-settings.php:466
|
3878 |
msgid "Maximum execution time"
|
3879 |
msgstr ""
|
3880 |
|
3881 |
+
#: inc/class-page-settings.php:468 inc/class-page-settings.php:470
|
3882 |
msgid "Alternative WP Cron"
|
3883 |
msgstr ""
|
3884 |
|
3885 |
+
#: inc/class-page-settings.php:468 inc/class-page-settings.php:472
|
3886 |
msgid "On"
|
3887 |
msgstr ""
|
3888 |
|
3889 |
+
#: inc/class-page-settings.php:470 inc/class-page-settings.php:474
|
3890 |
msgid "Off"
|
3891 |
msgstr ""
|
3892 |
|
3893 |
+
#: inc/class-page-settings.php:472 inc/class-page-settings.php:474
|
3894 |
msgid "Disabled WP Cron"
|
3895 |
msgstr ""
|
3896 |
|
3897 |
+
#: inc/class-page-settings.php:476 inc/class-page-settings.php:478
|
3898 |
msgid "CHMOD Dir"
|
3899 |
msgstr ""
|
3900 |
|
3901 |
+
#: inc/class-page-settings.php:480
|
3902 |
msgid "Server Time"
|
3903 |
msgstr ""
|
3904 |
|
3905 |
+
#: inc/class-page-settings.php:481
|
3906 |
msgid "Blog Time"
|
3907 |
msgstr ""
|
3908 |
|
3909 |
+
#: inc/class-page-settings.php:482
|
3910 |
msgid "Blog Timezone"
|
3911 |
msgstr ""
|
3912 |
|
3913 |
+
#: inc/class-page-settings.php:483
|
3914 |
msgid "Blog Time offset"
|
3915 |
msgstr ""
|
3916 |
|
3917 |
+
#: inc/class-page-settings.php:483
|
|
|
3918 |
msgid "%s hours"
|
3919 |
msgstr ""
|
3920 |
|
3921 |
+
#: inc/class-page-settings.php:484
|
3922 |
msgid "Blog language"
|
3923 |
msgstr ""
|
3924 |
|
3925 |
+
#: inc/class-page-settings.php:485
|
3926 |
msgid "MySQL Client encoding"
|
3927 |
msgstr ""
|
3928 |
|
3929 |
+
#: inc/class-page-settings.php:488
|
3930 |
msgid "Blog charset"
|
3931 |
msgstr ""
|
3932 |
|
3933 |
+
#: inc/class-page-settings.php:489
|
3934 |
msgid "PHP Memory limit"
|
3935 |
msgstr ""
|
3936 |
|
3937 |
+
#: inc/class-page-settings.php:490
|
3938 |
msgid "WP memory limit"
|
3939 |
msgstr ""
|
3940 |
|
3941 |
+
#: inc/class-page-settings.php:491
|
3942 |
msgid "WP maximum memory limit"
|
3943 |
msgstr ""
|
3944 |
|
3945 |
+
#: inc/class-page-settings.php:492
|
3946 |
msgid "Memory in use"
|
3947 |
msgstr ""
|
3948 |
|
3949 |
+
#: inc/class-page-settings.php:497
|
3950 |
msgid "Disabled PHP Functions:"
|
3951 |
msgstr ""
|
3952 |
|
3953 |
+
#: inc/class-page-settings.php:502
|
3954 |
msgid "Loaded PHP Extensions:"
|
3955 |
msgstr ""
|
3956 |
|
3957 |
+
#: inc/class-page-settings.php:514
|
3958 |
msgid "Save Changes"
|
3959 |
msgstr ""
|
3960 |
|
3961 |
+
#: inc/class-page-settings.php:516
|
3962 |
msgid "Reset all settings to default"
|
3963 |
msgstr ""
|
3964 |
|
3965 |
#: inc/class-php-admin-notice.php:123
|
3966 |
+
msgid ""
|
3967 |
+
"With the upcoming major release, BackWPup will be requiring PHP version 5.3 "
|
3968 |
+
"or higher."
|
3969 |
msgstr ""
|
3970 |
|
3971 |
#: inc/class-php-admin-notice.php:125
|
3981 |
msgstr ""
|
3982 |
|
3983 |
#: inc/class-php-admin-notice.php:164
|
3984 |
+
msgid ""
|
3985 |
+
"BackWPup has determined, your installation is still running on the old PHP "
|
3986 |
+
"5.2 version."
|
3987 |
msgstr ""
|
3988 |
|
3989 |
#: inc/class-php-admin-notice.php:167
|
3990 |
+
msgid ""
|
3991 |
+
"In order to ensure a fast and secure development for BackWPup, we will most "
|
3992 |
+
"likely not support PHP version 5.2 in our next version."
|
3993 |
msgstr ""
|
3994 |
|
3995 |
#: inc/class-php-admin-notice.php:168
|
3996 |
+
msgid ""
|
3997 |
+
"No need to worry, your host can update your PHP version relatively quickly "
|
3998 |
+
"and without any problems."
|
3999 |
msgstr ""
|
4000 |
|
4001 |
#: inc/class-php-admin-notice.php:169
|
4002 |
+
msgid ""
|
4003 |
+
"Otherwise you can continue to stay on this last version and do not update "
|
4004 |
+
"the plugin in the future!"
|
4005 |
msgstr ""
|
4006 |
|
4007 |
#: inc/class-php-admin-notice.php:173
|
4008 |
+
msgid ""
|
4009 |
+
"If the response from PHP 5.2 users is surprisingly high, we will eventually "
|
4010 |
+
"keep support for PHP 5.2 for a while."
|
4011 |
msgstr ""
|
4012 |
|
4013 |
#: inc/class-php-admin-notice.php:176
|
4018 |
msgid "Your BackWPup Team!"
|
4019 |
msgstr ""
|
4020 |
|
4021 |
+
#. Translators: This is the anchor text for an HTML link pointing to BackWPup
|
4022 |
+
#. contact page
|
4023 |
#: inc/class-php-admin-notice.php:205
|
4024 |
msgid "contact us"
|
4025 |
msgstr ""
|
4026 |
|
4027 |
+
#. Translators: %s is replaced by an HTML link with text "contact us" pointing
|
4028 |
+
#. to BackWPup contact page
|
4029 |
#: inc/class-php-admin-notice.php:207
|
|
|
4030 |
msgid "If you would like to have PHP 5.2 supported, please %s."
|
4031 |
msgstr ""
|
4032 |
|
4054 |
msgid "No job running"
|
4055 |
msgstr ""
|
4056 |
|
4057 |
+
#: inc/pro/class-destination-dropbox.php:23
|
4058 |
msgid "Auth Code:"
|
4059 |
msgstr ""
|
4060 |
|
4061 |
+
#: inc/pro/class-destination-dropbox.php:26
|
4062 |
msgid "Get auth code"
|
4063 |
msgstr ""
|
4064 |
|
4065 |
+
#: inc/pro/class-destination-dropbox.php:33
|
4066 |
+
#: inc/pro/class-destination-gdrive.php:294
|
4067 |
+
#: inc/pro/class-destination-gdrive.php:299
|
4068 |
#: inc/pro/class-destination-sugarsync.php:30
|
4069 |
msgid "Login:"
|
4070 |
msgstr ""
|
4071 |
|
4072 |
+
#: inc/pro/class-destination-dropbox.php:37
|
4073 |
+
#: inc/pro/class-destination-gdrive.php:306
|
4074 |
#: inc/pro/class-destination-sugarsync.php:56
|
4075 |
msgid "Folder:"
|
4076 |
msgstr ""
|
4077 |
|
4078 |
+
#: inc/pro/class-destination-dropbox.php:112
|
|
|
4079 |
msgid "%d. Try to sync files to Dropbox …"
|
4080 |
msgstr ""
|
4081 |
|
4082 |
+
#: inc/pro/class-destination-dropbox.php:147
|
4083 |
msgid "Retrieving file list from Dropbox"
|
4084 |
msgstr ""
|
4085 |
|
4086 |
+
#: inc/pro/class-destination-dropbox.php:161
|
4087 |
msgid "Upload changed files to Dropbox"
|
4088 |
msgstr ""
|
4089 |
|
4090 |
+
#: inc/pro/class-destination-dropbox.php:183
|
|
|
4091 |
msgid "File %s uploaded to Dropbox"
|
4092 |
msgstr ""
|
4093 |
|
4094 |
+
#: inc/pro/class-destination-dropbox.php:211
|
|
|
4095 |
msgid "Extra file %s uploaded to Dropbox"
|
4096 |
msgstr ""
|
4097 |
|
4098 |
+
#: inc/pro/class-destination-dropbox.php:226
|
|
|
|
|
|
|
|
|
|
|
4099 |
msgid "Folder %s deleted from Dropbox"
|
4100 |
msgstr ""
|
4101 |
|
4102 |
+
#: inc/pro/class-destination-dropbox.php:243
|
|
|
4103 |
msgid "File %s deleted from Dropbox"
|
4104 |
msgstr ""
|
4105 |
|
4108 |
msgstr ""
|
4109 |
|
4110 |
#: inc/pro/class-destination-folder.php:41
|
4111 |
+
#: inc/pro/class-destination-gdrive.php:321
|
4112 |
msgid "Oldest files will be deleted first."
|
4113 |
msgstr ""
|
4114 |
|
4115 |
#: inc/pro/class-destination-folder.php:87
|
|
|
4116 |
msgid "%d. Try to sync files to folder …"
|
4117 |
msgstr ""
|
4118 |
|
4120 |
msgid "Retrieving file list from folder"
|
4121 |
msgstr ""
|
4122 |
|
4123 |
+
#: inc/pro/class-destination-folder.php:101
|
4124 |
msgid "Copy changed files to folder"
|
4125 |
msgstr ""
|
4126 |
|
4127 |
+
#: inc/pro/class-destination-folder.php:115
|
|
|
4128 |
msgid "File %s copied"
|
4129 |
msgstr ""
|
4130 |
|
4131 |
+
#: inc/pro/class-destination-folder.php:128
|
4132 |
msgid "Delete not existing files from folder"
|
4133 |
msgstr ""
|
4134 |
|
4135 |
+
#: inc/pro/class-destination-folder.php:136
|
|
|
4136 |
msgid "Extra file %s copied"
|
4137 |
msgstr ""
|
4138 |
|
4139 |
+
#: inc/pro/class-destination-folder.php:152
|
|
|
4140 |
msgid "File %s deleted from folder"
|
4141 |
msgstr ""
|
4142 |
|
4143 |
+
#: inc/pro/class-destination-folder.php:210
|
|
|
4144 |
msgid "Empty folder %s deleted"
|
4145 |
msgstr ""
|
4146 |
|
4162 |
msgstr ""
|
4163 |
|
4164 |
#: inc/pro/class-destination-gdrive.php:41
|
4165 |
+
#: inc/pro/class-destination-gdrive.php:282
|
4166 |
+
msgid ""
|
4167 |
+
"Looks like you haven’t set up any API keys yet. Head over to <a href=\"%s"
|
4168 |
+
"\">Settings | API-Keys</a> and get Google Drive all set up, then come back "
|
4169 |
+
"here."
|
4170 |
msgstr ""
|
4171 |
|
4172 |
#: inc/pro/class-destination-gdrive.php:55
|
4173 |
+
#: inc/pro/class-destination-gdrive.php:297
|
4174 |
msgid "Authenticate"
|
4175 |
msgstr ""
|
4176 |
|
4177 |
#: inc/pro/class-destination-gdrive.php:62
|
4178 |
+
#: inc/pro/class-destination-gdrive.php:302
|
4179 |
msgid "Reauthenticate"
|
4180 |
msgstr ""
|
4181 |
|
4183 |
msgid "Folder in Google Drive"
|
4184 |
msgstr ""
|
4185 |
|
4186 |
+
#: inc/pro/class-destination-gdrive.php:110
|
4187 |
+
msgid ""
|
4188 |
+
"Consider using trash to delete files. If trash is not enabled, files will be "
|
4189 |
+
"deleted permanently."
|
4190 |
msgstr ""
|
4191 |
|
4192 |
+
#: inc/pro/class-destination-gdrive.php:167
|
4193 |
+
#: inc/pro/class-destination-gdrive.php:191
|
4194 |
msgid "GDrive: Authenticated."
|
4195 |
msgstr ""
|
4196 |
|
4197 |
+
#: inc/pro/class-destination-gdrive.php:171
|
4198 |
+
#: inc/pro/class-destination-gdrive.php:195
|
4199 |
msgid "GDrive: No refresh token received. Try to Authenticate again!"
|
4200 |
msgstr ""
|
4201 |
|
4202 |
+
#: inc/pro/class-destination-gdrive.php:177
|
4203 |
+
#: inc/pro/class-destination-gdrive.php:199
|
4204 |
+
#: inc/pro/class-destination-gdrive.php:218
|
4205 |
+
#: inc/pro/class-destination-gdrive.php:237
|
|
|
4206 |
msgid "GDrive API: %s"
|
4207 |
msgstr ""
|
4208 |
|
4209 |
+
#: inc/pro/class-destination-gdrive.php:440
|
|
|
4210 |
msgid "%d. Try to send backup file to Google Drive …"
|
4211 |
msgstr ""
|
4212 |
|
4213 |
+
#: inc/pro/class-destination-gdrive.php:468
|
4214 |
msgid "Uploading to Google Drive …"
|
4215 |
msgstr ""
|
4216 |
|
4217 |
+
#: inc/pro/class-destination-gdrive.php:530
|
4218 |
msgid "Could not create resumable file transfer to Google Drive"
|
4219 |
msgstr ""
|
4220 |
|
4221 |
+
#: inc/pro/class-destination-gdrive.php:574
|
4222 |
msgid "Can not resume transfer backup to Google Drive!"
|
4223 |
msgstr ""
|
4224 |
|
4225 |
+
#: inc/pro/class-destination-gdrive.php:641
|
|
|
4226 |
msgid "Error transfering file chunks to %s."
|
4227 |
msgstr ""
|
4228 |
|
4229 |
+
#: inc/pro/class-destination-gdrive.php:642
|
4230 |
+
#: inc/pro/class-destination-gdrive.php:668
|
4231 |
msgid "Google Drive"
|
4232 |
msgstr ""
|
4233 |
|
4234 |
+
#: inc/pro/class-destination-gdrive.php:716
|
|
|
4235 |
msgid "One file deleted from Google Drive"
|
4236 |
msgid_plural "%d files deleted on Google Drive"
|
4237 |
msgstr[0] ""
|
4238 |
msgstr[1] ""
|
4239 |
|
4240 |
+
#: inc/pro/class-destination-gdrive.php:722
|
4241 |
+
#: inc/pro/class-destination-gdrive.php:1028
|
|
|
4242 |
msgid "Google Drive API: %s"
|
4243 |
msgstr ""
|
4244 |
|
4245 |
+
#: inc/pro/class-destination-gdrive.php:849
|
|
|
4246 |
msgid "%d. Try to sync files to Google Drive …"
|
4247 |
msgstr ""
|
4248 |
|
4249 |
+
#: inc/pro/class-destination-gdrive.php:874
|
4250 |
msgid "Syncing changed files to Google Drive"
|
4251 |
msgstr ""
|
4252 |
|
4253 |
+
#: inc/pro/class-destination-gdrive.php:904
|
|
|
4254 |
msgid "File %s updated on Google Drive"
|
4255 |
msgstr ""
|
4256 |
|
4257 |
+
#: inc/pro/class-destination-gdrive.php:925
|
|
|
4258 |
msgid "File %s uploaded to Google Drive"
|
4259 |
msgstr ""
|
4260 |
|
4261 |
+
#: inc/pro/class-destination-gdrive.php:946
|
|
|
4262 |
msgid "File %s moved to trash in Google Drive"
|
4263 |
msgstr ""
|
4264 |
|
4265 |
+
#: inc/pro/class-destination-gdrive.php:949
|
|
|
4266 |
msgid "File %s deleted permanently in Google Drive"
|
4267 |
msgstr ""
|
4268 |
|
4269 |
+
#: inc/pro/class-destination-gdrive.php:995
|
|
|
4270 |
msgid "Extra file %s updated on Google Drive"
|
4271 |
msgstr ""
|
4272 |
|
4273 |
+
#: inc/pro/class-destination-gdrive.php:1017
|
|
|
4274 |
msgid "Extra file %s uploaded to Google Drive"
|
4275 |
msgstr ""
|
4276 |
|
4283 |
msgstr ""
|
4284 |
|
4285 |
#: inc/pro/class-destination-glacier.php:33
|
4286 |
+
#: inc/pro/class-destination-glacier.php:235
|
4287 |
msgid "Amazon Glacier Region"
|
4288 |
msgstr ""
|
4289 |
|
4290 |
#: inc/pro/class-destination-glacier.php:34
|
4291 |
+
#: inc/pro/class-destination-glacier.php:236
|
4292 |
msgid "US Standard"
|
4293 |
msgstr ""
|
4294 |
|
4295 |
#: inc/pro/class-destination-glacier.php:35
|
4296 |
+
#: inc/pro/class-destination-glacier.php:237
|
4297 |
msgid "US West (Northern California)"
|
4298 |
msgstr ""
|
4299 |
|
4300 |
#: inc/pro/class-destination-glacier.php:36
|
4301 |
+
#: inc/pro/class-destination-glacier.php:238
|
4302 |
msgid "US West (Oregon)"
|
4303 |
msgstr ""
|
4304 |
|
4305 |
#: inc/pro/class-destination-glacier.php:37
|
4306 |
+
#: inc/pro/class-destination-glacier.php:239
|
4307 |
msgid "EU (Ireland)"
|
4308 |
msgstr ""
|
4309 |
|
4310 |
#: inc/pro/class-destination-glacier.php:38
|
4311 |
+
#: inc/pro/class-destination-glacier.php:240
|
4312 |
msgid "EU (Germany)"
|
4313 |
msgstr ""
|
4314 |
|
4315 |
#: inc/pro/class-destination-glacier.php:39
|
4316 |
+
#: inc/pro/class-destination-glacier.php:241
|
4317 |
msgid "Asia Pacific (Tokyo)"
|
4318 |
msgstr ""
|
4319 |
|
4320 |
#: inc/pro/class-destination-glacier.php:40
|
4321 |
+
#: inc/pro/class-destination-glacier.php:242
|
4322 |
msgid "Asia Pacific (Seoul)"
|
4323 |
msgstr ""
|
4324 |
|
4327 |
msgstr ""
|
4328 |
|
4329 |
#: inc/pro/class-destination-glacier.php:42
|
4330 |
+
#: inc/pro/class-destination-glacier.php:244
|
4331 |
msgid "Asia Pacific (Sydney)"
|
4332 |
msgstr ""
|
4333 |
|
4334 |
#: inc/pro/class-destination-glacier.php:43
|
4335 |
+
#: inc/pro/class-destination-glacier.php:245
|
4336 |
msgid "South America (Sao Paulo)"
|
4337 |
msgstr ""
|
4338 |
|
4339 |
#: inc/pro/class-destination-glacier.php:44
|
4340 |
+
#: inc/pro/class-destination-glacier.php:246
|
4341 |
msgid "China (Beijing)"
|
4342 |
msgstr ""
|
4343 |
|
4362 |
msgstr ""
|
4363 |
|
4364 |
#: inc/pro/class-destination-glacier.php:108
|
4365 |
+
#: inc/pro/class-destination-glacier.php:264
|
4366 |
+
msgid ""
|
4367 |
+
"Number of files to keep in folder. (Archives deleted before 3 months after "
|
4368 |
+
"they have been stored may cause extra costs when deleted.)"
|
4369 |
msgstr ""
|
4370 |
|
4371 |
+
#: inc/pro/class-destination-glacier.php:172
|
4372 |
msgid "No vault found!"
|
4373 |
msgstr ""
|
4374 |
|
4375 |
+
#: inc/pro/class-destination-glacier.php:211
|
4376 |
+
#: inc/pro/class-destination-glacier.php:299
|
|
|
4377 |
msgid "Vault %1$s created."
|
4378 |
msgstr ""
|
4379 |
|
4380 |
+
#: inc/pro/class-destination-glacier.php:213
|
4381 |
+
#: inc/pro/class-destination-glacier.php:301
|
|
|
4382 |
msgid "Vault %s could not be created."
|
4383 |
msgstr ""
|
4384 |
|
4385 |
+
#: inc/pro/class-destination-glacier.php:234
|
4386 |
msgid "Select an Amazon Glacier region:"
|
4387 |
msgstr ""
|
4388 |
|
4389 |
+
#: inc/pro/class-destination-glacier.php:243
|
4390 |
msgid "Asia Pacific (Singapore)"
|
4391 |
msgstr ""
|
4392 |
|
4393 |
+
#: inc/pro/class-destination-glacier.php:248
|
4394 |
#: inc/pro/class-destination-msazure.php:19
|
4395 |
+
#: inc/pro/class-destination-s3.php:39
|
4396 |
msgid "Access Key:"
|
4397 |
msgstr ""
|
4398 |
|
4399 |
+
#: inc/pro/class-destination-glacier.php:250
|
4400 |
+
#: inc/pro/class-destination-s3.php:42
|
4401 |
msgid "Secret Key:"
|
4402 |
msgstr ""
|
4403 |
|
4404 |
+
#: inc/pro/class-destination-glacier.php:252
|
4405 |
msgid "Vault:"
|
4406 |
msgstr ""
|
4407 |
|
4408 |
+
#: inc/pro/class-destination-glacier.php:261
|
4409 |
msgid "New Vault:"
|
4410 |
msgstr ""
|
4411 |
|
4412 |
+
#: inc/pro/class-destination-glacier.php:341
|
4413 |
+
#: inc/pro/class-destination-glacier.php:456
|
4414 |
+
#: inc/pro/class-destination-glacier.php:475
|
4415 |
+
#: inc/pro/class-destination-glacier.php:518
|
|
|
4416 |
msgid "AWS API: %s"
|
4417 |
msgstr ""
|
4418 |
|
4419 |
+
#: inc/pro/class-destination-glacier.php:364
|
|
|
4420 |
msgid "%d. Trying to send backup file to Amazon Glacier …"
|
4421 |
msgstr ""
|
4422 |
|
4423 |
+
#: inc/pro/class-destination-glacier.php:377
|
|
|
4424 |
msgid "Connected to Glacier vault \"%1$s\" with %2$d archives and size of %3$d"
|
4425 |
msgstr ""
|
4426 |
|
4427 |
+
#: inc/pro/class-destination-glacier.php:379
|
|
|
4428 |
msgid "Glacier vault \"%s\" does not exist!"
|
4429 |
msgstr ""
|
4430 |
|
4431 |
+
#: inc/pro/class-destination-glacier.php:385
|
4432 |
msgid "Starting upload to Amazon Glacier …"
|
4433 |
msgstr ""
|
4434 |
|
4435 |
+
#: inc/pro/class-destination-glacier.php:438
|
|
|
4436 |
msgid "Archive ID: %s"
|
4437 |
msgstr ""
|
4438 |
|
4439 |
+
#: inc/pro/class-destination-glacier.php:449 inc/pro/class-pro.php:92
|
4440 |
msgid "Glacier"
|
4441 |
msgstr ""
|
4442 |
|
4443 |
+
#: inc/pro/class-destination-glacier.php:508
|
|
|
4444 |
msgid "Cannot delete archive from %s."
|
4445 |
msgstr ""
|
4446 |
|
4447 |
+
#: inc/pro/class-destination-glacier.php:512
|
|
|
4448 |
msgid "One file deleted on vault."
|
4449 |
msgid_plural "%d files deleted on vault"
|
4450 |
msgstr[0] ""
|
4470 |
msgstr ""
|
4471 |
|
4472 |
#: inc/pro/class-destination-msazure.php:119
|
|
|
4473 |
msgid "%d. Trying to sync files with Microsoft Azure (Blob) …"
|
4474 |
msgstr ""
|
4475 |
|
4482 |
msgstr ""
|
4483 |
|
4484 |
#: inc/pro/class-destination-msazure.php:182
|
|
|
4485 |
msgid "File %s uploaded to MS Azure."
|
4486 |
msgstr ""
|
4487 |
|
4488 |
#: inc/pro/class-destination-msazure.php:208
|
|
|
4489 |
msgid "Extra file %s uploaded to MS Azure."
|
4490 |
msgstr ""
|
4491 |
|
4494 |
msgstr ""
|
4495 |
|
4496 |
#: inc/pro/class-destination-msazure.php:224
|
|
|
4497 |
msgid "File %s deleted from MS Azure."
|
4498 |
msgstr ""
|
4499 |
|
4506 |
msgstr ""
|
4507 |
|
4508 |
#: inc/pro/class-destination-rsc.php:147
|
|
|
4509 |
msgid "%d. Trying to sync files to Rackspace cloud …"
|
4510 |
msgstr ""
|
4511 |
|
4512 |
#: inc/pro/class-destination-rsc.php:167
|
|
|
4513 |
msgid "Connected to Rackspace cloud files container %s."
|
4514 |
msgstr ""
|
4515 |
|
4522 |
msgstr ""
|
4523 |
|
4524 |
#: inc/pro/class-destination-rsc.php:230
|
|
|
4525 |
msgid "File %s uploaded to Rackspace Cloud."
|
4526 |
msgstr ""
|
4527 |
|
4528 |
#: inc/pro/class-destination-rsc.php:263
|
|
|
4529 |
msgid "Extra file %s uploaded to Rackspace Cloud."
|
4530 |
msgstr ""
|
4531 |
|
4534 |
msgstr ""
|
4535 |
|
4536 |
#: inc/pro/class-destination-rsc.php:280
|
|
|
4537 |
msgid "File %s deleted from Rackspace Cloud."
|
4538 |
msgstr ""
|
4539 |
|
4541 |
msgid "Select a S3 service:"
|
4542 |
msgstr ""
|
4543 |
|
4544 |
+
#: inc/pro/class-destination-s3.php:36
|
4545 |
msgid "or set an S3 Server URL:"
|
4546 |
msgstr ""
|
4547 |
|
4548 |
+
#: inc/pro/class-destination-s3.php:45
|
4549 |
msgid "Bucket:"
|
4550 |
msgstr ""
|
4551 |
|
4552 |
+
#: inc/pro/class-destination-s3.php:55
|
4553 |
msgid "New Bucket:"
|
4554 |
msgstr ""
|
4555 |
|
4556 |
+
#: inc/pro/class-destination-s3.php:57
|
4557 |
msgid "Folder in bucket:"
|
4558 |
msgstr ""
|
4559 |
|
4560 |
+
#: inc/pro/class-destination-s3.php:145
|
|
|
4561 |
msgid "Bucket %1$s created in %2$s."
|
4562 |
msgstr ""
|
4563 |
|
4564 |
+
#: inc/pro/class-destination-s3.php:169
|
|
|
4565 |
msgid "%d. Trying to sync files to S3 Service …"
|
4566 |
msgstr ""
|
4567 |
|
4568 |
+
#: inc/pro/class-destination-s3.php:203
|
4569 |
msgid "Retrieving file list from S3."
|
4570 |
msgstr ""
|
4571 |
|
4572 |
+
#: inc/pro/class-destination-s3.php:265
|
4573 |
msgid "Upload changed files to S3."
|
4574 |
msgstr ""
|
4575 |
|
4576 |
+
#: inc/pro/class-destination-s3.php:280
|
|
|
4577 |
msgid "File %s uploaded to S3."
|
4578 |
msgstr ""
|
4579 |
|
4580 |
+
#: inc/pro/class-destination-s3.php:308
|
|
|
4581 |
msgid "Extra file %s uploaded to S3."
|
4582 |
msgstr ""
|
4583 |
|
4584 |
+
#: inc/pro/class-destination-s3.php:321
|
4585 |
msgid "Delete nonexistent files on S3"
|
4586 |
msgstr ""
|
4587 |
|
4588 |
+
#: inc/pro/class-destination-s3.php:328
|
|
|
4589 |
msgid "File %s deleted from S3."
|
4590 |
msgstr ""
|
4591 |
|
4655 |
msgstr ""
|
4656 |
|
4657 |
#: inc/pro/class-jobtype-dbdump.php:190
|
4658 |
+
msgid ""
|
4659 |
+
"Path to mysqldump file, so a backup can be made with it. If it is correct "
|
4660 |
+
"and <em>shell_exec</em> is active, the backup will be generated with a "
|
4661 |
+
"system command. If <em>shell_exec</em> ist not active, this is disabled"
|
4662 |
msgstr ""
|
4663 |
|
4664 |
#: inc/pro/class-jobtype-dbdump.php:580
|
|
|
4665 |
msgid "Added database backup \"%1$s\" with %2$s to backup file list"
|
4666 |
msgstr ""
|
4667 |
|
4668 |
#: inc/pro/class-jobtype-dbdump.php:601
|
|
|
4669 |
msgid "%d. Try to backup MySQL system …"
|
4670 |
msgstr ""
|
4671 |
|
4672 |
#: inc/pro/class-jobtype-dbdump.php:608
|
4673 |
+
msgid ""
|
4674 |
+
"Executing of system commands not allowed. Please use backup with mysqli."
|
4675 |
msgstr ""
|
4676 |
|
4677 |
#: inc/pro/class-jobtype-dbdump.php:613
|
|
|
4678 |
msgid "%s file not in open basedir of PHP."
|
4679 |
msgstr ""
|
4680 |
|
4681 |
#: inc/pro/class-jobtype-dbdump.php:618
|
|
|
4682 |
msgid "%s file not found. Please correct the path for the mysqldump file."
|
4683 |
msgstr ""
|
4684 |
|
4685 |
#: inc/pro/class-jobtype-dbdump.php:702
|
|
|
4686 |
msgctxt "Executed exec() command"
|
4687 |
msgid "CLI Exec: %s"
|
4688 |
msgstr ""
|
4692 |
msgstr ""
|
4693 |
|
4694 |
#: inc/pro/class-jobtype-dbdump.php:713
|
4695 |
+
msgid ""
|
4696 |
+
"MySQL Server Error. This could be an issue with permissions. Try using "
|
4697 |
+
"database backup with mysqli."
|
4698 |
msgstr ""
|
4699 |
|
4700 |
#: inc/pro/class-jobtype-dbdump.php:714
|
4714 |
msgstr ""
|
4715 |
|
4716 |
#: inc/pro/class-jobtype-dbdump.php:722
|
|
|
4717 |
msgid "mysqldump returned: (%d) %s"
|
4718 |
msgstr ""
|
4719 |
|
4722 |
msgstr ""
|
4723 |
|
4724 |
#: inc/pro/class-jobtype-dbdump.php:781
|
|
|
4725 |
msgid "%d. Try to backup database as XML …"
|
4726 |
msgstr ""
|
4727 |
|
4728 |
#: inc/pro/class-jobtype-dbdump.php:851
|
|
|
4729 |
msgctxt "Database Charset"
|
4730 |
msgid "Cannot set DB charset to %s"
|
4731 |
msgstr ""
|
4735 |
msgstr ""
|
4736 |
|
4737 |
#: inc/pro/class-jobtype-dbdump.php:916
|
|
|
4738 |
msgid "Dump database create view \"%s\""
|
4739 |
msgstr ""
|
4740 |
|
4741 |
#: inc/pro/class-jobtype-dbdump.php:934
|
|
|
4742 |
msgid "Backup database structure \"%s\" to XML"
|
4743 |
msgstr ""
|
4744 |
|
4745 |
#: inc/pro/class-jobtype-dbdump.php:976
|
|
|
4746 |
msgid "Backup table \"%s\" data to XML"
|
4747 |
msgstr ""
|
4748 |
|
4749 |
#: inc/pro/class-jobtype-dbdump.php:1044
|
|
|
4750 |
msgid "Added database XML dump \"%1$s\" with %2$s to backup file list"
|
4751 |
msgstr ""
|
4752 |
|
4792 |
|
4793 |
#: inc/pro/class-page-wizard.php:179 inc/pro/class-page-wizard.php:456
|
4794 |
#: inc/pro/class-page-wizard.php:488
|
4795 |
+
msgid "Next ›"
|
4796 |
msgstr ""
|
4797 |
|
4798 |
#: inc/pro/class-page-wizard.php:196 inc/pro/class-page-wizard.php:452
|
4799 |
+
msgid "‹ Previous"
|
4800 |
msgstr ""
|
4801 |
|
4802 |
#: inc/pro/class-page-wizard.php:349
|
|
|
4803 |
msgctxt "Plugin Name"
|
4804 |
msgid "%s › Wizards"
|
4805 |
msgstr ""
|
4806 |
|
4807 |
#: inc/pro/class-page-wizard.php:388
|
|
|
4808 |
msgctxt "Plugin Name"
|
4809 |
msgid "%s Wizard:"
|
4810 |
msgstr ""
|
4826 |
msgstr ""
|
4827 |
|
4828 |
#: inc/pro/class-settings-apikeys.php:46
|
4829 |
+
msgid ""
|
4830 |
+
"Hash Key for BackWPup. It will be used to have hashes in folder and file "
|
4831 |
+
"names. It must at least 6 chars long."
|
4832 |
msgstr ""
|
4833 |
|
4834 |
#: inc/pro/class-settings-apikeys.php:49
|
4840 |
msgstr ""
|
4841 |
|
4842 |
#: inc/pro/class-settings-apikeys.php:74
|
4843 |
+
msgid ""
|
4844 |
+
"If you want to set your own Dropbox API Keys, you can do it here. Leave "
|
4845 |
+
"empty for default."
|
4846 |
msgstr ""
|
4847 |
|
4848 |
#: inc/pro/class-settings-apikeys.php:77
|
4866 |
msgstr ""
|
4867 |
|
4868 |
#: inc/pro/class-settings-apikeys.php:132
|
4869 |
+
msgid ""
|
4870 |
+
"If you want to set your own SugarSync API keys you can do that here. Leave "
|
4871 |
+
"empty for default."
|
4872 |
msgstr ""
|
4873 |
|
4874 |
#: inc/pro/class-settings-apikeys.php:135
|
4960 |
msgstr ""
|
4961 |
|
4962 |
#: inc/pro/class-wizard-job.php:427
|
4963 |
+
msgid ""
|
4964 |
+
"PHP Zip functions will be used if available (memory lees). Else PCLZip Class "
|
4965 |
+
"will used."
|
4966 |
msgstr ""
|
4967 |
|
4968 |
#: inc/pro/class-wizard-job.php:430 inc/pro/class-wizard-job.php:441
|
4987 |
msgstr ""
|
4988 |
|
4989 |
#: inc/pro/class-wizard-job.php:661
|
|
|
4990 |
msgid "Wizard: %1$s"
|
4991 |
msgstr ""
|
4992 |
|
4993 |
#: inc/pro/class-wizard-job.php:680
|
|
|
4994 |
msgid "New job %s generated."
|
4995 |
msgstr ""
|
4996 |
|
5052 |
msgstr ""
|
5053 |
|
5054 |
#: inc/pro/class-wizard-jobimport.php:67
|
5055 |
+
msgid ""
|
5056 |
+
"Please upload your BackWPup job XML export file and we’ll import the "
|
5057 |
+
"jobs into BackWPup."
|
5058 |
msgstr ""
|
5059 |
|
5060 |
#: inc/pro/class-wizard-jobimport.php:69
|
5062 |
msgstr ""
|
5063 |
|
5064 |
#: inc/pro/class-wizard-jobimport.php:69
|
|
|
5065 |
msgid "Maximum size: %s"
|
5066 |
msgstr ""
|
5067 |
|
5094 |
msgstr ""
|
5095 |
|
5096 |
#: inc/pro/class-wizard-jobimport.php:142
|
5097 |
+
msgid ""
|
5098 |
+
"File is empty. Please upload something more substantial. This error could "
|
5099 |
+
"also caused by uploads being disabled in your php.ini or by post_max_size "
|
5100 |
+
"being defined as smaller than upload_max_filesize in php.ini."
|
5101 |
msgstr ""
|
5102 |
|
5103 |
#: inc/pro/class-wizard-jobimport.php:157
|
5104 |
+
msgid ""
|
5105 |
+
"The export file could not be found at <code>%s</code>. This is likely due to "
|
5106 |
+
"an issue with permissions."
|
5107 |
msgstr ""
|
5108 |
|
5109 |
#: inc/pro/class-wizard-jobimport.php:164
|
5111 |
msgstr ""
|
5112 |
|
5113 |
#: inc/pro/class-wizard-jobimport.php:171
|
5114 |
+
msgid ""
|
5115 |
+
"This Export file (version %s) may not be supported by this version of the "
|
5116 |
+
"importer."
|
5117 |
msgstr ""
|
5118 |
|
5119 |
#: inc/pro/class-wizard-jobimport.php:177
|
5121 |
msgstr ""
|
5122 |
|
5123 |
#: inc/pro/class-wizard-jobimport.php:243
|
|
|
5124 |
msgid "Job %1$s with id %2$d imported"
|
5125 |
msgstr ""
|
5126 |
|
5153 |
msgstr ""
|
5154 |
|
5155 |
#: inc/pro/class-wizard-systemtest.php:99
|
5156 |
+
msgid ""
|
5157 |
+
"You must run WordPress version 3.4 or higher to use this plugin. You are "
|
5158 |
+
"using version %s now."
|
5159 |
msgstr ""
|
5160 |
|
5161 |
#: inc/pro/class-wizard-systemtest.php:104
|
5162 |
+
msgid ""
|
5163 |
+
"You must run PHP version 5.2.6 or higher to use this plugin. You are using "
|
5164 |
+
"version %s now."
|
5165 |
msgstr ""
|
5166 |
|
5167 |
#: inc/pro/class-wizard-systemtest.php:108
|
5168 |
+
msgid ""
|
5169 |
+
"We recommend to run a PHP version above 5.3.2 to get the full plugin "
|
5170 |
+
"functionality. You are using version %s now."
|
5171 |
msgstr ""
|
5172 |
|
5173 |
#: inc/pro/class-wizard-systemtest.php:113
|
5174 |
+
msgid ""
|
5175 |
+
"You must have the MySQLi extension installed and a MySQL server version of "
|
5176 |
+
"5.0.7 or higher to use this plugin. You are using version %s now."
|
5177 |
msgstr ""
|
5178 |
|
5179 |
#: inc/pro/class-wizard-systemtest.php:118
|
5180 |
+
msgid ""
|
5181 |
+
"PHP cURL extension must be installed to use the full plugin functionality."
|
5182 |
msgstr ""
|
5183 |
|
5184 |
+
#: inc/pro/class-wizard-systemtest.php:122
|
|
|
5185 |
msgctxt "%1 = extension name, %2 = file suffix"
|
5186 |
msgid "We recommend to install the %1$s extension to generate %2$s archives."
|
5187 |
msgstr ""
|
5188 |
|
5189 |
#: inc/pro/class-wizard-systemtest.php:146
|
|
|
5190 |
msgctxt "Link to PHP manual"
|
5191 |
msgid "Please disable the deprecated <a href=\"%s\">PHP safe mode</a>."
|
5192 |
msgstr ""
|
5193 |
|
5194 |
#: inc/pro/class-wizard-systemtest.php:154
|
5195 |
+
msgid ""
|
5196 |
+
"We recommend to install the PHP FTP extension to use the FTP backup "
|
5197 |
+
"destination."
|
5198 |
msgstr ""
|
5199 |
|
5200 |
#: inc/pro/class-wizard-systemtest.php:174
|
|
|
5201 |
msgid "The HTTP response test result is an error: \"%s\"."
|
5202 |
msgstr ""
|
5203 |
|
5204 |
#: inc/pro/class-wizard-systemtest.php:178
|
5205 |
+
msgid ""
|
5206 |
+
"The HTTP response test result is a wrong HTTP status: %s. It should be "
|
5207 |
+
"status 200."
|
5208 |
msgstr ""
|
5209 |
|
5210 |
#: inc/pro/class-wizard-systemtest.php:191
|
5216 |
msgstr ""
|
5217 |
|
5218 |
#: inc/pro/class-wizard-systemtest.php:199
|
5219 |
+
msgid ""
|
5220 |
+
"There is no error, but some warnings. BackWPup will work, but with "
|
5221 |
+
"limitations."
|
5222 |
msgstr ""
|
5223 |
|
5224 |
#: inc/pro/class-wizard-systemtest.php:202
|
5225 |
msgid "There are errors. Please correct them, or BackWPup cannot work."
|
5226 |
+
msgstr ""
|
5227 |
+
|
5228 |
+
#: vendor/inpsyde/phone-home-client/src/CronController.php:80
|
5229 |
+
msgid "Every %d days"
|
5230 |
+
msgstr ""
|
5231 |
+
|
5232 |
+
#: vendor/inpsyde/phone-home-client/src/FrontController.php:143
|
5233 |
+
msgid "%s needs your help"
|
5234 |
+
msgstr ""
|
5235 |
+
|
5236 |
+
#: vendor/inpsyde/phone-home-client/src/FrontController.php:144
|
5237 |
+
msgid "Help %s"
|
5238 |
+
msgstr ""
|
5239 |
+
|
5240 |
+
#: vendor/inpsyde/phone-home-client/src/Template/Buttons.php:28
|
5241 |
+
msgid "Yes, I agree."
|
5242 |
+
msgstr ""
|
5243 |
+
|
5244 |
+
#: vendor/inpsyde/phone-home-client/src/Template/Buttons.php:45
|
5245 |
+
msgid "I have to think about that, ask me later."
|
5246 |
+
msgstr ""
|
5247 |
+
|
5248 |
+
#: vendor/inpsyde/phone-home-client/src/Template/Buttons.php:62
|
5249 |
+
msgid "Please no. Don't ask me again."
|
5250 |
+
msgstr ""
|
5251 |
+
|
5252 |
+
#: vendor/inpsyde/phone-home-client/src/Template/Buttons.php:84
|
5253 |
+
msgid "More info"
|
5254 |
+
msgstr ""
|
5255 |
+
|
5256 |
+
#. Plugin Name of the plugin/theme
|
5257 |
+
msgid "BackWPup Pro"
|
5258 |
+
msgstr ""
|
5259 |
+
|
5260 |
+
#. Description of the plugin/theme
|
5261 |
+
msgid "WordPress Backup Plugin"
|
5262 |
+
msgstr ""
|
5263 |
+
|
5264 |
+
#. Author of the plugin/theme
|
5265 |
+
msgid "Inpsyde GmbH"
|
5266 |
+
msgstr ""
|
readme.txt
CHANGED
@@ -1,15 +1,16 @@
|
|
1 |
=== BackWPup - WordPress Backup Plugin ===
|
2 |
-
Contributors: inpsyde, danielhuesken, Bueltge, nullbyte
|
3 |
Tags: Amazon, Amazon S3, back up, backup, chinese, cloud, cloud files, database, db backup, dropbox, dump, file, french, ftp, ftps, german, migrate, multisite, russian, schedule, sftp, storage, S3, time, upload, xml
|
4 |
Requires at least: 3.9
|
5 |
-
Tested up to: 4.7.
|
6 |
-
Stable tag: 3.
|
7 |
License: GPLv3
|
8 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
9 |
|
10 |
Schedule complete automatic backups of your WordPress installation. Decide which content will be stored (Dropbox, S3…). This is the free version
|
11 |
|
12 |
== Description ==
|
|
|
13 |
The **backup plugin** **[BackWPup](http://backwpup.com/)** can be used to save your complete installation including /wp-content/ and push them to an external Backup Service, like **Dropbox**, **S3**, **FTP** and many more, see list below. With a single backup .zip file you are able to easily restore an installation. Please understand: this free version will not be supported as good as the [BackWPup Pro version](http://backwpup.com). With our premium version you get first class support and more features.
|
14 |
|
15 |
|
@@ -34,7 +35,7 @@ The **backup plugin** **[BackWPup](http://backwpup.com/)** can be used to save y
|
|
34 |
* Pro version and support available - [BackWPup Pro](http://backwpup.com)
|
35 |
|
36 |
= Requirements =
|
37 |
-
* WordPress 3.9 and PHP 5.
|
38 |
* To use the Plugin with full functionality PHP 5.3.3 with mysqli, FTP,gz, bz2, ZipArchive and curl is needed.
|
39 |
* Plugin functions that don't work because of your server settings, will not be displayed in admin area.
|
40 |
|
@@ -156,6 +157,18 @@ Yes. You need to have writing access to the wp-config.php file (usually residing
|
|
156 |
[You can find a detailed tutorial in the BackWPup documentation.](http://docs.backwpup.com/article/118-install-backwpup)
|
157 |
|
158 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
= Version 3.3.7 =
|
160 |
* Fixed: Services credentials lost after 3.3.6 update
|
161 |
* Fixed: Removed all instances of PHP short echo tags and other minor PHP 5.2 compatibility issues
|
1 |
=== BackWPup - WordPress Backup Plugin ===
|
2 |
+
Contributors: inpsyde, cocreation, danielhuesken, Bueltge, nullbyte
|
3 |
Tags: Amazon, Amazon S3, back up, backup, chinese, cloud, cloud files, database, db backup, dropbox, dump, file, french, ftp, ftps, german, migrate, multisite, russian, schedule, sftp, storage, S3, time, upload, xml
|
4 |
Requires at least: 3.9
|
5 |
+
Tested up to: 4.7.4
|
6 |
+
Stable tag: 3.4.0
|
7 |
License: GPLv3
|
8 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
9 |
|
10 |
Schedule complete automatic backups of your WordPress installation. Decide which content will be stored (Dropbox, S3…). This is the free version
|
11 |
|
12 |
== Description ==
|
13 |
+
|
14 |
The **backup plugin** **[BackWPup](http://backwpup.com/)** can be used to save your complete installation including /wp-content/ and push them to an external Backup Service, like **Dropbox**, **S3**, **FTP** and many more, see list below. With a single backup .zip file you are able to easily restore an installation. Please understand: this free version will not be supported as good as the [BackWPup Pro version](http://backwpup.com). With our premium version you get first class support and more features.
|
15 |
|
16 |
|
35 |
* Pro version and support available - [BackWPup Pro](http://backwpup.com)
|
36 |
|
37 |
= Requirements =
|
38 |
+
* WordPress 3.9 and PHP 5.3 required!
|
39 |
* To use the Plugin with full functionality PHP 5.3.3 with mysqli, FTP,gz, bz2, ZipArchive and curl is needed.
|
40 |
* Plugin functions that don't work because of your server settings, will not be displayed in admin area.
|
41 |
|
157 |
[You can find a detailed tutorial in the BackWPup documentation.](http://docs.backwpup.com/article/118-install-backwpup)
|
158 |
|
159 |
== Changelog ==
|
160 |
+
= Version 3.4.0 =
|
161 |
+
* Changed: Dropped support for PHP 5.2.
|
162 |
+
* Improved: Migrated to Dropbox API V2.
|
163 |
+
* Changed: Removed Adminer link from backend.
|
164 |
+
* Added: Backup file tracking so backups from other jobs aren't accidentally deleted.
|
165 |
+
* Fixed: Call to get_users was previously incorrect.
|
166 |
+
* Added: Ability to have backup file sent to multiple email addresses.
|
167 |
+
* Added: Web.config is now included in list of special files to back up.
|
168 |
+
* Fixed: error for some users when generating XML export.
|
169 |
+
* Fixed: opendir permission denied warning on some versions of IIS.
|
170 |
+
* Improved: accuracy of binary column export.
|
171 |
+
|
172 |
= Version 3.3.7 =
|
173 |
* Fixed: Services credentials lost after 3.3.6 update
|
174 |
* Fixed: Removed all instances of PHP short echo tags and other minor PHP 5.2 compatibility issues
|
vendor/PEAR/HTTP/Request2.php
CHANGED
@@ -1,1030 +1,1030 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class representing a HTTP request message
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/**
|
22 |
-
* A class representing an URL as per RFC 3986.
|
23 |
-
*/
|
24 |
-
require_once 'Net/URL2.php';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Exception class for HTTP_Request2 package
|
28 |
-
*/
|
29 |
-
require_once 'HTTP/Request2/Exception.php';
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Class representing a HTTP request message
|
33 |
-
*
|
34 |
-
* @category HTTP
|
35 |
-
* @package HTTP_Request2
|
36 |
-
* @author Alexey Borzov <avb@php.net>
|
37 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
38 |
-
* @version Release: 2.2.1
|
39 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
40 |
-
* @link http://tools.ietf.org/html/rfc2616#section-5
|
41 |
-
*/
|
42 |
-
class HTTP_Request2 implements SplSubject
|
43 |
-
{
|
44 |
-
/**#@+
|
45 |
-
* Constants for HTTP request methods
|
46 |
-
*
|
47 |
-
* @link http://tools.ietf.org/html/rfc2616#section-5.1.1
|
48 |
-
*/
|
49 |
-
const METHOD_OPTIONS = 'OPTIONS';
|
50 |
-
const METHOD_GET = 'GET';
|
51 |
-
const METHOD_HEAD = 'HEAD';
|
52 |
-
const METHOD_POST = 'POST';
|
53 |
-
const METHOD_PUT = 'PUT';
|
54 |
-
const METHOD_DELETE = 'DELETE';
|
55 |
-
const METHOD_TRACE = 'TRACE';
|
56 |
-
const METHOD_CONNECT = 'CONNECT';
|
57 |
-
/**#@-*/
|
58 |
-
|
59 |
-
/**#@+
|
60 |
-
* Constants for HTTP authentication schemes
|
61 |
-
*
|
62 |
-
* @link http://tools.ietf.org/html/rfc2617
|
63 |
-
*/
|
64 |
-
const AUTH_BASIC = 'basic';
|
65 |
-
const AUTH_DIGEST = 'digest';
|
66 |
-
/**#@-*/
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Regular expression used to check for invalid symbols in RFC 2616 tokens
|
70 |
-
* @link http://pear.php.net/bugs/bug.php?id=15630
|
71 |
-
*/
|
72 |
-
const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!';
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Regular expression used to check for invalid symbols in cookie strings
|
76 |
-
* @link http://pear.php.net/bugs/bug.php?id=15630
|
77 |
-
* @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
|
78 |
-
*/
|
79 |
-
const REGEXP_INVALID_COOKIE = '/[\s,;]/';
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Fileinfo magic database resource
|
83 |
-
* @var resource
|
84 |
-
* @see detectMimeType()
|
85 |
-
*/
|
86 |
-
private static $_fileinfoDb;
|
87 |
-
|
88 |
-
/**
|
89 |
-
* Observers attached to the request (instances of SplObserver)
|
90 |
-
* @var array
|
91 |
-
*/
|
92 |
-
protected $observers = array();
|
93 |
-
|
94 |
-
/**
|
95 |
-
* Request URL
|
96 |
-
* @var Net_URL2
|
97 |
-
*/
|
98 |
-
protected $url;
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Request method
|
102 |
-
* @var string
|
103 |
-
*/
|
104 |
-
protected $method = self::METHOD_GET;
|
105 |
-
|
106 |
-
/**
|
107 |
-
* Authentication data
|
108 |
-
* @var array
|
109 |
-
* @see getAuth()
|
110 |
-
*/
|
111 |
-
protected $auth;
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Request headers
|
115 |
-
* @var array
|
116 |
-
*/
|
117 |
-
protected $headers = array();
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Configuration parameters
|
121 |
-
* @var array
|
122 |
-
* @see setConfig()
|
123 |
-
*/
|
124 |
-
protected $config = array(
|
125 |
-
'adapter' => 'HTTP_Request2_Adapter_Socket',
|
126 |
-
'connect_timeout' => 10,
|
127 |
-
'timeout' => 0,
|
128 |
-
'use_brackets' => true,
|
129 |
-
'protocol_version' => '1.1',
|
130 |
-
'buffer_size' => 16384,
|
131 |
-
'store_body' => true,
|
132 |
-
'local_ip' => null,
|
133 |
-
|
134 |
-
'proxy_host' => '',
|
135 |
-
'proxy_port' => '',
|
136 |
-
'proxy_user' => '',
|
137 |
-
'proxy_password' => '',
|
138 |
-
'proxy_auth_scheme' => self::AUTH_BASIC,
|
139 |
-
'proxy_type' => 'http',
|
140 |
-
|
141 |
-
'ssl_verify_peer' => true,
|
142 |
-
'ssl_verify_host' => true,
|
143 |
-
'ssl_cafile' => null,
|
144 |
-
'ssl_capath' => null,
|
145 |
-
'ssl_local_cert' => null,
|
146 |
-
'ssl_passphrase' => null,
|
147 |
-
|
148 |
-
'digest_compat_ie' => false,
|
149 |
-
|
150 |
-
'follow_redirects' => false,
|
151 |
-
'max_redirects' => 5,
|
152 |
-
'strict_redirects' => false
|
153 |
-
);
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Last event in request / response handling, intended for observers
|
157 |
-
* @var array
|
158 |
-
* @see getLastEvent()
|
159 |
-
*/
|
160 |
-
protected $lastEvent = array(
|
161 |
-
'name' => 'start',
|
162 |
-
'data' => null
|
163 |
-
);
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Request body
|
167 |
-
* @var string|resource
|
168 |
-
* @see setBody()
|
169 |
-
*/
|
170 |
-
protected $body = '';
|
171 |
-
|
172 |
-
/**
|
173 |
-
* Array of POST parameters
|
174 |
-
* @var array
|
175 |
-
*/
|
176 |
-
protected $postParams = array();
|
177 |
-
|
178 |
-
/**
|
179 |
-
* Array of file uploads (for multipart/form-data POST requests)
|
180 |
-
* @var array
|
181 |
-
*/
|
182 |
-
protected $uploads = array();
|
183 |
-
|
184 |
-
/**
|
185 |
-
* Adapter used to perform actual HTTP request
|
186 |
-
* @var HTTP_Request2_Adapter
|
187 |
-
*/
|
188 |
-
protected $adapter;
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Cookie jar to persist cookies between requests
|
192 |
-
* @var HTTP_Request2_CookieJar
|
193 |
-
*/
|
194 |
-
protected $cookieJar = null;
|
195 |
-
|
196 |
-
/**
|
197 |
-
* Constructor. Can set request URL, method and configuration array.
|
198 |
-
*
|
199 |
-
* Also sets a default value for User-Agent header.
|
200 |
-
*
|
201 |
-
* @param string|Net_Url2 $url Request URL
|
202 |
-
* @param string $method Request method
|
203 |
-
* @param array $config Configuration for this Request instance
|
204 |
-
*/
|
205 |
-
public function __construct(
|
206 |
-
$url = null, $method = self::METHOD_GET, array $config = array()
|
207 |
-
) {
|
208 |
-
$this->setConfig($config);
|
209 |
-
if (!empty($url)) {
|
210 |
-
$this->setUrl($url);
|
211 |
-
}
|
212 |
-
if (!empty($method)) {
|
213 |
-
$this->setMethod($method);
|
214 |
-
}
|
215 |
-
$this->setHeader(
|
216 |
-
'user-agent', 'HTTP_Request2/2.2.1 ' .
|
217 |
-
'(http://pear.php.net/package/http_request2) PHP/' . phpversion()
|
218 |
-
);
|
219 |
-
}
|
220 |
-
|
221 |
-
/**
|
222 |
-
* Sets the URL for this request
|
223 |
-
*
|
224 |
-
* If the URL has userinfo part (username & password) these will be removed
|
225 |
-
* and converted to auth data. If the URL does not have a path component,
|
226 |
-
* that will be set to '/'.
|
227 |
-
*
|
228 |
-
* @param string|Net_URL2 $url Request URL
|
229 |
-
*
|
230 |
-
* @return HTTP_Request2
|
231 |
-
* @throws HTTP_Request2_LogicException
|
232 |
-
*/
|
233 |
-
public function setUrl($url)
|
234 |
-
{
|
235 |
-
if (is_string($url)) {
|
236 |
-
$url = new Net_URL2(
|
237 |
-
$url, array(Net_URL2::OPTION_USE_BRACKETS => $this->config['use_brackets'])
|
238 |
-
);
|
239 |
-
}
|
240 |
-
if (!$url instanceof Net_URL2) {
|
241 |
-
throw new HTTP_Request2_LogicException(
|
242 |
-
'Parameter is not a valid HTTP URL',
|
243 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
244 |
-
);
|
245 |
-
}
|
246 |
-
// URL contains username / password?
|
247 |
-
if ($url->getUserinfo()) {
|
248 |
-
$username = $url->getUser();
|
249 |
-
$password = $url->getPassword();
|
250 |
-
$this->setAuth(rawurldecode($username), $password? rawurldecode($password): '');
|
251 |
-
$url->setUserinfo('');
|
252 |
-
}
|
253 |
-
if ('' == $url->getPath()) {
|
254 |
-
$url->setPath('/');
|
255 |
-
}
|
256 |
-
$this->url = $url;
|
257 |
-
|
258 |
-
return $this;
|
259 |
-
}
|
260 |
-
|
261 |
-
/**
|
262 |
-
* Returns the request URL
|
263 |
-
*
|
264 |
-
* @return Net_URL2
|
265 |
-
*/
|
266 |
-
public function getUrl()
|
267 |
-
{
|
268 |
-
return $this->url;
|
269 |
-
}
|
270 |
-
|
271 |
-
/**
|
272 |
-
* Sets the request method
|
273 |
-
*
|
274 |
-
* @param string $method one of the methods defined in RFC 2616
|
275 |
-
*
|
276 |
-
* @return HTTP_Request2
|
277 |
-
* @throws HTTP_Request2_LogicException if the method name is invalid
|
278 |
-
*/
|
279 |
-
public function setMethod($method)
|
280 |
-
{
|
281 |
-
// Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1
|
282 |
-
if (preg_match(self::REGEXP_INVALID_TOKEN, $method)) {
|
283 |
-
throw new HTTP_Request2_LogicException(
|
284 |
-
"Invalid request method '{$method}'",
|
285 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
286 |
-
);
|
287 |
-
}
|
288 |
-
$this->method = $method;
|
289 |
-
|
290 |
-
return $this;
|
291 |
-
}
|
292 |
-
|
293 |
-
/**
|
294 |
-
* Returns the request method
|
295 |
-
*
|
296 |
-
* @return string
|
297 |
-
*/
|
298 |
-
public function getMethod()
|
299 |
-
{
|
300 |
-
return $this->method;
|
301 |
-
}
|
302 |
-
|
303 |
-
/**
|
304 |
-
* Sets the configuration parameter(s)
|
305 |
-
*
|
306 |
-
* The following parameters are available:
|
307 |
-
* <ul>
|
308 |
-
* <li> 'adapter' - adapter to use (string)</li>
|
309 |
-
* <li> 'connect_timeout' - Connection timeout in seconds (integer)</li>
|
310 |
-
* <li> 'timeout' - Total number of seconds a request can take.
|
311 |
-
* Use 0 for no limit, should be greater than
|
312 |
-
* 'connect_timeout' if set (integer)</li>
|
313 |
-
* <li> 'use_brackets' - Whether to append [] to array variable names (bool)</li>
|
314 |
-
* <li> 'protocol_version' - HTTP Version to use, '1.0' or '1.1' (string)</li>
|
315 |
-
* <li> 'buffer_size' - Buffer size to use for reading and writing (int)</li>
|
316 |
-
* <li> 'store_body' - Whether to store response body in response object.
|
317 |
-
* Set to false if receiving a huge response and
|
318 |
-
* using an Observer to save it (boolean)</li>
|
319 |
-
* <li> 'local_ip' - Specifies the IP address that will be used for accessing
|
320 |
-
* the network (string)</li>
|
321 |
-
* <li> 'proxy_type' - Proxy type, 'http' or 'socks5' (string)</li>
|
322 |
-
* <li> 'proxy_host' - Proxy server host (string)</li>
|
323 |
-
* <li> 'proxy_port' - Proxy server port (integer)</li>
|
324 |
-
* <li> 'proxy_user' - Proxy auth username (string)</li>
|
325 |
-
* <li> 'proxy_password' - Proxy auth password (string)</li>
|
326 |
-
* <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>
|
327 |
-
* <li> 'proxy' - Shorthand for proxy_* parameters, proxy given as URL,
|
328 |
-
* e.g. 'socks5://localhost:1080/' (string)</li>
|
329 |
-
* <li> 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)</li>
|
330 |
-
* <li> 'ssl_verify_host' - Whether to check that Common Name in SSL
|
331 |
-
* certificate matches host name (bool)</li>
|
332 |
-
* <li> 'ssl_cafile' - Cerificate Authority file to verify the peer
|
333 |
-
* with (use with 'ssl_verify_peer') (string)</li>
|
334 |
-
* <li> 'ssl_capath' - Directory holding multiple Certificate
|
335 |
-
* Authority files (string)</li>
|
336 |
-
* <li> 'ssl_local_cert' - Name of a file containing local cerificate (string)</li>
|
337 |
-
* <li> 'ssl_passphrase' - Passphrase with which local certificate
|
338 |
-
* was encoded (string)</li>
|
339 |
-
* <li> 'digest_compat_ie' - Whether to imitate behaviour of MSIE 5 and 6
|
340 |
-
* in using URL without query string in digest
|
341 |
-
* authentication (boolean)</li>
|
342 |
-
* <li> 'follow_redirects' - Whether to automatically follow HTTP Redirects (boolean)</li>
|
343 |
-
* <li> 'max_redirects' - Maximum number of redirects to follow (integer)</li>
|
344 |
-
* <li> 'strict_redirects' - Whether to keep request method on redirects via status 301 and
|
345 |
-
* 302 (true, needed for compatibility with RFC 2616)
|
346 |
-
* or switch to GET (false, needed for compatibility with most
|
347 |
-
* browsers) (boolean)</li>
|
348 |
-
* </ul>
|
349 |
-
*
|
350 |
-
* @param string|array $nameOrConfig configuration parameter name or array
|
351 |
-
* ('parameter name' => 'parameter value')
|
352 |
-
* @param mixed $value parameter value if $nameOrConfig is not an array
|
353 |
-
*
|
354 |
-
* @return HTTP_Request2
|
355 |
-
* @throws HTTP_Request2_LogicException If the parameter is unknown
|
356 |
-
*/
|
357 |
-
public function setConfig($nameOrConfig, $value = null)
|
358 |
-
{
|
359 |
-
if (is_array($nameOrConfig)) {
|
360 |
-
foreach ($nameOrConfig as $name => $value) {
|
361 |
-
$this->setConfig($name, $value);
|
362 |
-
}
|
363 |
-
|
364 |
-
} elseif ('proxy' == $nameOrConfig) {
|
365 |
-
$url = new Net_URL2($value);
|
366 |
-
$this->setConfig(array(
|
367 |
-
'proxy_type' => $url->getScheme(),
|
368 |
-
'proxy_host' => $url->getHost(),
|
369 |
-
'proxy_port' => $url->getPort(),
|
370 |
-
'proxy_user' => rawurldecode($url->getUser()),
|
371 |
-
'proxy_password' => rawurldecode($url->getPassword())
|
372 |
-
));
|
373 |
-
|
374 |
-
} else {
|
375 |
-
if (!array_key_exists($nameOrConfig, $this->config)) {
|
376 |
-
throw new HTTP_Request2_LogicException(
|
377 |
-
"Unknown configuration parameter '{$nameOrConfig}'",
|
378 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
379 |
-
);
|
380 |
-
}
|
381 |
-
$this->config[$nameOrConfig] = $value;
|
382 |
-
}
|
383 |
-
|
384 |
-
return $this;
|
385 |
-
}
|
386 |
-
|
387 |
-
/**
|
388 |
-
* Returns the value(s) of the configuration parameter(s)
|
389 |
-
*
|
390 |
-
* @param string $name parameter name
|
391 |
-
*
|
392 |
-
* @return mixed value of $name parameter, array of all configuration
|
393 |
-
* parameters if $name is not given
|
394 |
-
* @throws HTTP_Request2_LogicException If the parameter is unknown
|
395 |
-
*/
|
396 |
-
public function getConfig($name = null)
|
397 |
-
{
|
398 |
-
if (null === $name) {
|
399 |
-
return $this->config;
|
400 |
-
} elseif (!array_key_exists($name, $this->config)) {
|
401 |
-
throw new HTTP_Request2_LogicException(
|
402 |
-
"Unknown configuration parameter '{$name}'",
|
403 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
404 |
-
);
|
405 |
-
}
|
406 |
-
return $this->config[$name];
|
407 |
-
}
|
408 |
-
|
409 |
-
/**
|
410 |
-
* Sets the autentification data
|
411 |
-
*
|
412 |
-
* @param string $user user name
|
413 |
-
* @param string $password password
|
414 |
-
* @param string $scheme authentication scheme
|
415 |
-
*
|
416 |
-
* @return HTTP_Request2
|
417 |
-
*/
|
418 |
-
public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)
|
419 |
-
{
|
420 |
-
if (empty($user)) {
|
421 |
-
$this->auth = null;
|
422 |
-
} else {
|
423 |
-
$this->auth = array(
|
424 |
-
'user' => (string)$user,
|
425 |
-
'password' => (string)$password,
|
426 |
-
'scheme' => $scheme
|
427 |
-
);
|
428 |
-
}
|
429 |
-
|
430 |
-
return $this;
|
431 |
-
}
|
432 |
-
|
433 |
-
/**
|
434 |
-
* Returns the authentication data
|
435 |
-
*
|
436 |
-
* The array has the keys 'user', 'password' and 'scheme', where 'scheme'
|
437 |
-
* is one of the HTTP_Request2::AUTH_* constants.
|
438 |
-
*
|
439 |
-
* @return array
|
440 |
-
*/
|
441 |
-
public function getAuth()
|
442 |
-
{
|
443 |
-
return $this->auth;
|
444 |
-
}
|
445 |
-
|
446 |
-
/**
|
447 |
-
* Sets request header(s)
|
448 |
-
*
|
449 |
-
* The first parameter may be either a full header string 'header: value' or
|
450 |
-
* header name. In the former case $value parameter is ignored, in the latter
|
451 |
-
* the header's value will either be set to $value or the header will be
|
452 |
-
* removed if $value is null. The first parameter can also be an array of
|
453 |
-
* headers, in that case method will be called recursively.
|
454 |
-
*
|
455 |
-
* Note that headers are treated case insensitively as per RFC 2616.
|
456 |
-
*
|
457 |
-
* <code>
|
458 |
-
* $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'
|
459 |
-
* $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'
|
460 |
-
* $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'
|
461 |
-
* $req->setHeader('FOO'); // removes 'Foo' header from request
|
462 |
-
* </code>
|
463 |
-
*
|
464 |
-
* @param string|array $name header name, header string ('Header: value')
|
465 |
-
* or an array of headers
|
466 |
-
* @param string|array|null $value header value if $name is not an array,
|
467 |
-
* header will be removed if value is null
|
468 |
-
* @param bool $replace whether to replace previous header with the
|
469 |
-
* same name or append to its value
|
470 |
-
*
|
471 |
-
* @return HTTP_Request2
|
472 |
-
* @throws HTTP_Request2_LogicException
|
473 |
-
*/
|
474 |
-
public function setHeader($name, $value = null, $replace = true)
|
475 |
-
{
|
476 |
-
if (is_array($name)) {
|
477 |
-
foreach ($name as $k => $v) {
|
478 |
-
if (is_string($k)) {
|
479 |
-
$this->setHeader($k, $v, $replace);
|
480 |
-
} else {
|
481 |
-
$this->setHeader($v, null, $replace);
|
482 |
-
}
|
483 |
-
}
|
484 |
-
} else {
|
485 |
-
if (null === $value && strpos($name, ':')) {
|
486 |
-
list($name, $value) = array_map('trim', explode(':', $name, 2));
|
487 |
-
}
|
488 |
-
// Header name should be a token: http://tools.ietf.org/html/rfc2616#section-4.2
|
489 |
-
if (preg_match(self::REGEXP_INVALID_TOKEN, $name)) {
|
490 |
-
throw new HTTP_Request2_LogicException(
|
491 |
-
"Invalid header name '{$name}'",
|
492 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
493 |
-
);
|
494 |
-
}
|
495 |
-
// Header names are case insensitive anyway
|
496 |
-
$name = strtolower($name);
|
497 |
-
if (null === $value) {
|
498 |
-
unset($this->headers[$name]);
|
499 |
-
|
500 |
-
} else {
|
501 |
-
if (is_array($value)) {
|
502 |
-
$value = implode(', ', array_map('trim', $value));
|
503 |
-
} elseif (is_string($value)) {
|
504 |
-
$value = trim($value);
|
505 |
-
}
|
506 |
-
if (!isset($this->headers[$name]) || $replace) {
|
507 |
-
$this->headers[$name] = $value;
|
508 |
-
} else {
|
509 |
-
$this->headers[$name] .= ', ' . $value;
|
510 |
-
}
|
511 |
-
}
|
512 |
-
}
|
513 |
-
|
514 |
-
return $this;
|
515 |
-
}
|
516 |
-
|
517 |
-
/**
|
518 |
-
* Returns the request headers
|
519 |
-
*
|
520 |
-
* The array is of the form ('header name' => 'header value'), header names
|
521 |
-
* are lowercased
|
522 |
-
*
|
523 |
-
* @return array
|
524 |
-
*/
|
525 |
-
public function getHeaders()
|
526 |
-
{
|
527 |
-
return $this->headers;
|
528 |
-
}
|
529 |
-
|
530 |
-
/**
|
531 |
-
* Adds a cookie to the request
|
532 |
-
*
|
533 |
-
* If the request does not have a CookieJar object set, this method simply
|
534 |
-
* appends a cookie to "Cookie:" header.
|
535 |
-
*
|
536 |
-
* If a CookieJar object is available, the cookie is stored in that object.
|
537 |
-
* Data from request URL will be used for setting its 'domain' and 'path'
|
538 |
-
* parameters, 'expires' and 'secure' will be set to null and false,
|
539 |
-
* respectively. If you need further control, use CookieJar's methods.
|
540 |
-
*
|
541 |
-
* @param string $name cookie name
|
542 |
-
* @param string $value cookie value
|
543 |
-
*
|
544 |
-
* @return HTTP_Request2
|
545 |
-
* @throws HTTP_Request2_LogicException
|
546 |
-
* @see setCookieJar()
|
547 |
-
*/
|
548 |
-
public function addCookie($name, $value)
|
549 |
-
{
|
550 |
-
if (!empty($this->cookieJar)) {
|
551 |
-
$this->cookieJar->store(
|
552 |
-
array('name' => $name, 'value' => $value), $this->url
|
553 |
-
);
|
554 |
-
|
555 |
-
} else {
|
556 |
-
$cookie = $name . '=' . $value;
|
557 |
-
if (preg_match(self::REGEXP_INVALID_COOKIE, $cookie)) {
|
558 |
-
throw new HTTP_Request2_LogicException(
|
559 |
-
"Invalid cookie: '{$cookie}'",
|
560 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
561 |
-
);
|
562 |
-
}
|
563 |
-
$cookies = empty($this->headers['cookie'])? '': $this->headers['cookie'] . '; ';
|
564 |
-
$this->setHeader('cookie', $cookies . $cookie);
|
565 |
-
}
|
566 |
-
|
567 |
-
return $this;
|
568 |
-
}
|
569 |
-
|
570 |
-
/**
|
571 |
-
* Sets the request body
|
572 |
-
*
|
573 |
-
* If you provide file pointer rather than file name, it should support
|
574 |
-
* fstat() and rewind() operations.
|
575 |
-
*
|
576 |
-
* @param string|resource|HTTP_Request2_MultipartBody $body Either a
|
577 |
-
* string with the body or filename containing body or
|
578 |
-
* pointer to an open file or object with multipart body data
|
579 |
-
* @param bool $isFilename Whether
|
580 |
-
* first parameter is a filename
|
581 |
-
*
|
582 |
-
* @return HTTP_Request2
|
583 |
-
* @throws HTTP_Request2_LogicException
|
584 |
-
*/
|
585 |
-
public function setBody($body, $isFilename = false)
|
586 |
-
{
|
587 |
-
if (!$isFilename && !is_resource($body)) {
|
588 |
-
if (!$body instanceof HTTP_Request2_MultipartBody) {
|
589 |
-
$this->body = (string)$body;
|
590 |
-
} else {
|
591 |
-
$this->body = $body;
|
592 |
-
}
|
593 |
-
} else {
|
594 |
-
$fileData = $this->fopenWrapper($body, empty($this->headers['content-type']));
|
595 |
-
$this->body = $fileData['fp'];
|
596 |
-
if (empty($this->headers['content-type'])) {
|
597 |
-
$this->setHeader('content-type', $fileData['type']);
|
598 |
-
}
|
599 |
-
}
|
600 |
-
$this->postParams = $this->uploads = array();
|
601 |
-
|
602 |
-
return $this;
|
603 |
-
}
|
604 |
-
|
605 |
-
/**
|
606 |
-
* Returns the request body
|
607 |
-
*
|
608 |
-
* @return string|resource|HTTP_Request2_MultipartBody
|
609 |
-
*/
|
610 |
-
public function getBody()
|
611 |
-
{
|
612 |
-
if (self::METHOD_POST == $this->method
|
613 |
-
&& (!empty($this->postParams) || !empty($this->uploads))
|
614 |
-
) {
|
615 |
-
if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
|
616 |
-
$body = http_build_query($this->postParams, '', '&');
|
617 |
-
if (!$this->getConfig('use_brackets')) {
|
618 |
-
$body = preg_replace('/%5B\d+%5D=/', '=', $body);
|
619 |
-
}
|
620 |
-
// support RFC 3986 by not encoding '~' symbol (request #15368)
|
621 |
-
return str_replace('%7E', '~', $body);
|
622 |
-
|
623 |
-
} elseif (0 === strpos($this->headers['content-type'], 'multipart/form-data')) {
|
624 |
-
require_once 'HTTP/Request2/MultipartBody.php';
|
625 |
-
return new HTTP_Request2_MultipartBody(
|
626 |
-
$this->postParams, $this->uploads, $this->getConfig('use_brackets')
|
627 |
-
);
|
628 |
-
}
|
629 |
-
}
|
630 |
-
return $this->body;
|
631 |
-
}
|
632 |
-
|
633 |
-
/**
|
634 |
-
* Adds a file to form-based file upload
|
635 |
-
*
|
636 |
-
* Used to emulate file upload via a HTML form. The method also sets
|
637 |
-
* Content-Type of HTTP request to 'multipart/form-data'.
|
638 |
-
*
|
639 |
-
* If you just want to send the contents of a file as the body of HTTP
|
640 |
-
* request you should use setBody() method.
|
641 |
-
*
|
642 |
-
* If you provide file pointers rather than file names, they should support
|
643 |
-
* fstat() and rewind() operations.
|
644 |
-
*
|
645 |
-
* @param string $fieldName name of file-upload field
|
646 |
-
* @param string|resource|array $filename full name of local file,
|
647 |
-
* pointer to open file or an array of files
|
648 |
-
* @param string $sendFilename filename to send in the request
|
649 |
-
* @param string $contentType content-type of file being uploaded
|
650 |
-
*
|
651 |
-
* @return HTTP_Request2
|
652 |
-
* @throws HTTP_Request2_LogicException
|
653 |
-
*/
|
654 |
-
public function addUpload(
|
655 |
-
$fieldName, $filename, $sendFilename = null, $contentType = null
|
656 |
-
) {
|
657 |
-
if (!is_array($filename)) {
|
658 |
-
$fileData = $this->fopenWrapper($filename, empty($contentType));
|
659 |
-
$this->uploads[$fieldName] = array(
|
660 |
-
'fp' => $fileData['fp'],
|
661 |
-
'filename' => !empty($sendFilename)? $sendFilename
|
662 |
-
:(is_string($filename)? basename($filename): 'anonymous.blob') ,
|
663 |
-
'size' => $fileData['size'],
|
664 |
-
'type' => empty($contentType)? $fileData['type']: $contentType
|
665 |
-
);
|
666 |
-
} else {
|
667 |
-
$fps = $names = $sizes = $types = array();
|
668 |
-
foreach ($filename as $f) {
|
669 |
-
if (!is_array($f)) {
|
670 |
-
$f = array($f);
|
671 |
-
}
|
672 |
-
$fileData = $this->fopenWrapper($f[0], empty($f[2]));
|
673 |
-
$fps[] = $fileData['fp'];
|
674 |
-
$names[] = !empty($f[1])? $f[1]
|
675 |
-
:(is_string($f[0])? basename($f[0]): 'anonymous.blob');
|
676 |
-
$sizes[] = $fileData['size'];
|
677 |
-
$types[] = empty($f[2])? $fileData['type']: $f[2];
|
678 |
-
}
|
679 |
-
$this->uploads[$fieldName] = array(
|
680 |
-
'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
|
681 |
-
);
|
682 |
-
}
|
683 |
-
if (empty($this->headers['content-type'])
|
684 |
-
|| 'application/x-www-form-urlencoded' == $this->headers['content-type']
|
685 |
-
) {
|
686 |
-
$this->setHeader('content-type', 'multipart/form-data');
|
687 |
-
}
|
688 |
-
|
689 |
-
return $this;
|
690 |
-
}
|
691 |
-
|
692 |
-
/**
|
693 |
-
* Adds POST parameter(s) to the request.
|
694 |
-
*
|
695 |
-
* @param string|array $name parameter name or array ('name' => 'value')
|
696 |
-
* @param mixed $value parameter value (can be an array)
|
697 |
-
*
|
698 |
-
* @return HTTP_Request2
|
699 |
-
*/
|
700 |
-
public function addPostParameter($name, $value = null)
|
701 |
-
{
|
702 |
-
if (!is_array($name)) {
|
703 |
-
$this->postParams[$name] = $value;
|
704 |
-
} else {
|
705 |
-
foreach ($name as $k => $v) {
|
706 |
-
$this->addPostParameter($k, $v);
|
707 |
-
}
|
708 |
-
}
|
709 |
-
if (empty($this->headers['content-type'])) {
|
710 |
-
$this->setHeader('content-type', 'application/x-www-form-urlencoded');
|
711 |
-
}
|
712 |
-
|
713 |
-
return $this;
|
714 |
-
}
|
715 |
-
|
716 |
-
/**
|
717 |
-
* Attaches a new observer
|
718 |
-
*
|
719 |
-
* @param SplObserver $observer any object implementing SplObserver
|
720 |
-
*/
|
721 |
-
public function attach(SplObserver $observer)
|
722 |
-
{
|
723 |
-
foreach ($this->observers as $attached) {
|
724 |
-
if ($attached === $observer) {
|
725 |
-
return;
|
726 |
-
}
|
727 |
-
}
|
728 |
-
$this->observers[] = $observer;
|
729 |
-
}
|
730 |
-
|
731 |
-
/**
|
732 |
-
* Detaches an existing observer
|
733 |
-
*
|
734 |
-
* @param SplObserver $observer any object implementing SplObserver
|
735 |
-
*/
|
736 |
-
public function detach(SplObserver $observer)
|
737 |
-
{
|
738 |
-
foreach ($this->observers as $key => $attached) {
|
739 |
-
if ($attached === $observer) {
|
740 |
-
unset($this->observers[$key]);
|
741 |
-
return;
|
742 |
-
}
|
743 |
-
}
|
744 |
-
}
|
745 |
-
|
746 |
-
/**
|
747 |
-
* Notifies all observers
|
748 |
-
*/
|
749 |
-
public function notify()
|
750 |
-
{
|
751 |
-
foreach ($this->observers as $observer) {
|
752 |
-
$observer->update($this);
|
753 |
-
}
|
754 |
-
}
|
755 |
-
|
756 |
-
/**
|
757 |
-
* Sets the last event
|
758 |
-
*
|
759 |
-
* Adapters should use this method to set the current state of the request
|
760 |
-
* and notify the observers.
|
761 |
-
*
|
762 |
-
* @param string $name event name
|
763 |
-
* @param mixed $data event data
|
764 |
-
*/
|
765 |
-
public function setLastEvent($name, $data = null)
|
766 |
-
{
|
767 |
-
$this->lastEvent = array(
|
768 |
-
'name' => $name,
|
769 |
-
'data' => $data
|
770 |
-
);
|
771 |
-
$this->notify();
|
772 |
-
}
|
773 |
-
|
774 |
-
/**
|
775 |
-
* Returns the last event
|
776 |
-
*
|
777 |
-
* Observers should use this method to access the last change in request.
|
778 |
-
* The following event names are possible:
|
779 |
-
* <ul>
|
780 |
-
* <li>'connect' - after connection to remote server,
|
781 |
-
* data is the destination (string)</li>
|
782 |
-
* <li>'disconnect' - after disconnection from server</li>
|
783 |
-
* <li>'sentHeaders' - after sending the request headers,
|
784 |
-
* data is the headers sent (string)</li>
|
785 |
-
* <li>'sentBodyPart' - after sending a part of the request body,
|
786 |
-
* data is the length of that part (int)</li>
|
787 |
-
* <li>'sentBody' - after sending the whole request body,
|
788 |
-
* data is request body length (int)</li>
|
789 |
-
* <li>'receivedHeaders' - after receiving the response headers,
|
790 |
-
* data is HTTP_Request2_Response object</li>
|
791 |
-
* <li>'receivedBodyPart' - after receiving a part of the response
|
792 |
-
* body, data is that part (string)</li>
|
793 |
-
* <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still
|
794 |
-
* encoded by Content-Encoding</li>
|
795 |
-
* <li>'receivedBody' - after receiving the complete response
|
796 |
-
* body, data is HTTP_Request2_Response object</li>
|
797 |
-
* </ul>
|
798 |
-
* Different adapters may not send all the event types. Mock adapter does
|
799 |
-
* not send any events to the observers.
|
800 |
-
*
|
801 |
-
* @return array The array has two keys: 'name' and 'data'
|
802 |
-
*/
|
803 |
-
public function getLastEvent()
|
804 |
-
{
|
805 |
-
return $this->lastEvent;
|
806 |
-
}
|
807 |
-
|
808 |
-
/**
|
809 |
-
* Sets the adapter used to actually perform the request
|
810 |
-
*
|
811 |
-
* You can pass either an instance of a class implementing HTTP_Request2_Adapter
|
812 |
-
* or a class name. The method will only try to include a file if the class
|
813 |
-
* name starts with HTTP_Request2_Adapter_, it will also try to prepend this
|
814 |
-
* prefix to the class name if it doesn't contain any underscores, so that
|
815 |
-
* <code>
|
816 |
-
* $request->setAdapter('curl');
|
817 |
-
* </code>
|
818 |
-
* will work.
|
819 |
-
*
|
820 |
-
* @param string|HTTP_Request2_Adapter $adapter Adapter to use
|
821 |
-
*
|
822 |
-
* @return HTTP_Request2
|
823 |
-
* @throws HTTP_Request2_LogicException
|
824 |
-
*/
|
825 |
-
public function setAdapter($adapter)
|
826 |
-
{
|
827 |
-
if (is_string($adapter)) {
|
828 |
-
if (!class_exists($adapter, false)) {
|
829 |
-
if (false === strpos($adapter, '_')) {
|
830 |
-
$adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
|
831 |
-
}
|
832 |
-
if (!class_exists($adapter, false)
|
833 |
-
&& preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)
|
834 |
-
) {
|
835 |
-
include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
|
836 |
-
}
|
837 |
-
if (!class_exists($adapter, false)) {
|
838 |
-
throw new HTTP_Request2_LogicException(
|
839 |
-
"Class {$adapter} not found",
|
840 |
-
HTTP_Request2_Exception::MISSING_VALUE
|
841 |
-
);
|
842 |
-
}
|
843 |
-
}
|
844 |
-
$adapter = new $adapter;
|
845 |
-
}
|
846 |
-
if (!$adapter instanceof HTTP_Request2_Adapter) {
|
847 |
-
throw new HTTP_Request2_LogicException(
|
848 |
-
'Parameter is not a HTTP request adapter',
|
849 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
850 |
-
);
|
851 |
-
}
|
852 |
-
$this->adapter = $adapter;
|
853 |
-
|
854 |
-
return $this;
|
855 |
-
}
|
856 |
-
|
857 |
-
/**
|
858 |
-
* Sets the cookie jar
|
859 |
-
*
|
860 |
-
* A cookie jar is used to maintain cookies across HTTP requests and
|
861 |
-
* responses. Cookies from jar will be automatically added to the request
|
862 |
-
* headers based on request URL.
|
863 |
-
*
|
864 |
-
* @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to
|
865 |
-
* create a new one, false to remove
|
866 |
-
*
|
867 |
-
* @return HTTP_Request2
|
868 |
-
* @throws HTTP_Request2_LogicException
|
869 |
-
*/
|
870 |
-
public function setCookieJar($jar = true)
|
871 |
-
{
|
872 |
-
if (!class_exists('HTTP_Request2_CookieJar', false)) {
|
873 |
-
require_once 'HTTP/Request2/CookieJar.php';
|
874 |
-
}
|
875 |
-
|
876 |
-
if ($jar instanceof HTTP_Request2_CookieJar) {
|
877 |
-
$this->cookieJar = $jar;
|
878 |
-
} elseif (true === $jar) {
|
879 |
-
$this->cookieJar = new HTTP_Request2_CookieJar();
|
880 |
-
} elseif (!$jar) {
|
881 |
-
$this->cookieJar = null;
|
882 |
-
} else {
|
883 |
-
throw new HTTP_Request2_LogicException(
|
884 |
-
'Invalid parameter passed to setCookieJar()',
|
885 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
886 |
-
);
|
887 |
-
}
|
888 |
-
|
889 |
-
return $this;
|
890 |
-
}
|
891 |
-
|
892 |
-
/**
|
893 |
-
* Returns current CookieJar object or null if none
|
894 |
-
*
|
895 |
-
* @return HTTP_Request2_CookieJar|null
|
896 |
-
*/
|
897 |
-
public function getCookieJar()
|
898 |
-
{
|
899 |
-
return $this->cookieJar;
|
900 |
-
}
|
901 |
-
|
902 |
-
/**
|
903 |
-
* Sends the request and returns the response
|
904 |
-
*
|
905 |
-
* @throws HTTP_Request2_Exception
|
906 |
-
* @return HTTP_Request2_Response
|
907 |
-
*/
|
908 |
-
public function send()
|
909 |
-
{
|
910 |
-
// Sanity check for URL
|
911 |
-
if (!$this->url instanceof Net_URL2
|
912 |
-
|| !$this->url->isAbsolute()
|
913 |
-
|| !in_array(strtolower($this->url->getScheme()), array('https', 'http'))
|
914 |
-
) {
|
915 |
-
throw new HTTP_Request2_LogicException(
|
916 |
-
'HTTP_Request2 needs an absolute HTTP(S) request URL, '
|
917 |
-
. ($this->url instanceof Net_URL2
|
918 |
-
? "'" . $this->url->__toString() . "'" : 'none')
|
919 |
-
. ' given',
|
920 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
921 |
-
);
|
922 |
-
}
|
923 |
-
if (empty($this->adapter)) {
|
924 |
-
$this->setAdapter($this->getConfig('adapter'));
|
925 |
-
}
|
926 |
-
// magic_quotes_runtime may break file uploads and chunked response
|
927 |
-
// processing; see bug #4543. Don't use ini_get() here; see bug #16440.
|
928 |
-
if ($magicQuotes = get_magic_quotes_runtime()) {
|
929 |
-
set_magic_quotes_runtime(false);
|
930 |
-
}
|
931 |
-
// force using single byte encoding if mbstring extension overloads
|
932 |
-
// strlen() and substr(); see bug #1781, bug #10605
|
933 |
-
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
|
934 |
-
$oldEncoding = mb_internal_encoding();
|
935 |
-
mb_internal_encoding('8bit');
|
936 |
-
}
|
937 |
-
|
938 |
-
try {
|
939 |
-
$response = $this->adapter->sendRequest($this);
|
940 |
-
} catch (Exception $e) {
|
941 |
-
}
|
942 |
-
// cleanup in either case (poor man's "finally" clause)
|
943 |
-
if ($magicQuotes) {
|
944 |
-
set_magic_quotes_runtime(true);
|
945 |
-
}
|
946 |
-
if (!empty($oldEncoding)) {
|
947 |
-
mb_internal_encoding($oldEncoding);
|
948 |
-
}
|
949 |
-
// rethrow the exception
|
950 |
-
if (!empty($e)) {
|
951 |
-
throw $e;
|
952 |
-
}
|
953 |
-
return $response;
|
954 |
-
}
|
955 |
-
|
956 |
-
/**
|
957 |
-
* Wrapper around fopen()/fstat() used by setBody() and addUpload()
|
958 |
-
*
|
959 |
-
* @param string|resource $file file name or pointer to open file
|
960 |
-
* @param bool $detectType whether to try autodetecting MIME
|
961 |
-
* type of file, will only work if $file is a
|
962 |
-
* filename, not pointer
|
963 |
-
*
|
964 |
-
* @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)
|
965 |
-
* @throws HTTP_Request2_LogicException
|
966 |
-
*/
|
967 |
-
protected function fopenWrapper($file, $detectType = false)
|
968 |
-
{
|
969 |
-
if (!is_string($file) && !is_resource($file)) {
|
970 |
-
throw new HTTP_Request2_LogicException(
|
971 |
-
"Filename or file pointer resource expected",
|
972 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
973 |
-
);
|
974 |
-
}
|
975 |
-
$fileData = array(
|
976 |
-
'fp' => is_string($file)? null: $file,
|
977 |
-
'type' => 'application/octet-stream',
|
978 |
-
'size' => 0
|
979 |
-
);
|
980 |
-
if (is_string($file)) {
|
981 |
-
if (!($fileData['fp'] = @fopen($file, 'rb'))) {
|
982 |
-
$error = error_get_last();
|
983 |
-
throw new HTTP_Request2_LogicException(
|
984 |
-
$error['message'], HTTP_Request2_Exception::READ_ERROR
|
985 |
-
);
|
986 |
-
}
|
987 |
-
if ($detectType) {
|
988 |
-
$fileData['type'] = self::detectMimeType($file);
|
989 |
-
}
|
990 |
-
}
|
991 |
-
if (!($stat = fstat($fileData['fp']))) {
|
992 |
-
throw new HTTP_Request2_LogicException(
|
993 |
-
"fstat() call failed", HTTP_Request2_Exception::READ_ERROR
|
994 |
-
);
|
995 |
-
}
|
996 |
-
$fileData['size'] = $stat['size'];
|
997 |
-
|
998 |
-
return $fileData;
|
999 |
-
}
|
1000 |
-
|
1001 |
-
/**
|
1002 |
-
* Tries to detect MIME type of a file
|
1003 |
-
*
|
1004 |
-
* The method will try to use fileinfo extension if it is available,
|
1005 |
-
* deprecated mime_content_type() function in the other case. If neither
|
1006 |
-
* works, default 'application/octet-stream' MIME type is returned
|
1007 |
-
*
|
1008 |
-
* @param string $filename file name
|
1009 |
-
*
|
1010 |
-
* @return string file MIME type
|
1011 |
-
*/
|
1012 |
-
protected static function detectMimeType($filename)
|
1013 |
-
{
|
1014 |
-
// finfo extension from PECL available
|
1015 |
-
if (function_exists('finfo_open')) {
|
1016 |
-
if (!isset(self::$_fileinfoDb)) {
|
1017 |
-
self::$_fileinfoDb = @finfo_open(FILEINFO_MIME);
|
1018 |
-
}
|
1019 |
-
if (self::$_fileinfoDb) {
|
1020 |
-
$info = finfo_file(self::$_fileinfoDb, $filename);
|
1021 |
-
}
|
1022 |
-
}
|
1023 |
-
// (deprecated) mime_content_type function available
|
1024 |
-
if (empty($info) && function_exists('mime_content_type')) {
|
1025 |
-
return mime_content_type($filename);
|
1026 |
-
}
|
1027 |
-
return empty($info)? 'application/octet-stream': $info;
|
1028 |
-
}
|
1029 |
-
}
|
1030 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class representing a HTTP request message
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/**
|
22 |
+
* A class representing an URL as per RFC 3986.
|
23 |
+
*/
|
24 |
+
require_once 'Net/URL2.php';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Exception class for HTTP_Request2 package
|
28 |
+
*/
|
29 |
+
require_once 'HTTP/Request2/Exception.php';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Class representing a HTTP request message
|
33 |
+
*
|
34 |
+
* @category HTTP
|
35 |
+
* @package HTTP_Request2
|
36 |
+
* @author Alexey Borzov <avb@php.net>
|
37 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
38 |
+
* @version Release: 2.2.1
|
39 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
40 |
+
* @link http://tools.ietf.org/html/rfc2616#section-5
|
41 |
+
*/
|
42 |
+
class HTTP_Request2 implements SplSubject
|
43 |
+
{
|
44 |
+
/**#@+
|
45 |
+
* Constants for HTTP request methods
|
46 |
+
*
|
47 |
+
* @link http://tools.ietf.org/html/rfc2616#section-5.1.1
|
48 |
+
*/
|
49 |
+
const METHOD_OPTIONS = 'OPTIONS';
|
50 |
+
const METHOD_GET = 'GET';
|
51 |
+
const METHOD_HEAD = 'HEAD';
|
52 |
+
const METHOD_POST = 'POST';
|
53 |
+
const METHOD_PUT = 'PUT';
|
54 |
+
const METHOD_DELETE = 'DELETE';
|
55 |
+
const METHOD_TRACE = 'TRACE';
|
56 |
+
const METHOD_CONNECT = 'CONNECT';
|
57 |
+
/**#@-*/
|
58 |
+
|
59 |
+
/**#@+
|
60 |
+
* Constants for HTTP authentication schemes
|
61 |
+
*
|
62 |
+
* @link http://tools.ietf.org/html/rfc2617
|
63 |
+
*/
|
64 |
+
const AUTH_BASIC = 'basic';
|
65 |
+
const AUTH_DIGEST = 'digest';
|
66 |
+
/**#@-*/
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Regular expression used to check for invalid symbols in RFC 2616 tokens
|
70 |
+
* @link http://pear.php.net/bugs/bug.php?id=15630
|
71 |
+
*/
|
72 |
+
const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!';
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Regular expression used to check for invalid symbols in cookie strings
|
76 |
+
* @link http://pear.php.net/bugs/bug.php?id=15630
|
77 |
+
* @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
|
78 |
+
*/
|
79 |
+
const REGEXP_INVALID_COOKIE = '/[\s,;]/';
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Fileinfo magic database resource
|
83 |
+
* @var resource
|
84 |
+
* @see detectMimeType()
|
85 |
+
*/
|
86 |
+
private static $_fileinfoDb;
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Observers attached to the request (instances of SplObserver)
|
90 |
+
* @var array
|
91 |
+
*/
|
92 |
+
protected $observers = array();
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Request URL
|
96 |
+
* @var Net_URL2
|
97 |
+
*/
|
98 |
+
protected $url;
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Request method
|
102 |
+
* @var string
|
103 |
+
*/
|
104 |
+
protected $method = self::METHOD_GET;
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Authentication data
|
108 |
+
* @var array
|
109 |
+
* @see getAuth()
|
110 |
+
*/
|
111 |
+
protected $auth;
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Request headers
|
115 |
+
* @var array
|
116 |
+
*/
|
117 |
+
protected $headers = array();
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Configuration parameters
|
121 |
+
* @var array
|
122 |
+
* @see setConfig()
|
123 |
+
*/
|
124 |
+
protected $config = array(
|
125 |
+
'adapter' => 'HTTP_Request2_Adapter_Socket',
|
126 |
+
'connect_timeout' => 10,
|
127 |
+
'timeout' => 0,
|
128 |
+
'use_brackets' => true,
|
129 |
+
'protocol_version' => '1.1',
|
130 |
+
'buffer_size' => 16384,
|
131 |
+
'store_body' => true,
|
132 |
+
'local_ip' => null,
|
133 |
+
|
134 |
+
'proxy_host' => '',
|
135 |
+
'proxy_port' => '',
|
136 |
+
'proxy_user' => '',
|
137 |
+
'proxy_password' => '',
|
138 |
+
'proxy_auth_scheme' => self::AUTH_BASIC,
|
139 |
+
'proxy_type' => 'http',
|
140 |
+
|
141 |
+
'ssl_verify_peer' => true,
|
142 |
+
'ssl_verify_host' => true,
|
143 |
+
'ssl_cafile' => null,
|
144 |
+
'ssl_capath' => null,
|
145 |
+
'ssl_local_cert' => null,
|
146 |
+
'ssl_passphrase' => null,
|
147 |
+
|
148 |
+
'digest_compat_ie' => false,
|
149 |
+
|
150 |
+
'follow_redirects' => false,
|
151 |
+
'max_redirects' => 5,
|
152 |
+
'strict_redirects' => false
|
153 |
+
);
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Last event in request / response handling, intended for observers
|
157 |
+
* @var array
|
158 |
+
* @see getLastEvent()
|
159 |
+
*/
|
160 |
+
protected $lastEvent = array(
|
161 |
+
'name' => 'start',
|
162 |
+
'data' => null
|
163 |
+
);
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Request body
|
167 |
+
* @var string|resource
|
168 |
+
* @see setBody()
|
169 |
+
*/
|
170 |
+
protected $body = '';
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Array of POST parameters
|
174 |
+
* @var array
|
175 |
+
*/
|
176 |
+
protected $postParams = array();
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Array of file uploads (for multipart/form-data POST requests)
|
180 |
+
* @var array
|
181 |
+
*/
|
182 |
+
protected $uploads = array();
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Adapter used to perform actual HTTP request
|
186 |
+
* @var HTTP_Request2_Adapter
|
187 |
+
*/
|
188 |
+
protected $adapter;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Cookie jar to persist cookies between requests
|
192 |
+
* @var HTTP_Request2_CookieJar
|
193 |
+
*/
|
194 |
+
protected $cookieJar = null;
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Constructor. Can set request URL, method and configuration array.
|
198 |
+
*
|
199 |
+
* Also sets a default value for User-Agent header.
|
200 |
+
*
|
201 |
+
* @param string|Net_Url2 $url Request URL
|
202 |
+
* @param string $method Request method
|
203 |
+
* @param array $config Configuration for this Request instance
|
204 |
+
*/
|
205 |
+
public function __construct(
|
206 |
+
$url = null, $method = self::METHOD_GET, array $config = array()
|
207 |
+
) {
|
208 |
+
$this->setConfig($config);
|
209 |
+
if (!empty($url)) {
|
210 |
+
$this->setUrl($url);
|
211 |
+
}
|
212 |
+
if (!empty($method)) {
|
213 |
+
$this->setMethod($method);
|
214 |
+
}
|
215 |
+
$this->setHeader(
|
216 |
+
'user-agent', 'HTTP_Request2/2.2.1 ' .
|
217 |
+
'(http://pear.php.net/package/http_request2) PHP/' . phpversion()
|
218 |
+
);
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Sets the URL for this request
|
223 |
+
*
|
224 |
+
* If the URL has userinfo part (username & password) these will be removed
|
225 |
+
* and converted to auth data. If the URL does not have a path component,
|
226 |
+
* that will be set to '/'.
|
227 |
+
*
|
228 |
+
* @param string|Net_URL2 $url Request URL
|
229 |
+
*
|
230 |
+
* @return HTTP_Request2
|
231 |
+
* @throws HTTP_Request2_LogicException
|
232 |
+
*/
|
233 |
+
public function setUrl($url)
|
234 |
+
{
|
235 |
+
if (is_string($url)) {
|
236 |
+
$url = new Net_URL2(
|
237 |
+
$url, array(Net_URL2::OPTION_USE_BRACKETS => $this->config['use_brackets'])
|
238 |
+
);
|
239 |
+
}
|
240 |
+
if (!$url instanceof Net_URL2) {
|
241 |
+
throw new HTTP_Request2_LogicException(
|
242 |
+
'Parameter is not a valid HTTP URL',
|
243 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
244 |
+
);
|
245 |
+
}
|
246 |
+
// URL contains username / password?
|
247 |
+
if ($url->getUserinfo()) {
|
248 |
+
$username = $url->getUser();
|
249 |
+
$password = $url->getPassword();
|
250 |
+
$this->setAuth(rawurldecode($username), $password? rawurldecode($password): '');
|
251 |
+
$url->setUserinfo('');
|
252 |
+
}
|
253 |
+
if ('' == $url->getPath()) {
|
254 |
+
$url->setPath('/');
|
255 |
+
}
|
256 |
+
$this->url = $url;
|
257 |
+
|
258 |
+
return $this;
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* Returns the request URL
|
263 |
+
*
|
264 |
+
* @return Net_URL2
|
265 |
+
*/
|
266 |
+
public function getUrl()
|
267 |
+
{
|
268 |
+
return $this->url;
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Sets the request method
|
273 |
+
*
|
274 |
+
* @param string $method one of the methods defined in RFC 2616
|
275 |
+
*
|
276 |
+
* @return HTTP_Request2
|
277 |
+
* @throws HTTP_Request2_LogicException if the method name is invalid
|
278 |
+
*/
|
279 |
+
public function setMethod($method)
|
280 |
+
{
|
281 |
+
// Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1
|
282 |
+
if (preg_match(self::REGEXP_INVALID_TOKEN, $method)) {
|
283 |
+
throw new HTTP_Request2_LogicException(
|
284 |
+
"Invalid request method '{$method}'",
|
285 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
286 |
+
);
|
287 |
+
}
|
288 |
+
$this->method = $method;
|
289 |
+
|
290 |
+
return $this;
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Returns the request method
|
295 |
+
*
|
296 |
+
* @return string
|
297 |
+
*/
|
298 |
+
public function getMethod()
|
299 |
+
{
|
300 |
+
return $this->method;
|
301 |
+
}
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Sets the configuration parameter(s)
|
305 |
+
*
|
306 |
+
* The following parameters are available:
|
307 |
+
* <ul>
|
308 |
+
* <li> 'adapter' - adapter to use (string)</li>
|
309 |
+
* <li> 'connect_timeout' - Connection timeout in seconds (integer)</li>
|
310 |
+
* <li> 'timeout' - Total number of seconds a request can take.
|
311 |
+
* Use 0 for no limit, should be greater than
|
312 |
+
* 'connect_timeout' if set (integer)</li>
|
313 |
+
* <li> 'use_brackets' - Whether to append [] to array variable names (bool)</li>
|
314 |
+
* <li> 'protocol_version' - HTTP Version to use, '1.0' or '1.1' (string)</li>
|
315 |
+
* <li> 'buffer_size' - Buffer size to use for reading and writing (int)</li>
|
316 |
+
* <li> 'store_body' - Whether to store response body in response object.
|
317 |
+
* Set to false if receiving a huge response and
|
318 |
+
* using an Observer to save it (boolean)</li>
|
319 |
+
* <li> 'local_ip' - Specifies the IP address that will be used for accessing
|
320 |
+
* the network (string)</li>
|
321 |
+
* <li> 'proxy_type' - Proxy type, 'http' or 'socks5' (string)</li>
|
322 |
+
* <li> 'proxy_host' - Proxy server host (string)</li>
|
323 |
+
* <li> 'proxy_port' - Proxy server port (integer)</li>
|
324 |
+
* <li> 'proxy_user' - Proxy auth username (string)</li>
|
325 |
+
* <li> 'proxy_password' - Proxy auth password (string)</li>
|
326 |
+
* <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>
|
327 |
+
* <li> 'proxy' - Shorthand for proxy_* parameters, proxy given as URL,
|
328 |
+
* e.g. 'socks5://localhost:1080/' (string)</li>
|
329 |
+
* <li> 'ssl_verify_peer' - Whether to verify peer's SSL certificate (bool)</li>
|
330 |
+
* <li> 'ssl_verify_host' - Whether to check that Common Name in SSL
|
331 |
+
* certificate matches host name (bool)</li>
|
332 |
+
* <li> 'ssl_cafile' - Cerificate Authority file to verify the peer
|
333 |
+
* with (use with 'ssl_verify_peer') (string)</li>
|
334 |
+
* <li> 'ssl_capath' - Directory holding multiple Certificate
|
335 |
+
* Authority files (string)</li>
|
336 |
+
* <li> 'ssl_local_cert' - Name of a file containing local cerificate (string)</li>
|
337 |
+
* <li> 'ssl_passphrase' - Passphrase with which local certificate
|
338 |
+
* was encoded (string)</li>
|
339 |
+
* <li> 'digest_compat_ie' - Whether to imitate behaviour of MSIE 5 and 6
|
340 |
+
* in using URL without query string in digest
|
341 |
+
* authentication (boolean)</li>
|
342 |
+
* <li> 'follow_redirects' - Whether to automatically follow HTTP Redirects (boolean)</li>
|
343 |
+
* <li> 'max_redirects' - Maximum number of redirects to follow (integer)</li>
|
344 |
+
* <li> 'strict_redirects' - Whether to keep request method on redirects via status 301 and
|
345 |
+
* 302 (true, needed for compatibility with RFC 2616)
|
346 |
+
* or switch to GET (false, needed for compatibility with most
|
347 |
+
* browsers) (boolean)</li>
|
348 |
+
* </ul>
|
349 |
+
*
|
350 |
+
* @param string|array $nameOrConfig configuration parameter name or array
|
351 |
+
* ('parameter name' => 'parameter value')
|
352 |
+
* @param mixed $value parameter value if $nameOrConfig is not an array
|
353 |
+
*
|
354 |
+
* @return HTTP_Request2
|
355 |
+
* @throws HTTP_Request2_LogicException If the parameter is unknown
|
356 |
+
*/
|
357 |
+
public function setConfig($nameOrConfig, $value = null)
|
358 |
+
{
|
359 |
+
if (is_array($nameOrConfig)) {
|
360 |
+
foreach ($nameOrConfig as $name => $value) {
|
361 |
+
$this->setConfig($name, $value);
|
362 |
+
}
|
363 |
+
|
364 |
+
} elseif ('proxy' == $nameOrConfig) {
|
365 |
+
$url = new Net_URL2($value);
|
366 |
+
$this->setConfig(array(
|
367 |
+
'proxy_type' => $url->getScheme(),
|
368 |
+
'proxy_host' => $url->getHost(),
|
369 |
+
'proxy_port' => $url->getPort(),
|
370 |
+
'proxy_user' => rawurldecode($url->getUser()),
|
371 |
+
'proxy_password' => rawurldecode($url->getPassword())
|
372 |
+
));
|
373 |
+
|
374 |
+
} else {
|
375 |
+
if (!array_key_exists($nameOrConfig, $this->config)) {
|
376 |
+
throw new HTTP_Request2_LogicException(
|
377 |
+
"Unknown configuration parameter '{$nameOrConfig}'",
|
378 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
379 |
+
);
|
380 |
+
}
|
381 |
+
$this->config[$nameOrConfig] = $value;
|
382 |
+
}
|
383 |
+
|
384 |
+
return $this;
|
385 |
+
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Returns the value(s) of the configuration parameter(s)
|
389 |
+
*
|
390 |
+
* @param string $name parameter name
|
391 |
+
*
|
392 |
+
* @return mixed value of $name parameter, array of all configuration
|
393 |
+
* parameters if $name is not given
|
394 |
+
* @throws HTTP_Request2_LogicException If the parameter is unknown
|
395 |
+
*/
|
396 |
+
public function getConfig($name = null)
|
397 |
+
{
|
398 |
+
if (null === $name) {
|
399 |
+
return $this->config;
|
400 |
+
} elseif (!array_key_exists($name, $this->config)) {
|
401 |
+
throw new HTTP_Request2_LogicException(
|
402 |
+
"Unknown configuration parameter '{$name}'",
|
403 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
404 |
+
);
|
405 |
+
}
|
406 |
+
return $this->config[$name];
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* Sets the autentification data
|
411 |
+
*
|
412 |
+
* @param string $user user name
|
413 |
+
* @param string $password password
|
414 |
+
* @param string $scheme authentication scheme
|
415 |
+
*
|
416 |
+
* @return HTTP_Request2
|
417 |
+
*/
|
418 |
+
public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)
|
419 |
+
{
|
420 |
+
if (empty($user)) {
|
421 |
+
$this->auth = null;
|
422 |
+
} else {
|
423 |
+
$this->auth = array(
|
424 |
+
'user' => (string)$user,
|
425 |
+
'password' => (string)$password,
|
426 |
+
'scheme' => $scheme
|
427 |
+
);
|
428 |
+
}
|
429 |
+
|
430 |
+
return $this;
|
431 |
+
}
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Returns the authentication data
|
435 |
+
*
|
436 |
+
* The array has the keys 'user', 'password' and 'scheme', where 'scheme'
|
437 |
+
* is one of the HTTP_Request2::AUTH_* constants.
|
438 |
+
*
|
439 |
+
* @return array
|
440 |
+
*/
|
441 |
+
public function getAuth()
|
442 |
+
{
|
443 |
+
return $this->auth;
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Sets request header(s)
|
448 |
+
*
|
449 |
+
* The first parameter may be either a full header string 'header: value' or
|
450 |
+
* header name. In the former case $value parameter is ignored, in the latter
|
451 |
+
* the header's value will either be set to $value or the header will be
|
452 |
+
* removed if $value is null. The first parameter can also be an array of
|
453 |
+
* headers, in that case method will be called recursively.
|
454 |
+
*
|
455 |
+
* Note that headers are treated case insensitively as per RFC 2616.
|
456 |
+
*
|
457 |
+
* <code>
|
458 |
+
* $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'
|
459 |
+
* $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'
|
460 |
+
* $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'
|
461 |
+
* $req->setHeader('FOO'); // removes 'Foo' header from request
|
462 |
+
* </code>
|
463 |
+
*
|
464 |
+
* @param string|array $name header name, header string ('Header: value')
|
465 |
+
* or an array of headers
|
466 |
+
* @param string|array|null $value header value if $name is not an array,
|
467 |
+
* header will be removed if value is null
|
468 |
+
* @param bool $replace whether to replace previous header with the
|
469 |
+
* same name or append to its value
|
470 |
+
*
|
471 |
+
* @return HTTP_Request2
|
472 |
+
* @throws HTTP_Request2_LogicException
|
473 |
+
*/
|
474 |
+
public function setHeader($name, $value = null, $replace = true)
|
475 |
+
{
|
476 |
+
if (is_array($name)) {
|
477 |
+
foreach ($name as $k => $v) {
|
478 |
+
if (is_string($k)) {
|
479 |
+
$this->setHeader($k, $v, $replace);
|
480 |
+
} else {
|
481 |
+
$this->setHeader($v, null, $replace);
|
482 |
+
}
|
483 |
+
}
|
484 |
+
} else {
|
485 |
+
if (null === $value && strpos($name, ':')) {
|
486 |
+
list($name, $value) = array_map('trim', explode(':', $name, 2));
|
487 |
+
}
|
488 |
+
// Header name should be a token: http://tools.ietf.org/html/rfc2616#section-4.2
|
489 |
+
if (preg_match(self::REGEXP_INVALID_TOKEN, $name)) {
|
490 |
+
throw new HTTP_Request2_LogicException(
|
491 |
+
"Invalid header name '{$name}'",
|
492 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
493 |
+
);
|
494 |
+
}
|
495 |
+
// Header names are case insensitive anyway
|
496 |
+
$name = strtolower($name);
|
497 |
+
if (null === $value) {
|
498 |
+
unset($this->headers[$name]);
|
499 |
+
|
500 |
+
} else {
|
501 |
+
if (is_array($value)) {
|
502 |
+
$value = implode(', ', array_map('trim', $value));
|
503 |
+
} elseif (is_string($value)) {
|
504 |
+
$value = trim($value);
|
505 |
+
}
|
506 |
+
if (!isset($this->headers[$name]) || $replace) {
|
507 |
+
$this->headers[$name] = $value;
|
508 |
+
} else {
|
509 |
+
$this->headers[$name] .= ', ' . $value;
|
510 |
+
}
|
511 |
+
}
|
512 |
+
}
|
513 |
+
|
514 |
+
return $this;
|
515 |
+
}
|
516 |
+
|
517 |
+
/**
|
518 |
+
* Returns the request headers
|
519 |
+
*
|
520 |
+
* The array is of the form ('header name' => 'header value'), header names
|
521 |
+
* are lowercased
|
522 |
+
*
|
523 |
+
* @return array
|
524 |
+
*/
|
525 |
+
public function getHeaders()
|
526 |
+
{
|
527 |
+
return $this->headers;
|
528 |
+
}
|
529 |
+
|
530 |
+
/**
|
531 |
+
* Adds a cookie to the request
|
532 |
+
*
|
533 |
+
* If the request does not have a CookieJar object set, this method simply
|
534 |
+
* appends a cookie to "Cookie:" header.
|
535 |
+
*
|
536 |
+
* If a CookieJar object is available, the cookie is stored in that object.
|
537 |
+
* Data from request URL will be used for setting its 'domain' and 'path'
|
538 |
+
* parameters, 'expires' and 'secure' will be set to null and false,
|
539 |
+
* respectively. If you need further control, use CookieJar's methods.
|
540 |
+
*
|
541 |
+
* @param string $name cookie name
|
542 |
+
* @param string $value cookie value
|
543 |
+
*
|
544 |
+
* @return HTTP_Request2
|
545 |
+
* @throws HTTP_Request2_LogicException
|
546 |
+
* @see setCookieJar()
|
547 |
+
*/
|
548 |
+
public function addCookie($name, $value)
|
549 |
+
{
|
550 |
+
if (!empty($this->cookieJar)) {
|
551 |
+
$this->cookieJar->store(
|
552 |
+
array('name' => $name, 'value' => $value), $this->url
|
553 |
+
);
|
554 |
+
|
555 |
+
} else {
|
556 |
+
$cookie = $name . '=' . $value;
|
557 |
+
if (preg_match(self::REGEXP_INVALID_COOKIE, $cookie)) {
|
558 |
+
throw new HTTP_Request2_LogicException(
|
559 |
+
"Invalid cookie: '{$cookie}'",
|
560 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
561 |
+
);
|
562 |
+
}
|
563 |
+
$cookies = empty($this->headers['cookie'])? '': $this->headers['cookie'] . '; ';
|
564 |
+
$this->setHeader('cookie', $cookies . $cookie);
|
565 |
+
}
|
566 |
+
|
567 |
+
return $this;
|
568 |
+
}
|
569 |
+
|
570 |
+
/**
|
571 |
+
* Sets the request body
|
572 |
+
*
|
573 |
+
* If you provide file pointer rather than file name, it should support
|
574 |
+
* fstat() and rewind() operations.
|
575 |
+
*
|
576 |
+
* @param string|resource|HTTP_Request2_MultipartBody $body Either a
|
577 |
+
* string with the body or filename containing body or
|
578 |
+
* pointer to an open file or object with multipart body data
|
579 |
+
* @param bool $isFilename Whether
|
580 |
+
* first parameter is a filename
|
581 |
+
*
|
582 |
+
* @return HTTP_Request2
|
583 |
+
* @throws HTTP_Request2_LogicException
|
584 |
+
*/
|
585 |
+
public function setBody($body, $isFilename = false)
|
586 |
+
{
|
587 |
+
if (!$isFilename && !is_resource($body)) {
|
588 |
+
if (!$body instanceof HTTP_Request2_MultipartBody) {
|
589 |
+
$this->body = (string)$body;
|
590 |
+
} else {
|
591 |
+
$this->body = $body;
|
592 |
+
}
|
593 |
+
} else {
|
594 |
+
$fileData = $this->fopenWrapper($body, empty($this->headers['content-type']));
|
595 |
+
$this->body = $fileData['fp'];
|
596 |
+
if (empty($this->headers['content-type'])) {
|
597 |
+
$this->setHeader('content-type', $fileData['type']);
|
598 |
+
}
|
599 |
+
}
|
600 |
+
$this->postParams = $this->uploads = array();
|
601 |
+
|
602 |
+
return $this;
|
603 |
+
}
|
604 |
+
|
605 |
+
/**
|
606 |
+
* Returns the request body
|
607 |
+
*
|
608 |
+
* @return string|resource|HTTP_Request2_MultipartBody
|
609 |
+
*/
|
610 |
+
public function getBody()
|
611 |
+
{
|
612 |
+
if (self::METHOD_POST == $this->method
|
613 |
+
&& (!empty($this->postParams) || !empty($this->uploads))
|
614 |
+
) {
|
615 |
+
if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
|
616 |
+
$body = http_build_query($this->postParams, '', '&');
|
617 |
+
if (!$this->getConfig('use_brackets')) {
|
618 |
+
$body = preg_replace('/%5B\d+%5D=/', '=', $body);
|
619 |
+
}
|
620 |
+
// support RFC 3986 by not encoding '~' symbol (request #15368)
|
621 |
+
return str_replace('%7E', '~', $body);
|
622 |
+
|
623 |
+
} elseif (0 === strpos($this->headers['content-type'], 'multipart/form-data')) {
|
624 |
+
require_once 'HTTP/Request2/MultipartBody.php';
|
625 |
+
return new HTTP_Request2_MultipartBody(
|
626 |
+
$this->postParams, $this->uploads, $this->getConfig('use_brackets')
|
627 |
+
);
|
628 |
+
}
|
629 |
+
}
|
630 |
+
return $this->body;
|
631 |
+
}
|
632 |
+
|
633 |
+
/**
|
634 |
+
* Adds a file to form-based file upload
|
635 |
+
*
|
636 |
+
* Used to emulate file upload via a HTML form. The method also sets
|
637 |
+
* Content-Type of HTTP request to 'multipart/form-data'.
|
638 |
+
*
|
639 |
+
* If you just want to send the contents of a file as the body of HTTP
|
640 |
+
* request you should use setBody() method.
|
641 |
+
*
|
642 |
+
* If you provide file pointers rather than file names, they should support
|
643 |
+
* fstat() and rewind() operations.
|
644 |
+
*
|
645 |
+
* @param string $fieldName name of file-upload field
|
646 |
+
* @param string|resource|array $filename full name of local file,
|
647 |
+
* pointer to open file or an array of files
|
648 |
+
* @param string $sendFilename filename to send in the request
|
649 |
+
* @param string $contentType content-type of file being uploaded
|
650 |
+
*
|
651 |
+
* @return HTTP_Request2
|
652 |
+
* @throws HTTP_Request2_LogicException
|
653 |
+
*/
|
654 |
+
public function addUpload(
|
655 |
+
$fieldName, $filename, $sendFilename = null, $contentType = null
|
656 |
+
) {
|
657 |
+
if (!is_array($filename)) {
|
658 |
+
$fileData = $this->fopenWrapper($filename, empty($contentType));
|
659 |
+
$this->uploads[$fieldName] = array(
|
660 |
+
'fp' => $fileData['fp'],
|
661 |
+
'filename' => !empty($sendFilename)? $sendFilename
|
662 |
+
:(is_string($filename)? basename($filename): 'anonymous.blob') ,
|
663 |
+
'size' => $fileData['size'],
|
664 |
+
'type' => empty($contentType)? $fileData['type']: $contentType
|
665 |
+
);
|
666 |
+
} else {
|
667 |
+
$fps = $names = $sizes = $types = array();
|
668 |
+
foreach ($filename as $f) {
|
669 |
+
if (!is_array($f)) {
|
670 |
+
$f = array($f);
|
671 |
+
}
|
672 |
+
$fileData = $this->fopenWrapper($f[0], empty($f[2]));
|
673 |
+
$fps[] = $fileData['fp'];
|
674 |
+
$names[] = !empty($f[1])? $f[1]
|
675 |
+
:(is_string($f[0])? basename($f[0]): 'anonymous.blob');
|
676 |
+
$sizes[] = $fileData['size'];
|
677 |
+
$types[] = empty($f[2])? $fileData['type']: $f[2];
|
678 |
+
}
|
679 |
+
$this->uploads[$fieldName] = array(
|
680 |
+
'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
|
681 |
+
);
|
682 |
+
}
|
683 |
+
if (empty($this->headers['content-type'])
|
684 |
+
|| 'application/x-www-form-urlencoded' == $this->headers['content-type']
|
685 |
+
) {
|
686 |
+
$this->setHeader('content-type', 'multipart/form-data');
|
687 |
+
}
|
688 |
+
|
689 |
+
return $this;
|
690 |
+
}
|
691 |
+
|
692 |
+
/**
|
693 |
+
* Adds POST parameter(s) to the request.
|
694 |
+
*
|
695 |
+
* @param string|array $name parameter name or array ('name' => 'value')
|
696 |
+
* @param mixed $value parameter value (can be an array)
|
697 |
+
*
|
698 |
+
* @return HTTP_Request2
|
699 |
+
*/
|
700 |
+
public function addPostParameter($name, $value = null)
|
701 |
+
{
|
702 |
+
if (!is_array($name)) {
|
703 |
+
$this->postParams[$name] = $value;
|
704 |
+
} else {
|
705 |
+
foreach ($name as $k => $v) {
|
706 |
+
$this->addPostParameter($k, $v);
|
707 |
+
}
|
708 |
+
}
|
709 |
+
if (empty($this->headers['content-type'])) {
|
710 |
+
$this->setHeader('content-type', 'application/x-www-form-urlencoded');
|
711 |
+
}
|
712 |
+
|
713 |
+
return $this;
|
714 |
+
}
|
715 |
+
|
716 |
+
/**
|
717 |
+
* Attaches a new observer
|
718 |
+
*
|
719 |
+
* @param SplObserver $observer any object implementing SplObserver
|
720 |
+
*/
|
721 |
+
public function attach(SplObserver $observer)
|
722 |
+
{
|
723 |
+
foreach ($this->observers as $attached) {
|
724 |
+
if ($attached === $observer) {
|
725 |
+
return;
|
726 |
+
}
|
727 |
+
}
|
728 |
+
$this->observers[] = $observer;
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Detaches an existing observer
|
733 |
+
*
|
734 |
+
* @param SplObserver $observer any object implementing SplObserver
|
735 |
+
*/
|
736 |
+
public function detach(SplObserver $observer)
|
737 |
+
{
|
738 |
+
foreach ($this->observers as $key => $attached) {
|
739 |
+
if ($attached === $observer) {
|
740 |
+
unset($this->observers[$key]);
|
741 |
+
return;
|
742 |
+
}
|
743 |
+
}
|
744 |
+
}
|
745 |
+
|
746 |
+
/**
|
747 |
+
* Notifies all observers
|
748 |
+
*/
|
749 |
+
public function notify()
|
750 |
+
{
|
751 |
+
foreach ($this->observers as $observer) {
|
752 |
+
$observer->update($this);
|
753 |
+
}
|
754 |
+
}
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Sets the last event
|
758 |
+
*
|
759 |
+
* Adapters should use this method to set the current state of the request
|
760 |
+
* and notify the observers.
|
761 |
+
*
|
762 |
+
* @param string $name event name
|
763 |
+
* @param mixed $data event data
|
764 |
+
*/
|
765 |
+
public function setLastEvent($name, $data = null)
|
766 |
+
{
|
767 |
+
$this->lastEvent = array(
|
768 |
+
'name' => $name,
|
769 |
+
'data' => $data
|
770 |
+
);
|
771 |
+
$this->notify();
|
772 |
+
}
|
773 |
+
|
774 |
+
/**
|
775 |
+
* Returns the last event
|
776 |
+
*
|
777 |
+
* Observers should use this method to access the last change in request.
|
778 |
+
* The following event names are possible:
|
779 |
+
* <ul>
|
780 |
+
* <li>'connect' - after connection to remote server,
|
781 |
+
* data is the destination (string)</li>
|
782 |
+
* <li>'disconnect' - after disconnection from server</li>
|
783 |
+
* <li>'sentHeaders' - after sending the request headers,
|
784 |
+
* data is the headers sent (string)</li>
|
785 |
+
* <li>'sentBodyPart' - after sending a part of the request body,
|
786 |
+
* data is the length of that part (int)</li>
|
787 |
+
* <li>'sentBody' - after sending the whole request body,
|
788 |
+
* data is request body length (int)</li>
|
789 |
+
* <li>'receivedHeaders' - after receiving the response headers,
|
790 |
+
* data is HTTP_Request2_Response object</li>
|
791 |
+
* <li>'receivedBodyPart' - after receiving a part of the response
|
792 |
+
* body, data is that part (string)</li>
|
793 |
+
* <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still
|
794 |
+
* encoded by Content-Encoding</li>
|
795 |
+
* <li>'receivedBody' - after receiving the complete response
|
796 |
+
* body, data is HTTP_Request2_Response object</li>
|
797 |
+
* </ul>
|
798 |
+
* Different adapters may not send all the event types. Mock adapter does
|
799 |
+
* not send any events to the observers.
|
800 |
+
*
|
801 |
+
* @return array The array has two keys: 'name' and 'data'
|
802 |
+
*/
|
803 |
+
public function getLastEvent()
|
804 |
+
{
|
805 |
+
return $this->lastEvent;
|
806 |
+
}
|
807 |
+
|
808 |
+
/**
|
809 |
+
* Sets the adapter used to actually perform the request
|
810 |
+
*
|
811 |
+
* You can pass either an instance of a class implementing HTTP_Request2_Adapter
|
812 |
+
* or a class name. The method will only try to include a file if the class
|
813 |
+
* name starts with HTTP_Request2_Adapter_, it will also try to prepend this
|
814 |
+
* prefix to the class name if it doesn't contain any underscores, so that
|
815 |
+
* <code>
|
816 |
+
* $request->setAdapter('curl');
|
817 |
+
* </code>
|
818 |
+
* will work.
|
819 |
+
*
|
820 |
+
* @param string|HTTP_Request2_Adapter $adapter Adapter to use
|
821 |
+
*
|
822 |
+
* @return HTTP_Request2
|
823 |
+
* @throws HTTP_Request2_LogicException
|
824 |
+
*/
|
825 |
+
public function setAdapter($adapter)
|
826 |
+
{
|
827 |
+
if (is_string($adapter)) {
|
828 |
+
if (!class_exists($adapter, false)) {
|
829 |
+
if (false === strpos($adapter, '_')) {
|
830 |
+
$adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
|
831 |
+
}
|
832 |
+
if (!class_exists($adapter, false)
|
833 |
+
&& preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)
|
834 |
+
) {
|
835 |
+
include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
|
836 |
+
}
|
837 |
+
if (!class_exists($adapter, false)) {
|
838 |
+
throw new HTTP_Request2_LogicException(
|
839 |
+
"Class {$adapter} not found",
|
840 |
+
HTTP_Request2_Exception::MISSING_VALUE
|
841 |
+
);
|
842 |
+
}
|
843 |
+
}
|
844 |
+
$adapter = new $adapter;
|
845 |
+
}
|
846 |
+
if (!$adapter instanceof HTTP_Request2_Adapter) {
|
847 |
+
throw new HTTP_Request2_LogicException(
|
848 |
+
'Parameter is not a HTTP request adapter',
|
849 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
850 |
+
);
|
851 |
+
}
|
852 |
+
$this->adapter = $adapter;
|
853 |
+
|
854 |
+
return $this;
|
855 |
+
}
|
856 |
+
|
857 |
+
/**
|
858 |
+
* Sets the cookie jar
|
859 |
+
*
|
860 |
+
* A cookie jar is used to maintain cookies across HTTP requests and
|
861 |
+
* responses. Cookies from jar will be automatically added to the request
|
862 |
+
* headers based on request URL.
|
863 |
+
*
|
864 |
+
* @param HTTP_Request2_CookieJar|bool $jar Existing CookieJar object, true to
|
865 |
+
* create a new one, false to remove
|
866 |
+
*
|
867 |
+
* @return HTTP_Request2
|
868 |
+
* @throws HTTP_Request2_LogicException
|
869 |
+
*/
|
870 |
+
public function setCookieJar($jar = true)
|
871 |
+
{
|
872 |
+
if (!class_exists('HTTP_Request2_CookieJar', false)) {
|
873 |
+
require_once 'HTTP/Request2/CookieJar.php';
|
874 |
+
}
|
875 |
+
|
876 |
+
if ($jar instanceof HTTP_Request2_CookieJar) {
|
877 |
+
$this->cookieJar = $jar;
|
878 |
+
} elseif (true === $jar) {
|
879 |
+
$this->cookieJar = new HTTP_Request2_CookieJar();
|
880 |
+
} elseif (!$jar) {
|
881 |
+
$this->cookieJar = null;
|
882 |
+
} else {
|
883 |
+
throw new HTTP_Request2_LogicException(
|
884 |
+
'Invalid parameter passed to setCookieJar()',
|
885 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
886 |
+
);
|
887 |
+
}
|
888 |
+
|
889 |
+
return $this;
|
890 |
+
}
|
891 |
+
|
892 |
+
/**
|
893 |
+
* Returns current CookieJar object or null if none
|
894 |
+
*
|
895 |
+
* @return HTTP_Request2_CookieJar|null
|
896 |
+
*/
|
897 |
+
public function getCookieJar()
|
898 |
+
{
|
899 |
+
return $this->cookieJar;
|
900 |
+
}
|
901 |
+
|
902 |
+
/**
|
903 |
+
* Sends the request and returns the response
|
904 |
+
*
|
905 |
+
* @throws HTTP_Request2_Exception
|
906 |
+
* @return HTTP_Request2_Response
|
907 |
+
*/
|
908 |
+
public function send()
|
909 |
+
{
|
910 |
+
// Sanity check for URL
|
911 |
+
if (!$this->url instanceof Net_URL2
|
912 |
+
|| !$this->url->isAbsolute()
|
913 |
+
|| !in_array(strtolower($this->url->getScheme()), array('https', 'http'))
|
914 |
+
) {
|
915 |
+
throw new HTTP_Request2_LogicException(
|
916 |
+
'HTTP_Request2 needs an absolute HTTP(S) request URL, '
|
917 |
+
. ($this->url instanceof Net_URL2
|
918 |
+
? "'" . $this->url->__toString() . "'" : 'none')
|
919 |
+
. ' given',
|
920 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
921 |
+
);
|
922 |
+
}
|
923 |
+
if (empty($this->adapter)) {
|
924 |
+
$this->setAdapter($this->getConfig('adapter'));
|
925 |
+
}
|
926 |
+
// magic_quotes_runtime may break file uploads and chunked response
|
927 |
+
// processing; see bug #4543. Don't use ini_get() here; see bug #16440.
|
928 |
+
if ($magicQuotes = get_magic_quotes_runtime()) {
|
929 |
+
set_magic_quotes_runtime(false);
|
930 |
+
}
|
931 |
+
// force using single byte encoding if mbstring extension overloads
|
932 |
+
// strlen() and substr(); see bug #1781, bug #10605
|
933 |
+
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
|
934 |
+
$oldEncoding = mb_internal_encoding();
|
935 |
+
mb_internal_encoding('8bit');
|
936 |
+
}
|
937 |
+
|
938 |
+
try {
|
939 |
+
$response = $this->adapter->sendRequest($this);
|
940 |
+
} catch (Exception $e) {
|
941 |
+
}
|
942 |
+
// cleanup in either case (poor man's "finally" clause)
|
943 |
+
if ($magicQuotes) {
|
944 |
+
set_magic_quotes_runtime(true);
|
945 |
+
}
|
946 |
+
if (!empty($oldEncoding)) {
|
947 |
+
mb_internal_encoding($oldEncoding);
|
948 |
+
}
|
949 |
+
// rethrow the exception
|
950 |
+
if (!empty($e)) {
|
951 |
+
throw $e;
|
952 |
+
}
|
953 |
+
return $response;
|
954 |
+
}
|
955 |
+
|
956 |
+
/**
|
957 |
+
* Wrapper around fopen()/fstat() used by setBody() and addUpload()
|
958 |
+
*
|
959 |
+
* @param string|resource $file file name or pointer to open file
|
960 |
+
* @param bool $detectType whether to try autodetecting MIME
|
961 |
+
* type of file, will only work if $file is a
|
962 |
+
* filename, not pointer
|
963 |
+
*
|
964 |
+
* @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)
|
965 |
+
* @throws HTTP_Request2_LogicException
|
966 |
+
*/
|
967 |
+
protected function fopenWrapper($file, $detectType = false)
|
968 |
+
{
|
969 |
+
if (!is_string($file) && !is_resource($file)) {
|
970 |
+
throw new HTTP_Request2_LogicException(
|
971 |
+
"Filename or file pointer resource expected",
|
972 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
973 |
+
);
|
974 |
+
}
|
975 |
+
$fileData = array(
|
976 |
+
'fp' => is_string($file)? null: $file,
|
977 |
+
'type' => 'application/octet-stream',
|
978 |
+
'size' => 0
|
979 |
+
);
|
980 |
+
if (is_string($file)) {
|
981 |
+
if (!($fileData['fp'] = @fopen($file, 'rb'))) {
|
982 |
+
$error = error_get_last();
|
983 |
+
throw new HTTP_Request2_LogicException(
|
984 |
+
$error['message'], HTTP_Request2_Exception::READ_ERROR
|
985 |
+
);
|
986 |
+
}
|
987 |
+
if ($detectType) {
|
988 |
+
$fileData['type'] = self::detectMimeType($file);
|
989 |
+
}
|
990 |
+
}
|
991 |
+
if (!($stat = fstat($fileData['fp']))) {
|
992 |
+
throw new HTTP_Request2_LogicException(
|
993 |
+
"fstat() call failed", HTTP_Request2_Exception::READ_ERROR
|
994 |
+
);
|
995 |
+
}
|
996 |
+
$fileData['size'] = $stat['size'];
|
997 |
+
|
998 |
+
return $fileData;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
/**
|
1002 |
+
* Tries to detect MIME type of a file
|
1003 |
+
*
|
1004 |
+
* The method will try to use fileinfo extension if it is available,
|
1005 |
+
* deprecated mime_content_type() function in the other case. If neither
|
1006 |
+
* works, default 'application/octet-stream' MIME type is returned
|
1007 |
+
*
|
1008 |
+
* @param string $filename file name
|
1009 |
+
*
|
1010 |
+
* @return string file MIME type
|
1011 |
+
*/
|
1012 |
+
protected static function detectMimeType($filename)
|
1013 |
+
{
|
1014 |
+
// finfo extension from PECL available
|
1015 |
+
if (function_exists('finfo_open')) {
|
1016 |
+
if (!isset(self::$_fileinfoDb)) {
|
1017 |
+
self::$_fileinfoDb = @finfo_open(FILEINFO_MIME);
|
1018 |
+
}
|
1019 |
+
if (self::$_fileinfoDb) {
|
1020 |
+
$info = finfo_file(self::$_fileinfoDb, $filename);
|
1021 |
+
}
|
1022 |
+
}
|
1023 |
+
// (deprecated) mime_content_type function available
|
1024 |
+
if (empty($info) && function_exists('mime_content_type')) {
|
1025 |
+
return mime_content_type($filename);
|
1026 |
+
}
|
1027 |
+
return empty($info)? 'application/octet-stream': $info;
|
1028 |
+
}
|
1029 |
+
}
|
1030 |
+
?>
|
vendor/PEAR/HTTP/Request2/Adapter.php
CHANGED
@@ -1,137 +1,137 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Base class for HTTP_Request2 adapters
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Class representing a HTTP response
|
23 |
-
*/
|
24 |
-
require_once 'HTTP/Request2/Response.php';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Base class for HTTP_Request2 adapters
|
28 |
-
*
|
29 |
-
* HTTP_Request2 class itself only defines methods for aggregating the request
|
30 |
-
* data, all actual work of sending the request to the remote server and
|
31 |
-
* receiving its response is performed by adapters.
|
32 |
-
*
|
33 |
-
* @category HTTP
|
34 |
-
* @package HTTP_Request2
|
35 |
-
* @author Alexey Borzov <avb@php.net>
|
36 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
37 |
-
* @version Release: 2.2.1
|
38 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
39 |
-
*/
|
40 |
-
abstract class HTTP_Request2_Adapter
|
41 |
-
{
|
42 |
-
/**
|
43 |
-
* A list of methods that MUST NOT have a request body, per RFC 2616
|
44 |
-
* @var array
|
45 |
-
*/
|
46 |
-
protected static $bodyDisallowed = array('TRACE');
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Methods having defined semantics for request body
|
50 |
-
*
|
51 |
-
* Content-Length header (indicating that the body follows, section 4.3 of
|
52 |
-
* RFC 2616) will be sent for these methods even if no body was added
|
53 |
-
*
|
54 |
-
* @var array
|
55 |
-
* @link http://pear.php.net/bugs/bug.php?id=12900
|
56 |
-
* @link http://pear.php.net/bugs/bug.php?id=14740
|
57 |
-
*/
|
58 |
-
protected static $bodyRequired = array('POST', 'PUT');
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Request being sent
|
62 |
-
* @var HTTP_Request2
|
63 |
-
*/
|
64 |
-
protected $request;
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Request body
|
68 |
-
* @var string|resource|HTTP_Request2_MultipartBody
|
69 |
-
* @see HTTP_Request2::getBody()
|
70 |
-
*/
|
71 |
-
protected $requestBody;
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Length of the request body
|
75 |
-
* @var integer
|
76 |
-
*/
|
77 |
-
protected $contentLength;
|
78 |
-
|
79 |
-
/**
|
80 |
-
* Sends request to the remote server and returns its response
|
81 |
-
*
|
82 |
-
* @param HTTP_Request2 $request HTTP request message
|
83 |
-
*
|
84 |
-
* @return HTTP_Request2_Response
|
85 |
-
* @throws HTTP_Request2_Exception
|
86 |
-
*/
|
87 |
-
abstract public function sendRequest(HTTP_Request2 $request);
|
88 |
-
|
89 |
-
/**
|
90 |
-
* Calculates length of the request body, adds proper headers
|
91 |
-
*
|
92 |
-
* @param array &$headers associative array of request headers, this method
|
93 |
-
* will add proper 'Content-Length' and 'Content-Type'
|
94 |
-
* headers to this array (or remove them if not needed)
|
95 |
-
*/
|
96 |
-
protected function calculateRequestLength(&$headers)
|
97 |
-
{
|
98 |
-
$this->requestBody = $this->request->getBody();
|
99 |
-
|
100 |
-
if (is_string($this->requestBody)) {
|
101 |
-
$this->contentLength = strlen($this->requestBody);
|
102 |
-
} elseif (is_resource($this->requestBody)) {
|
103 |
-
$stat = fstat($this->requestBody);
|
104 |
-
$this->contentLength = $stat['size'];
|
105 |
-
rewind($this->requestBody);
|
106 |
-
} else {
|
107 |
-
$this->contentLength = $this->requestBody->getLength();
|
108 |
-
$headers['content-type'] = 'multipart/form-data; boundary=' .
|
109 |
-
$this->requestBody->getBoundary();
|
110 |
-
$this->requestBody->rewind();
|
111 |
-
}
|
112 |
-
|
113 |
-
if (in_array($this->request->getMethod(), self::$bodyDisallowed)
|
114 |
-
|| 0 == $this->contentLength
|
115 |
-
) {
|
116 |
-
// No body: send a Content-Length header nonetheless (request #12900),
|
117 |
-
// but do that only for methods that require a body (bug #14740)
|
118 |
-
if (in_array($this->request->getMethod(), self::$bodyRequired)) {
|
119 |
-
$headers['content-length'] = 0;
|
120 |
-
} else {
|
121 |
-
unset($headers['content-length']);
|
122 |
-
// if the method doesn't require a body and doesn't have a
|
123 |
-
// body, don't send a Content-Type header. (request #16799)
|
124 |
-
unset($headers['content-type']);
|
125 |
-
}
|
126 |
-
} else {
|
127 |
-
if (empty($headers['content-type'])) {
|
128 |
-
$headers['content-type'] = 'application/x-www-form-urlencoded';
|
129 |
-
}
|
130 |
-
// Content-Length should not be sent for chunked Transfer-Encoding (bug #20125)
|
131 |
-
if (!isset($headers['transfer-encoding'])) {
|
132 |
-
$headers['content-length'] = $this->contentLength;
|
133 |
-
}
|
134 |
-
}
|
135 |
-
}
|
136 |
-
}
|
137 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Base class for HTTP_Request2 adapters
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Class representing a HTTP response
|
23 |
+
*/
|
24 |
+
require_once 'HTTP/Request2/Response.php';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Base class for HTTP_Request2 adapters
|
28 |
+
*
|
29 |
+
* HTTP_Request2 class itself only defines methods for aggregating the request
|
30 |
+
* data, all actual work of sending the request to the remote server and
|
31 |
+
* receiving its response is performed by adapters.
|
32 |
+
*
|
33 |
+
* @category HTTP
|
34 |
+
* @package HTTP_Request2
|
35 |
+
* @author Alexey Borzov <avb@php.net>
|
36 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
37 |
+
* @version Release: 2.2.1
|
38 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
39 |
+
*/
|
40 |
+
abstract class HTTP_Request2_Adapter
|
41 |
+
{
|
42 |
+
/**
|
43 |
+
* A list of methods that MUST NOT have a request body, per RFC 2616
|
44 |
+
* @var array
|
45 |
+
*/
|
46 |
+
protected static $bodyDisallowed = array('TRACE');
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Methods having defined semantics for request body
|
50 |
+
*
|
51 |
+
* Content-Length header (indicating that the body follows, section 4.3 of
|
52 |
+
* RFC 2616) will be sent for these methods even if no body was added
|
53 |
+
*
|
54 |
+
* @var array
|
55 |
+
* @link http://pear.php.net/bugs/bug.php?id=12900
|
56 |
+
* @link http://pear.php.net/bugs/bug.php?id=14740
|
57 |
+
*/
|
58 |
+
protected static $bodyRequired = array('POST', 'PUT');
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Request being sent
|
62 |
+
* @var HTTP_Request2
|
63 |
+
*/
|
64 |
+
protected $request;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Request body
|
68 |
+
* @var string|resource|HTTP_Request2_MultipartBody
|
69 |
+
* @see HTTP_Request2::getBody()
|
70 |
+
*/
|
71 |
+
protected $requestBody;
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Length of the request body
|
75 |
+
* @var integer
|
76 |
+
*/
|
77 |
+
protected $contentLength;
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Sends request to the remote server and returns its response
|
81 |
+
*
|
82 |
+
* @param HTTP_Request2 $request HTTP request message
|
83 |
+
*
|
84 |
+
* @return HTTP_Request2_Response
|
85 |
+
* @throws HTTP_Request2_Exception
|
86 |
+
*/
|
87 |
+
abstract public function sendRequest(HTTP_Request2 $request);
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Calculates length of the request body, adds proper headers
|
91 |
+
*
|
92 |
+
* @param array &$headers associative array of request headers, this method
|
93 |
+
* will add proper 'Content-Length' and 'Content-Type'
|
94 |
+
* headers to this array (or remove them if not needed)
|
95 |
+
*/
|
96 |
+
protected function calculateRequestLength(&$headers)
|
97 |
+
{
|
98 |
+
$this->requestBody = $this->request->getBody();
|
99 |
+
|
100 |
+
if (is_string($this->requestBody)) {
|
101 |
+
$this->contentLength = strlen($this->requestBody);
|
102 |
+
} elseif (is_resource($this->requestBody)) {
|
103 |
+
$stat = fstat($this->requestBody);
|
104 |
+
$this->contentLength = $stat['size'];
|
105 |
+
rewind($this->requestBody);
|
106 |
+
} else {
|
107 |
+
$this->contentLength = $this->requestBody->getLength();
|
108 |
+
$headers['content-type'] = 'multipart/form-data; boundary=' .
|
109 |
+
$this->requestBody->getBoundary();
|
110 |
+
$this->requestBody->rewind();
|
111 |
+
}
|
112 |
+
|
113 |
+
if (in_array($this->request->getMethod(), self::$bodyDisallowed)
|
114 |
+
|| 0 == $this->contentLength
|
115 |
+
) {
|
116 |
+
// No body: send a Content-Length header nonetheless (request #12900),
|
117 |
+
// but do that only for methods that require a body (bug #14740)
|
118 |
+
if (in_array($this->request->getMethod(), self::$bodyRequired)) {
|
119 |
+
$headers['content-length'] = 0;
|
120 |
+
} else {
|
121 |
+
unset($headers['content-length']);
|
122 |
+
// if the method doesn't require a body and doesn't have a
|
123 |
+
// body, don't send a Content-Type header. (request #16799)
|
124 |
+
unset($headers['content-type']);
|
125 |
+
}
|
126 |
+
} else {
|
127 |
+
if (empty($headers['content-type'])) {
|
128 |
+
$headers['content-type'] = 'application/x-www-form-urlencoded';
|
129 |
+
}
|
130 |
+
// Content-Length should not be sent for chunked Transfer-Encoding (bug #20125)
|
131 |
+
if (!isset($headers['transfer-encoding'])) {
|
132 |
+
$headers['content-length'] = $this->contentLength;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
}
|
136 |
+
}
|
137 |
+
?>
|
vendor/PEAR/HTTP/Request2/Adapter/Curl.php
CHANGED
@@ -1,567 +1,567 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Adapter for HTTP_Request2 wrapping around cURL extension
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Base class for HTTP_Request2 adapters
|
23 |
-
*/
|
24 |
-
require_once 'HTTP/Request2/Adapter.php';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Adapter for HTTP_Request2 wrapping around cURL extension
|
28 |
-
*
|
29 |
-
* @category HTTP
|
30 |
-
* @package HTTP_Request2
|
31 |
-
* @author Alexey Borzov <avb@php.net>
|
32 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
33 |
-
* @version Release: 2.2.1
|
34 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
35 |
-
*/
|
36 |
-
class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
|
37 |
-
{
|
38 |
-
/**
|
39 |
-
* Mapping of header names to cURL options
|
40 |
-
* @var array
|
41 |
-
*/
|
42 |
-
protected static $headerMap = array(
|
43 |
-
'accept-encoding' => CURLOPT_ENCODING,
|
44 |
-
'cookie' => CURLOPT_COOKIE,
|
45 |
-
'referer' => CURLOPT_REFERER,
|
46 |
-
'user-agent' => CURLOPT_USERAGENT
|
47 |
-
);
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Mapping of SSL context options to cURL options
|
51 |
-
* @var array
|
52 |
-
*/
|
53 |
-
protected static $sslContextMap = array(
|
54 |
-
'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,
|
55 |
-
'ssl_cafile' => CURLOPT_CAINFO,
|
56 |
-
'ssl_capath' => CURLOPT_CAPATH,
|
57 |
-
'ssl_local_cert' => CURLOPT_SSLCERT,
|
58 |
-
'ssl_passphrase' => CURLOPT_SSLCERTPASSWD
|
59 |
-
);
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Mapping of CURLE_* constants to Exception subclasses and error codes
|
63 |
-
* @var array
|
64 |
-
*/
|
65 |
-
protected static $errorMap = array(
|
66 |
-
CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException',
|
67 |
-
HTTP_Request2_Exception::NON_HTTP_REDIRECT),
|
68 |
-
CURLE_COULDNT_RESOLVE_PROXY => array('HTTP_Request2_ConnectionException'),
|
69 |
-
CURLE_COULDNT_RESOLVE_HOST => array('HTTP_Request2_ConnectionException'),
|
70 |
-
CURLE_COULDNT_CONNECT => array('HTTP_Request2_ConnectionException'),
|
71 |
-
// error returned from write callback
|
72 |
-
CURLE_WRITE_ERROR => array('HTTP_Request2_MessageException',
|
73 |
-
HTTP_Request2_Exception::NON_HTTP_REDIRECT),
|
74 |
-
CURLE_OPERATION_TIMEOUTED => array('HTTP_Request2_MessageException',
|
75 |
-
HTTP_Request2_Exception::TIMEOUT),
|
76 |
-
CURLE_HTTP_RANGE_ERROR => array('HTTP_Request2_MessageException'),
|
77 |
-
CURLE_SSL_CONNECT_ERROR => array('HTTP_Request2_ConnectionException'),
|
78 |
-
CURLE_LIBRARY_NOT_FOUND => array('HTTP_Request2_LogicException',
|
79 |
-
HTTP_Request2_Exception::MISCONFIGURATION),
|
80 |
-
CURLE_FUNCTION_NOT_FOUND => array('HTTP_Request2_LogicException',
|
81 |
-
HTTP_Request2_Exception::MISCONFIGURATION),
|
82 |
-
CURLE_ABORTED_BY_CALLBACK => array('HTTP_Request2_MessageException',
|
83 |
-
HTTP_Request2_Exception::NON_HTTP_REDIRECT),
|
84 |
-
CURLE_TOO_MANY_REDIRECTS => array('HTTP_Request2_MessageException',
|
85 |
-
HTTP_Request2_Exception::TOO_MANY_REDIRECTS),
|
86 |
-
CURLE_SSL_PEER_CERTIFICATE => array('HTTP_Request2_ConnectionException'),
|
87 |
-
CURLE_GOT_NOTHING => array('HTTP_Request2_MessageException'),
|
88 |
-
CURLE_SSL_ENGINE_NOTFOUND => array('HTTP_Request2_LogicException',
|
89 |
-
HTTP_Request2_Exception::MISCONFIGURATION),
|
90 |
-
CURLE_SSL_ENGINE_SETFAILED => array('HTTP_Request2_LogicException',
|
91 |
-
HTTP_Request2_Exception::MISCONFIGURATION),
|
92 |
-
CURLE_SEND_ERROR => array('HTTP_Request2_MessageException'),
|
93 |
-
CURLE_RECV_ERROR => array('HTTP_Request2_MessageException'),
|
94 |
-
CURLE_SSL_CERTPROBLEM => array('HTTP_Request2_LogicException',
|
95 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT),
|
96 |
-
CURLE_SSL_CIPHER => array('HTTP_Request2_ConnectionException'),
|
97 |
-
CURLE_SSL_CACERT => array('HTTP_Request2_ConnectionException'),
|
98 |
-
CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'),
|
99 |
-
);
|
100 |
-
|
101 |
-
/**
|
102 |
-
* Response being received
|
103 |
-
* @var HTTP_Request2_Response
|
104 |
-
*/
|
105 |
-
protected $response;
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Whether 'sentHeaders' event was sent to observers
|
109 |
-
* @var boolean
|
110 |
-
*/
|
111 |
-
protected $eventSentHeaders = false;
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Whether 'receivedHeaders' event was sent to observers
|
115 |
-
* @var boolean
|
116 |
-
*/
|
117 |
-
protected $eventReceivedHeaders = false;
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Position within request body
|
121 |
-
* @var integer
|
122 |
-
* @see callbackReadBody()
|
123 |
-
*/
|
124 |
-
protected $position = 0;
|
125 |
-
|
126 |
-
/**
|
127 |
-
* Information about last transfer, as returned by curl_getinfo()
|
128 |
-
* @var array
|
129 |
-
*/
|
130 |
-
protected $lastInfo;
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Creates a subclass of HTTP_Request2_Exception from curl error data
|
134 |
-
*
|
135 |
-
* @param resource $ch curl handle
|
136 |
-
*
|
137 |
-
* @return HTTP_Request2_Exception
|
138 |
-
*/
|
139 |
-
protected static function wrapCurlError($ch)
|
140 |
-
{
|
141 |
-
$nativeCode = curl_errno($ch);
|
142 |
-
$message = 'Curl error: ' . curl_error($ch);
|
143 |
-
if (!isset(self::$errorMap[$nativeCode])) {
|
144 |
-
return new HTTP_Request2_Exception($message, 0, $nativeCode);
|
145 |
-
} else {
|
146 |
-
$class = self::$errorMap[$nativeCode][0];
|
147 |
-
$code = empty(self::$errorMap[$nativeCode][1])
|
148 |
-
? 0 : self::$errorMap[$nativeCode][1];
|
149 |
-
return new $class($message, $code, $nativeCode);
|
150 |
-
}
|
151 |
-
}
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Sends request to the remote server and returns its response
|
155 |
-
*
|
156 |
-
* @param HTTP_Request2 $request HTTP request message
|
157 |
-
*
|
158 |
-
* @return HTTP_Request2_Response
|
159 |
-
* @throws HTTP_Request2_Exception
|
160 |
-
*/
|
161 |
-
public function sendRequest(HTTP_Request2 $request)
|
162 |
-
{
|
163 |
-
if (!extension_loaded('curl')) {
|
164 |
-
throw new HTTP_Request2_LogicException(
|
165 |
-
'cURL extension not available', HTTP_Request2_Exception::MISCONFIGURATION
|
166 |
-
);
|
167 |
-
}
|
168 |
-
|
169 |
-
$this->request = $request;
|
170 |
-
$this->response = null;
|
171 |
-
$this->position = 0;
|
172 |
-
$this->eventSentHeaders = false;
|
173 |
-
$this->eventReceivedHeaders = false;
|
174 |
-
|
175 |
-
try {
|
176 |
-
if (false === curl_exec($ch = $this->createCurlHandle())) {
|
177 |
-
$e = self::wrapCurlError($ch);
|
178 |
-
}
|
179 |
-
} catch (Exception $e) {
|
180 |
-
}
|
181 |
-
if (isset($ch)) {
|
182 |
-
$this->lastInfo = curl_getinfo($ch);
|
183 |
-
curl_close($ch);
|
184 |
-
}
|
185 |
-
|
186 |
-
$response = $this->response;
|
187 |
-
unset($this->request, $this->requestBody, $this->response);
|
188 |
-
|
189 |
-
if (!empty($e)) {
|
190 |
-
throw $e;
|
191 |
-
}
|
192 |
-
|
193 |
-
if ($jar = $request->getCookieJar()) {
|
194 |
-
$jar->addCookiesFromResponse($response, $request->getUrl());
|
195 |
-
}
|
196 |
-
|
197 |
-
if (0 < $this->lastInfo['size_download']) {
|
198 |
-
$request->setLastEvent('receivedBody', $response);
|
199 |
-
}
|
200 |
-
return $response;
|
201 |
-
}
|
202 |
-
|
203 |
-
/**
|
204 |
-
* Returns information about last transfer
|
205 |
-
*
|
206 |
-
* @return array associative array as returned by curl_getinfo()
|
207 |
-
*/
|
208 |
-
public function getInfo()
|
209 |
-
{
|
210 |
-
return $this->lastInfo;
|
211 |
-
}
|
212 |
-
|
213 |
-
/**
|
214 |
-
* Creates a new cURL handle and populates it with data from the request
|
215 |
-
*
|
216 |
-
* @return resource a cURL handle, as created by curl_init()
|
217 |
-
* @throws HTTP_Request2_LogicException
|
218 |
-
* @throws HTTP_Request2_NotImplementedException
|
219 |
-
*/
|
220 |
-
protected function createCurlHandle()
|
221 |
-
{
|
222 |
-
$ch = curl_init();
|
223 |
-
|
224 |
-
curl_setopt_array($ch, array(
|
225 |
-
// setup write callbacks
|
226 |
-
CURLOPT_HEADERFUNCTION => array($this, 'callbackWriteHeader'),
|
227 |
-
CURLOPT_WRITEFUNCTION => array($this, 'callbackWriteBody'),
|
228 |
-
// buffer size
|
229 |
-
CURLOPT_BUFFERSIZE => $this->request->getConfig('buffer_size'),
|
230 |
-
// connection timeout
|
231 |
-
CURLOPT_CONNECTTIMEOUT => $this->request->getConfig('connect_timeout'),
|
232 |
-
// save full outgoing headers, in case someone is interested
|
233 |
-
CURLINFO_HEADER_OUT => true,
|
234 |
-
// request url
|
235 |
-
CURLOPT_URL => $this->request->getUrl()->getUrl()
|
236 |
-
));
|
237 |
-
|
238 |
-
// set up redirects
|
239 |
-
if (!$this->request->getConfig('follow_redirects')) {
|
240 |
-
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
|
241 |
-
} else {
|
242 |
-
if (!@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)) {
|
243 |
-
throw new HTTP_Request2_LogicException(
|
244 |
-
'Redirect support in curl is unavailable due to open_basedir or safe_mode setting',
|
245 |
-
HTTP_Request2_Exception::MISCONFIGURATION
|
246 |
-
);
|
247 |
-
}
|
248 |
-
curl_setopt($ch, CURLOPT_MAXREDIRS, $this->request->getConfig('max_redirects'));
|
249 |
-
// limit redirects to http(s), works in 5.2.10+
|
250 |
-
if (defined('CURLOPT_REDIR_PROTOCOLS')) {
|
251 |
-
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
252 |
-
}
|
253 |
-
// works in 5.3.2+, http://bugs.php.net/bug.php?id=49571
|
254 |
-
if ($this->request->getConfig('strict_redirects') && defined('CURLOPT_POSTREDIR')) {
|
255 |
-
curl_setopt($ch, CURLOPT_POSTREDIR, 3);
|
256 |
-
}
|
257 |
-
}
|
258 |
-
|
259 |
-
// set local IP via CURLOPT_INTERFACE (request #19515)
|
260 |
-
if ($ip = $this->request->getConfig('local_ip')) {
|
261 |
-
curl_setopt($ch, CURLOPT_INTERFACE, $ip);
|
262 |
-
}
|
263 |
-
|
264 |
-
// request timeout
|
265 |
-
if ($timeout = $this->request->getConfig('timeout')) {
|
266 |
-
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
267 |
-
}
|
268 |
-
|
269 |
-
// set HTTP version
|
270 |
-
switch ($this->request->getConfig('protocol_version')) {
|
271 |
-
case '1.0':
|
272 |
-
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
273 |
-
break;
|
274 |
-
case '1.1':
|
275 |
-
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
276 |
-
}
|
277 |
-
|
278 |
-
// set request method
|
279 |
-
switch ($this->request->getMethod()) {
|
280 |
-
case HTTP_Request2::METHOD_GET:
|
281 |
-
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
282 |
-
break;
|
283 |
-
case HTTP_Request2::METHOD_POST:
|
284 |
-
curl_setopt($ch, CURLOPT_POST, true);
|
285 |
-
break;
|
286 |
-
case HTTP_Request2::METHOD_HEAD:
|
287 |
-
curl_setopt($ch, CURLOPT_NOBODY, true);
|
288 |
-
break;
|
289 |
-
case HTTP_Request2::METHOD_PUT:
|
290 |
-
curl_setopt($ch, CURLOPT_UPLOAD, true);
|
291 |
-
break;
|
292 |
-
default:
|
293 |
-
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
|
294 |
-
}
|
295 |
-
|
296 |
-
// set proxy, if needed
|
297 |
-
if ($host = $this->request->getConfig('proxy_host')) {
|
298 |
-
if (!($port = $this->request->getConfig('proxy_port'))) {
|
299 |
-
throw new HTTP_Request2_LogicException(
|
300 |
-
'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE
|
301 |
-
);
|
302 |
-
}
|
303 |
-
curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
|
304 |
-
if ($user = $this->request->getConfig('proxy_user')) {
|
305 |
-
curl_setopt(
|
306 |
-
$ch, CURLOPT_PROXYUSERPWD,
|
307 |
-
$user . ':' . $this->request->getConfig('proxy_password')
|
308 |
-
);
|
309 |
-
switch ($this->request->getConfig('proxy_auth_scheme')) {
|
310 |
-
case HTTP_Request2::AUTH_BASIC:
|
311 |
-
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
312 |
-
break;
|
313 |
-
case HTTP_Request2::AUTH_DIGEST:
|
314 |
-
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
|
315 |
-
}
|
316 |
-
}
|
317 |
-
if ($type = $this->request->getConfig('proxy_type')) {
|
318 |
-
switch ($type) {
|
319 |
-
case 'http':
|
320 |
-
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
321 |
-
break;
|
322 |
-
case 'socks5':
|
323 |
-
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
324 |
-
break;
|
325 |
-
default:
|
326 |
-
throw new HTTP_Request2_NotImplementedException(
|
327 |
-
"Proxy type '{$type}' is not supported"
|
328 |
-
);
|
329 |
-
}
|
330 |
-
}
|
331 |
-
}
|
332 |
-
|
333 |
-
// set authentication data
|
334 |
-
if ($auth = $this->request->getAuth()) {
|
335 |
-
curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
|
336 |
-
switch ($auth['scheme']) {
|
337 |
-
case HTTP_Request2::AUTH_BASIC:
|
338 |
-
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
339 |
-
break;
|
340 |
-
case HTTP_Request2::AUTH_DIGEST:
|
341 |
-
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
342 |
-
}
|
343 |
-
}
|
344 |
-
|
345 |
-
// set SSL options
|
346 |
-
foreach ($this->request->getConfig() as $name => $value) {
|
347 |
-
if ('ssl_verify_host' == $name && null !== $value) {
|
348 |
-
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value? 2: 0);
|
349 |
-
} elseif (isset(self::$sslContextMap[$name]) && null !== $value) {
|
350 |
-
curl_setopt($ch, self::$sslContextMap[$name], $value);
|
351 |
-
}
|
352 |
-
}
|
353 |
-
|
354 |
-
$headers = $this->request->getHeaders();
|
355 |
-
// make cURL automagically send proper header
|
356 |
-
if (!isset($headers['accept-encoding'])) {
|
357 |
-
$headers['accept-encoding'] = '';
|
358 |
-
}
|
359 |
-
|
360 |
-
if (($jar = $this->request->getCookieJar())
|
361 |
-
&& ($cookies = $jar->getMatching($this->request->getUrl(), true))
|
362 |
-
) {
|
363 |
-
$headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
|
364 |
-
}
|
365 |
-
|
366 |
-
// set headers having special cURL keys
|
367 |
-
foreach (self::$headerMap as $name => $option) {
|
368 |
-
if (isset($headers[$name])) {
|
369 |
-
curl_setopt($ch, $option, $headers[$name]);
|
370 |
-
unset($headers[$name]);
|
371 |
-
}
|
372 |
-
}
|
373 |
-
|
374 |
-
$this->calculateRequestLength($headers);
|
375 |
-
if (isset($headers['content-length']) || isset($headers['transfer-encoding'])) {
|
376 |
-
$this->workaroundPhpBug47204($ch, $headers);
|
377 |
-
}
|
378 |
-
|
379 |
-
// set headers not having special keys
|
380 |
-
$headersFmt = array();
|
381 |
-
foreach ($headers as $name => $value) {
|
382 |
-
$canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
|
383 |
-
$headersFmt[] = $canonicalName . ': ' . $value;
|
384 |
-
}
|
385 |
-
curl_setopt($ch, CURLOPT_HTTPHEADER, $headersFmt);
|
386 |
-
|
387 |
-
return $ch;
|
388 |
-
}
|
389 |
-
|
390 |
-
/**
|
391 |
-
* Workaround for PHP bug #47204 that prevents rewinding request body
|
392 |
-
*
|
393 |
-
* The workaround consists of reading the entire request body into memory
|
394 |
-
* and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large
|
395 |
-
* file uploads, use Socket adapter instead.
|
396 |
-
*
|
397 |
-
* @param resource $ch cURL handle
|
398 |
-
* @param array &$headers Request headers
|
399 |
-
*/
|
400 |
-
protected function workaroundPhpBug47204($ch, &$headers)
|
401 |
-
{
|
402 |
-
// no redirects, no digest auth -> probably no rewind needed
|
403 |
-
if (!$this->request->getConfig('follow_redirects')
|
404 |
-
&& (!($auth = $this->request->getAuth())
|
405 |
-
|| HTTP_Request2::AUTH_DIGEST != $auth['scheme'])
|
406 |
-
) {
|
407 |
-
curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));
|
408 |
-
|
409 |
-
} else {
|
410 |
-
// rewind may be needed, read the whole body into memory
|
411 |
-
if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {
|
412 |
-
$this->requestBody = $this->requestBody->__toString();
|
413 |
-
|
414 |
-
} elseif (is_resource($this->requestBody)) {
|
415 |
-
$fp = $this->requestBody;
|
416 |
-
$this->requestBody = '';
|
417 |
-
while (!feof($fp)) {
|
418 |
-
$this->requestBody .= fread($fp, 16384);
|
419 |
-
}
|
420 |
-
}
|
421 |
-
// curl hangs up if content-length is present
|
422 |
-
unset($headers['content-length']);
|
423 |
-
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody);
|
424 |
-
}
|
425 |
-
}
|
426 |
-
|
427 |
-
/**
|
428 |
-
* Callback function called by cURL for reading the request body
|
429 |
-
*
|
430 |
-
* @param resource $ch cURL handle
|
431 |
-
* @param resource $fd file descriptor (not used)
|
432 |
-
* @param integer $length maximum length of data to return
|
433 |
-
*
|
434 |
-
* @return string part of the request body, up to $length bytes
|
435 |
-
*/
|
436 |
-
protected function callbackReadBody($ch, $fd, $length)
|
437 |
-
{
|
438 |
-
if (!$this->eventSentHeaders) {
|
439 |
-
$this->request->setLastEvent(
|
440 |
-
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
|
441 |
-
);
|
442 |
-
$this->eventSentHeaders = true;
|
443 |
-
}
|
444 |
-
if (in_array($this->request->getMethod(), self::$bodyDisallowed)
|
445 |
-
|| 0 == $this->contentLength || $this->position >= $this->contentLength
|
446 |
-
) {
|
447 |
-
return '';
|
448 |
-
}
|
449 |
-
if (is_string($this->requestBody)) {
|
450 |
-
$string = substr($this->requestBody, $this->position, $length);
|
451 |
-
} elseif (is_resource($this->requestBody)) {
|
452 |
-
$string = fread($this->requestBody, $length);
|
453 |
-
} else {
|
454 |
-
$string = $this->requestBody->read($length);
|
455 |
-
}
|
456 |
-
$this->request->setLastEvent('sentBodyPart', strlen($string));
|
457 |
-
$this->position += strlen($string);
|
458 |
-
return $string;
|
459 |
-
}
|
460 |
-
|
461 |
-
/**
|
462 |
-
* Callback function called by cURL for saving the response headers
|
463 |
-
*
|
464 |
-
* @param resource $ch cURL handle
|
465 |
-
* @param string $string response header (with trailing CRLF)
|
466 |
-
*
|
467 |
-
* @return integer number of bytes saved
|
468 |
-
* @see HTTP_Request2_Response::parseHeaderLine()
|
469 |
-
*/
|
470 |
-
protected function callbackWriteHeader($ch, $string)
|
471 |
-
{
|
472 |
-
// we may receive a second set of headers if doing e.g. digest auth
|
473 |
-
if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
|
474 |
-
// don't bother with 100-Continue responses (bug #15785)
|
475 |
-
if (!$this->eventSentHeaders
|
476 |
-
|| $this->response->getStatus() >= 200
|
477 |
-
) {
|
478 |
-
$this->request->setLastEvent(
|
479 |
-
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
|
480 |
-
);
|
481 |
-
}
|
482 |
-
$upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
|
483 |
-
// if body wasn't read by a callback, send event with total body size
|
484 |
-
if ($upload > $this->position) {
|
485 |
-
$this->request->setLastEvent(
|
486 |
-
'sentBodyPart', $upload - $this->position
|
487 |
-
);
|
488 |
-
$this->position = $upload;
|
489 |
-
}
|
490 |
-
if ($upload && (!$this->eventSentHeaders
|
491 |
-
|| $this->response->getStatus() >= 200)
|
492 |
-
) {
|
493 |
-
$this->request->setLastEvent('sentBody', $upload);
|
494 |
-
}
|
495 |
-
$this->eventSentHeaders = true;
|
496 |
-
// we'll need a new response object
|
497 |
-
if ($this->eventReceivedHeaders) {
|
498 |
-
$this->eventReceivedHeaders = false;
|
499 |
-
$this->response = null;
|
500 |
-
}
|
501 |
-
}
|
502 |
-
if (empty($this->response)) {
|
503 |
-
$this->response = new HTTP_Request2_Response(
|
504 |
-
$string, false, curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)
|
505 |
-
);
|
506 |
-
} else {
|
507 |
-
$this->response->parseHeaderLine($string);
|
508 |
-
if ('' == trim($string)) {
|
509 |
-
// don't bother with 100-Continue responses (bug #15785)
|
510 |
-
if (200 <= $this->response->getStatus()) {
|
511 |
-
$this->request->setLastEvent('receivedHeaders', $this->response);
|
512 |
-
}
|
513 |
-
|
514 |
-
if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) {
|
515 |
-
$redirectUrl = new Net_URL2($this->response->getHeader('location'));
|
516 |
-
|
517 |
-
// for versions lower than 5.2.10, check the redirection URL protocol
|
518 |
-
if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute()
|
519 |
-
&& !in_array($redirectUrl->getScheme(), array('http', 'https'))
|
520 |
-
) {
|
521 |
-
return -1;
|
522 |
-
}
|
523 |
-
|
524 |
-
if ($jar = $this->request->getCookieJar()) {
|
525 |
-
$jar->addCookiesFromResponse($this->response, $this->request->getUrl());
|
526 |
-
if (!$redirectUrl->isAbsolute()) {
|
527 |
-
$redirectUrl = $this->request->getUrl()->resolve($redirectUrl);
|
528 |
-
}
|
529 |
-
if ($cookies = $jar->getMatching($redirectUrl, true)) {
|
530 |
-
curl_setopt($ch, CURLOPT_COOKIE, $cookies);
|
531 |
-
}
|
532 |
-
}
|
533 |
-
}
|
534 |
-
$this->eventReceivedHeaders = true;
|
535 |
-
}
|
536 |
-
}
|
537 |
-
return strlen($string);
|
538 |
-
}
|
539 |
-
|
540 |
-
/**
|
541 |
-
* Callback function called by cURL for saving the response body
|
542 |
-
*
|
543 |
-
* @param resource $ch cURL handle (not used)
|
544 |
-
* @param string $string part of the response body
|
545 |
-
*
|
546 |
-
* @return integer number of bytes saved
|
547 |
-
* @throws HTTP_Request2_MessageException
|
548 |
-
* @see HTTP_Request2_Response::appendBody()
|
549 |
-
*/
|
550 |
-
protected function callbackWriteBody($ch, $string)
|
551 |
-
{
|
552 |
-
// cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if
|
553 |
-
// response doesn't start with proper HTTP status line (see bug #15716)
|
554 |
-
if (empty($this->response)) {
|
555 |
-
throw new HTTP_Request2_MessageException(
|
556 |
-
"Malformed response: {$string}",
|
557 |
-
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
558 |
-
);
|
559 |
-
}
|
560 |
-
if ($this->request->getConfig('store_body')) {
|
561 |
-
$this->response->appendBody($string);
|
562 |
-
}
|
563 |
-
$this->request->setLastEvent('receivedBodyPart', $string);
|
564 |
-
return strlen($string);
|
565 |
-
}
|
566 |
-
}
|
567 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Adapter for HTTP_Request2 wrapping around cURL extension
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Base class for HTTP_Request2 adapters
|
23 |
+
*/
|
24 |
+
require_once 'HTTP/Request2/Adapter.php';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Adapter for HTTP_Request2 wrapping around cURL extension
|
28 |
+
*
|
29 |
+
* @category HTTP
|
30 |
+
* @package HTTP_Request2
|
31 |
+
* @author Alexey Borzov <avb@php.net>
|
32 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
33 |
+
* @version Release: 2.2.1
|
34 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
35 |
+
*/
|
36 |
+
class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
|
37 |
+
{
|
38 |
+
/**
|
39 |
+
* Mapping of header names to cURL options
|
40 |
+
* @var array
|
41 |
+
*/
|
42 |
+
protected static $headerMap = array(
|
43 |
+
'accept-encoding' => CURLOPT_ENCODING,
|
44 |
+
'cookie' => CURLOPT_COOKIE,
|
45 |
+
'referer' => CURLOPT_REFERER,
|
46 |
+
'user-agent' => CURLOPT_USERAGENT
|
47 |
+
);
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Mapping of SSL context options to cURL options
|
51 |
+
* @var array
|
52 |
+
*/
|
53 |
+
protected static $sslContextMap = array(
|
54 |
+
'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,
|
55 |
+
'ssl_cafile' => CURLOPT_CAINFO,
|
56 |
+
'ssl_capath' => CURLOPT_CAPATH,
|
57 |
+
'ssl_local_cert' => CURLOPT_SSLCERT,
|
58 |
+
'ssl_passphrase' => CURLOPT_SSLCERTPASSWD
|
59 |
+
);
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Mapping of CURLE_* constants to Exception subclasses and error codes
|
63 |
+
* @var array
|
64 |
+
*/
|
65 |
+
protected static $errorMap = array(
|
66 |
+
CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException',
|
67 |
+
HTTP_Request2_Exception::NON_HTTP_REDIRECT),
|
68 |
+
CURLE_COULDNT_RESOLVE_PROXY => array('HTTP_Request2_ConnectionException'),
|
69 |
+
CURLE_COULDNT_RESOLVE_HOST => array('HTTP_Request2_ConnectionException'),
|
70 |
+
CURLE_COULDNT_CONNECT => array('HTTP_Request2_ConnectionException'),
|
71 |
+
// error returned from write callback
|
72 |
+
CURLE_WRITE_ERROR => array('HTTP_Request2_MessageException',
|
73 |
+
HTTP_Request2_Exception::NON_HTTP_REDIRECT),
|
74 |
+
CURLE_OPERATION_TIMEOUTED => array('HTTP_Request2_MessageException',
|
75 |
+
HTTP_Request2_Exception::TIMEOUT),
|
76 |
+
CURLE_HTTP_RANGE_ERROR => array('HTTP_Request2_MessageException'),
|
77 |
+
CURLE_SSL_CONNECT_ERROR => array('HTTP_Request2_ConnectionException'),
|
78 |
+
CURLE_LIBRARY_NOT_FOUND => array('HTTP_Request2_LogicException',
|
79 |
+
HTTP_Request2_Exception::MISCONFIGURATION),
|
80 |
+
CURLE_FUNCTION_NOT_FOUND => array('HTTP_Request2_LogicException',
|
81 |
+
HTTP_Request2_Exception::MISCONFIGURATION),
|
82 |
+
CURLE_ABORTED_BY_CALLBACK => array('HTTP_Request2_MessageException',
|
83 |
+
HTTP_Request2_Exception::NON_HTTP_REDIRECT),
|
84 |
+
CURLE_TOO_MANY_REDIRECTS => array('HTTP_Request2_MessageException',
|
85 |
+
HTTP_Request2_Exception::TOO_MANY_REDIRECTS),
|
86 |
+
CURLE_SSL_PEER_CERTIFICATE => array('HTTP_Request2_ConnectionException'),
|
87 |
+
CURLE_GOT_NOTHING => array('HTTP_Request2_MessageException'),
|
88 |
+
CURLE_SSL_ENGINE_NOTFOUND => array('HTTP_Request2_LogicException',
|
89 |
+
HTTP_Request2_Exception::MISCONFIGURATION),
|
90 |
+
CURLE_SSL_ENGINE_SETFAILED => array('HTTP_Request2_LogicException',
|
91 |
+
HTTP_Request2_Exception::MISCONFIGURATION),
|
92 |
+
CURLE_SEND_ERROR => array('HTTP_Request2_MessageException'),
|
93 |
+
CURLE_RECV_ERROR => array('HTTP_Request2_MessageException'),
|
94 |
+
CURLE_SSL_CERTPROBLEM => array('HTTP_Request2_LogicException',
|
95 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT),
|
96 |
+
CURLE_SSL_CIPHER => array('HTTP_Request2_ConnectionException'),
|
97 |
+
CURLE_SSL_CACERT => array('HTTP_Request2_ConnectionException'),
|
98 |
+
CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'),
|
99 |
+
);
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Response being received
|
103 |
+
* @var HTTP_Request2_Response
|
104 |
+
*/
|
105 |
+
protected $response;
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Whether 'sentHeaders' event was sent to observers
|
109 |
+
* @var boolean
|
110 |
+
*/
|
111 |
+
protected $eventSentHeaders = false;
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Whether 'receivedHeaders' event was sent to observers
|
115 |
+
* @var boolean
|
116 |
+
*/
|
117 |
+
protected $eventReceivedHeaders = false;
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Position within request body
|
121 |
+
* @var integer
|
122 |
+
* @see callbackReadBody()
|
123 |
+
*/
|
124 |
+
protected $position = 0;
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Information about last transfer, as returned by curl_getinfo()
|
128 |
+
* @var array
|
129 |
+
*/
|
130 |
+
protected $lastInfo;
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Creates a subclass of HTTP_Request2_Exception from curl error data
|
134 |
+
*
|
135 |
+
* @param resource $ch curl handle
|
136 |
+
*
|
137 |
+
* @return HTTP_Request2_Exception
|
138 |
+
*/
|
139 |
+
protected static function wrapCurlError($ch)
|
140 |
+
{
|
141 |
+
$nativeCode = curl_errno($ch);
|
142 |
+
$message = 'Curl error: ' . curl_error($ch);
|
143 |
+
if (!isset(self::$errorMap[$nativeCode])) {
|
144 |
+
return new HTTP_Request2_Exception($message, 0, $nativeCode);
|
145 |
+
} else {
|
146 |
+
$class = self::$errorMap[$nativeCode][0];
|
147 |
+
$code = empty(self::$errorMap[$nativeCode][1])
|
148 |
+
? 0 : self::$errorMap[$nativeCode][1];
|
149 |
+
return new $class($message, $code, $nativeCode);
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Sends request to the remote server and returns its response
|
155 |
+
*
|
156 |
+
* @param HTTP_Request2 $request HTTP request message
|
157 |
+
*
|
158 |
+
* @return HTTP_Request2_Response
|
159 |
+
* @throws HTTP_Request2_Exception
|
160 |
+
*/
|
161 |
+
public function sendRequest(HTTP_Request2 $request)
|
162 |
+
{
|
163 |
+
if (!extension_loaded('curl')) {
|
164 |
+
throw new HTTP_Request2_LogicException(
|
165 |
+
'cURL extension not available', HTTP_Request2_Exception::MISCONFIGURATION
|
166 |
+
);
|
167 |
+
}
|
168 |
+
|
169 |
+
$this->request = $request;
|
170 |
+
$this->response = null;
|
171 |
+
$this->position = 0;
|
172 |
+
$this->eventSentHeaders = false;
|
173 |
+
$this->eventReceivedHeaders = false;
|
174 |
+
|
175 |
+
try {
|
176 |
+
if (false === curl_exec($ch = $this->createCurlHandle())) {
|
177 |
+
$e = self::wrapCurlError($ch);
|
178 |
+
}
|
179 |
+
} catch (Exception $e) {
|
180 |
+
}
|
181 |
+
if (isset($ch)) {
|
182 |
+
$this->lastInfo = curl_getinfo($ch);
|
183 |
+
curl_close($ch);
|
184 |
+
}
|
185 |
+
|
186 |
+
$response = $this->response;
|
187 |
+
unset($this->request, $this->requestBody, $this->response);
|
188 |
+
|
189 |
+
if (!empty($e)) {
|
190 |
+
throw $e;
|
191 |
+
}
|
192 |
+
|
193 |
+
if ($jar = $request->getCookieJar()) {
|
194 |
+
$jar->addCookiesFromResponse($response, $request->getUrl());
|
195 |
+
}
|
196 |
+
|
197 |
+
if (0 < $this->lastInfo['size_download']) {
|
198 |
+
$request->setLastEvent('receivedBody', $response);
|
199 |
+
}
|
200 |
+
return $response;
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Returns information about last transfer
|
205 |
+
*
|
206 |
+
* @return array associative array as returned by curl_getinfo()
|
207 |
+
*/
|
208 |
+
public function getInfo()
|
209 |
+
{
|
210 |
+
return $this->lastInfo;
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* Creates a new cURL handle and populates it with data from the request
|
215 |
+
*
|
216 |
+
* @return resource a cURL handle, as created by curl_init()
|
217 |
+
* @throws HTTP_Request2_LogicException
|
218 |
+
* @throws HTTP_Request2_NotImplementedException
|
219 |
+
*/
|
220 |
+
protected function createCurlHandle()
|
221 |
+
{
|
222 |
+
$ch = curl_init();
|
223 |
+
|
224 |
+
curl_setopt_array($ch, array(
|
225 |
+
// setup write callbacks
|
226 |
+
CURLOPT_HEADERFUNCTION => array($this, 'callbackWriteHeader'),
|
227 |
+
CURLOPT_WRITEFUNCTION => array($this, 'callbackWriteBody'),
|
228 |
+
// buffer size
|
229 |
+
CURLOPT_BUFFERSIZE => $this->request->getConfig('buffer_size'),
|
230 |
+
// connection timeout
|
231 |
+
CURLOPT_CONNECTTIMEOUT => $this->request->getConfig('connect_timeout'),
|
232 |
+
// save full outgoing headers, in case someone is interested
|
233 |
+
CURLINFO_HEADER_OUT => true,
|
234 |
+
// request url
|
235 |
+
CURLOPT_URL => $this->request->getUrl()->getUrl()
|
236 |
+
));
|
237 |
+
|
238 |
+
// set up redirects
|
239 |
+
if (!$this->request->getConfig('follow_redirects')) {
|
240 |
+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
|
241 |
+
} else {
|
242 |
+
if (!@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)) {
|
243 |
+
throw new HTTP_Request2_LogicException(
|
244 |
+
'Redirect support in curl is unavailable due to open_basedir or safe_mode setting',
|
245 |
+
HTTP_Request2_Exception::MISCONFIGURATION
|
246 |
+
);
|
247 |
+
}
|
248 |
+
curl_setopt($ch, CURLOPT_MAXREDIRS, $this->request->getConfig('max_redirects'));
|
249 |
+
// limit redirects to http(s), works in 5.2.10+
|
250 |
+
if (defined('CURLOPT_REDIR_PROTOCOLS')) {
|
251 |
+
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
252 |
+
}
|
253 |
+
// works in 5.3.2+, http://bugs.php.net/bug.php?id=49571
|
254 |
+
if ($this->request->getConfig('strict_redirects') && defined('CURLOPT_POSTREDIR')) {
|
255 |
+
curl_setopt($ch, CURLOPT_POSTREDIR, 3);
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
// set local IP via CURLOPT_INTERFACE (request #19515)
|
260 |
+
if ($ip = $this->request->getConfig('local_ip')) {
|
261 |
+
curl_setopt($ch, CURLOPT_INTERFACE, $ip);
|
262 |
+
}
|
263 |
+
|
264 |
+
// request timeout
|
265 |
+
if ($timeout = $this->request->getConfig('timeout')) {
|
266 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
267 |
+
}
|
268 |
+
|
269 |
+
// set HTTP version
|
270 |
+
switch ($this->request->getConfig('protocol_version')) {
|
271 |
+
case '1.0':
|
272 |
+
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
273 |
+
break;
|
274 |
+
case '1.1':
|
275 |
+
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
276 |
+
}
|
277 |
+
|
278 |
+
// set request method
|
279 |
+
switch ($this->request->getMethod()) {
|
280 |
+
case HTTP_Request2::METHOD_GET:
|
281 |
+
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
282 |
+
break;
|
283 |
+
case HTTP_Request2::METHOD_POST:
|
284 |
+
curl_setopt($ch, CURLOPT_POST, true);
|
285 |
+
break;
|
286 |
+
case HTTP_Request2::METHOD_HEAD:
|
287 |
+
curl_setopt($ch, CURLOPT_NOBODY, true);
|
288 |
+
break;
|
289 |
+
case HTTP_Request2::METHOD_PUT:
|
290 |
+
curl_setopt($ch, CURLOPT_UPLOAD, true);
|
291 |
+
break;
|
292 |
+
default:
|
293 |
+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
|
294 |
+
}
|
295 |
+
|
296 |
+
// set proxy, if needed
|
297 |
+
if ($host = $this->request->getConfig('proxy_host')) {
|
298 |
+
if (!($port = $this->request->getConfig('proxy_port'))) {
|
299 |
+
throw new HTTP_Request2_LogicException(
|
300 |
+
'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE
|
301 |
+
);
|
302 |
+
}
|
303 |
+
curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
|
304 |
+
if ($user = $this->request->getConfig('proxy_user')) {
|
305 |
+
curl_setopt(
|
306 |
+
$ch, CURLOPT_PROXYUSERPWD,
|
307 |
+
$user . ':' . $this->request->getConfig('proxy_password')
|
308 |
+
);
|
309 |
+
switch ($this->request->getConfig('proxy_auth_scheme')) {
|
310 |
+
case HTTP_Request2::AUTH_BASIC:
|
311 |
+
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
312 |
+
break;
|
313 |
+
case HTTP_Request2::AUTH_DIGEST:
|
314 |
+
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
|
315 |
+
}
|
316 |
+
}
|
317 |
+
if ($type = $this->request->getConfig('proxy_type')) {
|
318 |
+
switch ($type) {
|
319 |
+
case 'http':
|
320 |
+
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
321 |
+
break;
|
322 |
+
case 'socks5':
|
323 |
+
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
324 |
+
break;
|
325 |
+
default:
|
326 |
+
throw new HTTP_Request2_NotImplementedException(
|
327 |
+
"Proxy type '{$type}' is not supported"
|
328 |
+
);
|
329 |
+
}
|
330 |
+
}
|
331 |
+
}
|
332 |
+
|
333 |
+
// set authentication data
|
334 |
+
if ($auth = $this->request->getAuth()) {
|
335 |
+
curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
|
336 |
+
switch ($auth['scheme']) {
|
337 |
+
case HTTP_Request2::AUTH_BASIC:
|
338 |
+
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
339 |
+
break;
|
340 |
+
case HTTP_Request2::AUTH_DIGEST:
|
341 |
+
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
342 |
+
}
|
343 |
+
}
|
344 |
+
|
345 |
+
// set SSL options
|
346 |
+
foreach ($this->request->getConfig() as $name => $value) {
|
347 |
+
if ('ssl_verify_host' == $name && null !== $value) {
|
348 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value? 2: 0);
|
349 |
+
} elseif (isset(self::$sslContextMap[$name]) && null !== $value) {
|
350 |
+
curl_setopt($ch, self::$sslContextMap[$name], $value);
|
351 |
+
}
|
352 |
+
}
|
353 |
+
|
354 |
+
$headers = $this->request->getHeaders();
|
355 |
+
// make cURL automagically send proper header
|
356 |
+
if (!isset($headers['accept-encoding'])) {
|
357 |
+
$headers['accept-encoding'] = '';
|
358 |
+
}
|
359 |
+
|
360 |
+
if (($jar = $this->request->getCookieJar())
|
361 |
+
&& ($cookies = $jar->getMatching($this->request->getUrl(), true))
|
362 |
+
) {
|
363 |
+
$headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
|
364 |
+
}
|
365 |
+
|
366 |
+
// set headers having special cURL keys
|
367 |
+
foreach (self::$headerMap as $name => $option) {
|
368 |
+
if (isset($headers[$name])) {
|
369 |
+
curl_setopt($ch, $option, $headers[$name]);
|
370 |
+
unset($headers[$name]);
|
371 |
+
}
|
372 |
+
}
|
373 |
+
|
374 |
+
$this->calculateRequestLength($headers);
|
375 |
+
if (isset($headers['content-length']) || isset($headers['transfer-encoding'])) {
|
376 |
+
$this->workaroundPhpBug47204($ch, $headers);
|
377 |
+
}
|
378 |
+
|
379 |
+
// set headers not having special keys
|
380 |
+
$headersFmt = array();
|
381 |
+
foreach ($headers as $name => $value) {
|
382 |
+
$canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
|
383 |
+
$headersFmt[] = $canonicalName . ': ' . $value;
|
384 |
+
}
|
385 |
+
curl_setopt($ch, CURLOPT_HTTPHEADER, $headersFmt);
|
386 |
+
|
387 |
+
return $ch;
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* Workaround for PHP bug #47204 that prevents rewinding request body
|
392 |
+
*
|
393 |
+
* The workaround consists of reading the entire request body into memory
|
394 |
+
* and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large
|
395 |
+
* file uploads, use Socket adapter instead.
|
396 |
+
*
|
397 |
+
* @param resource $ch cURL handle
|
398 |
+
* @param array &$headers Request headers
|
399 |
+
*/
|
400 |
+
protected function workaroundPhpBug47204($ch, &$headers)
|
401 |
+
{
|
402 |
+
// no redirects, no digest auth -> probably no rewind needed
|
403 |
+
if (!$this->request->getConfig('follow_redirects')
|
404 |
+
&& (!($auth = $this->request->getAuth())
|
405 |
+
|| HTTP_Request2::AUTH_DIGEST != $auth['scheme'])
|
406 |
+
) {
|
407 |
+
curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));
|
408 |
+
|
409 |
+
} else {
|
410 |
+
// rewind may be needed, read the whole body into memory
|
411 |
+
if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {
|
412 |
+
$this->requestBody = $this->requestBody->__toString();
|
413 |
+
|
414 |
+
} elseif (is_resource($this->requestBody)) {
|
415 |
+
$fp = $this->requestBody;
|
416 |
+
$this->requestBody = '';
|
417 |
+
while (!feof($fp)) {
|
418 |
+
$this->requestBody .= fread($fp, 16384);
|
419 |
+
}
|
420 |
+
}
|
421 |
+
// curl hangs up if content-length is present
|
422 |
+
unset($headers['content-length']);
|
423 |
+
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody);
|
424 |
+
}
|
425 |
+
}
|
426 |
+
|
427 |
+
/**
|
428 |
+
* Callback function called by cURL for reading the request body
|
429 |
+
*
|
430 |
+
* @param resource $ch cURL handle
|
431 |
+
* @param resource $fd file descriptor (not used)
|
432 |
+
* @param integer $length maximum length of data to return
|
433 |
+
*
|
434 |
+
* @return string part of the request body, up to $length bytes
|
435 |
+
*/
|
436 |
+
protected function callbackReadBody($ch, $fd, $length)
|
437 |
+
{
|
438 |
+
if (!$this->eventSentHeaders) {
|
439 |
+
$this->request->setLastEvent(
|
440 |
+
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
|
441 |
+
);
|
442 |
+
$this->eventSentHeaders = true;
|
443 |
+
}
|
444 |
+
if (in_array($this->request->getMethod(), self::$bodyDisallowed)
|
445 |
+
|| 0 == $this->contentLength || $this->position >= $this->contentLength
|
446 |
+
) {
|
447 |
+
return '';
|
448 |
+
}
|
449 |
+
if (is_string($this->requestBody)) {
|
450 |
+
$string = substr($this->requestBody, $this->position, $length);
|
451 |
+
} elseif (is_resource($this->requestBody)) {
|
452 |
+
$string = fread($this->requestBody, $length);
|
453 |
+
} else {
|
454 |
+
$string = $this->requestBody->read($length);
|
455 |
+
}
|
456 |
+
$this->request->setLastEvent('sentBodyPart', strlen($string));
|
457 |
+
$this->position += strlen($string);
|
458 |
+
return $string;
|
459 |
+
}
|
460 |
+
|
461 |
+
/**
|
462 |
+
* Callback function called by cURL for saving the response headers
|
463 |
+
*
|
464 |
+
* @param resource $ch cURL handle
|
465 |
+
* @param string $string response header (with trailing CRLF)
|
466 |
+
*
|
467 |
+
* @return integer number of bytes saved
|
468 |
+
* @see HTTP_Request2_Response::parseHeaderLine()
|
469 |
+
*/
|
470 |
+
protected function callbackWriteHeader($ch, $string)
|
471 |
+
{
|
472 |
+
// we may receive a second set of headers if doing e.g. digest auth
|
473 |
+
if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
|
474 |
+
// don't bother with 100-Continue responses (bug #15785)
|
475 |
+
if (!$this->eventSentHeaders
|
476 |
+
|| $this->response->getStatus() >= 200
|
477 |
+
) {
|
478 |
+
$this->request->setLastEvent(
|
479 |
+
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
|
480 |
+
);
|
481 |
+
}
|
482 |
+
$upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
|
483 |
+
// if body wasn't read by a callback, send event with total body size
|
484 |
+
if ($upload > $this->position) {
|
485 |
+
$this->request->setLastEvent(
|
486 |
+
'sentBodyPart', $upload - $this->position
|
487 |
+
);
|
488 |
+
$this->position = $upload;
|
489 |
+
}
|
490 |
+
if ($upload && (!$this->eventSentHeaders
|
491 |
+
|| $this->response->getStatus() >= 200)
|
492 |
+
) {
|
493 |
+
$this->request->setLastEvent('sentBody', $upload);
|
494 |
+
}
|
495 |
+
$this->eventSentHeaders = true;
|
496 |
+
// we'll need a new response object
|
497 |
+
if ($this->eventReceivedHeaders) {
|
498 |
+
$this->eventReceivedHeaders = false;
|
499 |
+
$this->response = null;
|
500 |
+
}
|
501 |
+
}
|
502 |
+
if (empty($this->response)) {
|
503 |
+
$this->response = new HTTP_Request2_Response(
|
504 |
+
$string, false, curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)
|
505 |
+
);
|
506 |
+
} else {
|
507 |
+
$this->response->parseHeaderLine($string);
|
508 |
+
if ('' == trim($string)) {
|
509 |
+
// don't bother with 100-Continue responses (bug #15785)
|
510 |
+
if (200 <= $this->response->getStatus()) {
|
511 |
+
$this->request->setLastEvent('receivedHeaders', $this->response);
|
512 |
+
}
|
513 |
+
|
514 |
+
if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) {
|
515 |
+
$redirectUrl = new Net_URL2($this->response->getHeader('location'));
|
516 |
+
|
517 |
+
// for versions lower than 5.2.10, check the redirection URL protocol
|
518 |
+
if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute()
|
519 |
+
&& !in_array($redirectUrl->getScheme(), array('http', 'https'))
|
520 |
+
) {
|
521 |
+
return -1;
|
522 |
+
}
|
523 |
+
|
524 |
+
if ($jar = $this->request->getCookieJar()) {
|
525 |
+
$jar->addCookiesFromResponse($this->response, $this->request->getUrl());
|
526 |
+
if (!$redirectUrl->isAbsolute()) {
|
527 |
+
$redirectUrl = $this->request->getUrl()->resolve($redirectUrl);
|
528 |
+
}
|
529 |
+
if ($cookies = $jar->getMatching($redirectUrl, true)) {
|
530 |
+
curl_setopt($ch, CURLOPT_COOKIE, $cookies);
|
531 |
+
}
|
532 |
+
}
|
533 |
+
}
|
534 |
+
$this->eventReceivedHeaders = true;
|
535 |
+
}
|
536 |
+
}
|
537 |
+
return strlen($string);
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Callback function called by cURL for saving the response body
|
542 |
+
*
|
543 |
+
* @param resource $ch cURL handle (not used)
|
544 |
+
* @param string $string part of the response body
|
545 |
+
*
|
546 |
+
* @return integer number of bytes saved
|
547 |
+
* @throws HTTP_Request2_MessageException
|
548 |
+
* @see HTTP_Request2_Response::appendBody()
|
549 |
+
*/
|
550 |
+
protected function callbackWriteBody($ch, $string)
|
551 |
+
{
|
552 |
+
// cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if
|
553 |
+
// response doesn't start with proper HTTP status line (see bug #15716)
|
554 |
+
if (empty($this->response)) {
|
555 |
+
throw new HTTP_Request2_MessageException(
|
556 |
+
"Malformed response: {$string}",
|
557 |
+
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
558 |
+
);
|
559 |
+
}
|
560 |
+
if ($this->request->getConfig('store_body')) {
|
561 |
+
$this->response->appendBody($string);
|
562 |
+
}
|
563 |
+
$this->request->setLastEvent('receivedBodyPart', $string);
|
564 |
+
return strlen($string);
|
565 |
+
}
|
566 |
+
}
|
567 |
+
?>
|
vendor/PEAR/HTTP/Request2/Adapter/Mock.php
CHANGED
@@ -1,166 +1,166 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Mock adapter intended for testing
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Base class for HTTP_Request2 adapters
|
23 |
-
*/
|
24 |
-
require_once 'HTTP/Request2/Adapter.php';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Mock adapter intended for testing
|
28 |
-
*
|
29 |
-
* Can be used to test applications depending on HTTP_Request2 package without
|
30 |
-
* actually performing any HTTP requests. This adapter will return responses
|
31 |
-
* previously added via addResponse()
|
32 |
-
* <code>
|
33 |
-
* $mock = new HTTP_Request2_Adapter_Mock();
|
34 |
-
* $mock->addResponse("HTTP/1.1 ... ");
|
35 |
-
*
|
36 |
-
* $request = new HTTP_Request2();
|
37 |
-
* $request->setAdapter($mock);
|
38 |
-
*
|
39 |
-
* // This will return the response set above
|
40 |
-
* $response = $req->send();
|
41 |
-
* </code>
|
42 |
-
*
|
43 |
-
* @category HTTP
|
44 |
-
* @package HTTP_Request2
|
45 |
-
* @author Alexey Borzov <avb@php.net>
|
46 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
47 |
-
* @version Release: 2.2.1
|
48 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
49 |
-
*/
|
50 |
-
class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
|
51 |
-
{
|
52 |
-
/**
|
53 |
-
* A queue of responses to be returned by sendRequest()
|
54 |
-
* @var array
|
55 |
-
*/
|
56 |
-
protected $responses = array();
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Returns the next response from the queue built by addResponse()
|
60 |
-
*
|
61 |
-
* Only responses without explicit URLs or with URLs equal to request URL
|
62 |
-
* will be considered. If matching response is not found or the queue is
|
63 |
-
* empty then default empty response with status 400 will be returned,
|
64 |
-
* if an Exception object was added to the queue it will be thrown.
|
65 |
-
*
|
66 |
-
* @param HTTP_Request2 $request HTTP request message
|
67 |
-
*
|
68 |
-
* @return HTTP_Request2_Response
|
69 |
-
* @throws Exception
|
70 |
-
*/
|
71 |
-
public function sendRequest(HTTP_Request2 $request)
|
72 |
-
{
|
73 |
-
$requestUrl = (string)$request->getUrl();
|
74 |
-
$response = null;
|
75 |
-
foreach ($this->responses as $k => $v) {
|
76 |
-
if (!$v[1] || $requestUrl == $v[1]) {
|
77 |
-
$response = $v[0];
|
78 |
-
array_splice($this->responses, $k, 1);
|
79 |
-
break;
|
80 |
-
}
|
81 |
-
}
|
82 |
-
if (!$response) {
|
83 |
-
return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
|
84 |
-
|
85 |
-
} elseif ($response instanceof HTTP_Request2_Response) {
|
86 |
-
return $response;
|
87 |
-
|
88 |
-
} else {
|
89 |
-
// rethrow the exception
|
90 |
-
$class = get_class($response);
|
91 |
-
$message = $response->getMessage();
|
92 |
-
$code = $response->getCode();
|
93 |
-
throw new $class($message, $code);
|
94 |
-
}
|
95 |
-
}
|
96 |
-
|
97 |
-
/**
|
98 |
-
* Adds response to the queue
|
99 |
-
*
|
100 |
-
* @param mixed $response either a string, a pointer to an open file,
|
101 |
-
* an instance of HTTP_Request2_Response or Exception
|
102 |
-
* @param string $url A request URL this response should be valid for
|
103 |
-
* (see {@link http://pear.php.net/bugs/bug.php?id=19276})
|
104 |
-
*
|
105 |
-
* @throws HTTP_Request2_Exception
|
106 |
-
*/
|
107 |
-
public function addResponse($response, $url = null)
|
108 |
-
{
|
109 |
-
if (is_string($response)) {
|
110 |
-
$response = self::createResponseFromString($response);
|
111 |
-
} elseif (is_resource($response)) {
|
112 |
-
$response = self::createResponseFromFile($response);
|
113 |
-
} elseif (!$response instanceof HTTP_Request2_Response &&
|
114 |
-
!$response instanceof Exception
|
115 |
-
) {
|
116 |
-
throw new HTTP_Request2_Exception('Parameter is not a valid response');
|
117 |
-
}
|
118 |
-
$this->responses[] = array($response, $url);
|
119 |
-
}
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Creates a new HTTP_Request2_Response object from a string
|
123 |
-
*
|
124 |
-
* @param string $str string containing HTTP response message
|
125 |
-
*
|
126 |
-
* @return HTTP_Request2_Response
|
127 |
-
* @throws HTTP_Request2_Exception
|
128 |
-
*/
|
129 |
-
public static function createResponseFromString($str)
|
130 |
-
{
|
131 |
-
$parts = preg_split('!(\r?\n){2}!m', $str, 2);
|
132 |
-
$headerLines = explode("\n", $parts[0]);
|
133 |
-
$response = new HTTP_Request2_Response(array_shift($headerLines));
|
134 |
-
foreach ($headerLines as $headerLine) {
|
135 |
-
$response->parseHeaderLine($headerLine);
|
136 |
-
}
|
137 |
-
$response->parseHeaderLine('');
|
138 |
-
if (isset($parts[1])) {
|
139 |
-
$response->appendBody($parts[1]);
|
140 |
-
}
|
141 |
-
return $response;
|
142 |
-
}
|
143 |
-
|
144 |
-
/**
|
145 |
-
* Creates a new HTTP_Request2_Response object from a file
|
146 |
-
*
|
147 |
-
* @param resource $fp file pointer returned by fopen()
|
148 |
-
*
|
149 |
-
* @return HTTP_Request2_Response
|
150 |
-
* @throws HTTP_Request2_Exception
|
151 |
-
*/
|
152 |
-
public static function createResponseFromFile($fp)
|
153 |
-
{
|
154 |
-
$response = new HTTP_Request2_Response(fgets($fp));
|
155 |
-
do {
|
156 |
-
$headerLine = fgets($fp);
|
157 |
-
$response->parseHeaderLine($headerLine);
|
158 |
-
} while ('' != trim($headerLine));
|
159 |
-
|
160 |
-
while (!feof($fp)) {
|
161 |
-
$response->appendBody(fread($fp, 8192));
|
162 |
-
}
|
163 |
-
return $response;
|
164 |
-
}
|
165 |
-
}
|
166 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Mock adapter intended for testing
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Base class for HTTP_Request2 adapters
|
23 |
+
*/
|
24 |
+
require_once 'HTTP/Request2/Adapter.php';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Mock adapter intended for testing
|
28 |
+
*
|
29 |
+
* Can be used to test applications depending on HTTP_Request2 package without
|
30 |
+
* actually performing any HTTP requests. This adapter will return responses
|
31 |
+
* previously added via addResponse()
|
32 |
+
* <code>
|
33 |
+
* $mock = new HTTP_Request2_Adapter_Mock();
|
34 |
+
* $mock->addResponse("HTTP/1.1 ... ");
|
35 |
+
*
|
36 |
+
* $request = new HTTP_Request2();
|
37 |
+
* $request->setAdapter($mock);
|
38 |
+
*
|
39 |
+
* // This will return the response set above
|
40 |
+
* $response = $req->send();
|
41 |
+
* </code>
|
42 |
+
*
|
43 |
+
* @category HTTP
|
44 |
+
* @package HTTP_Request2
|
45 |
+
* @author Alexey Borzov <avb@php.net>
|
46 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
47 |
+
* @version Release: 2.2.1
|
48 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
49 |
+
*/
|
50 |
+
class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
|
51 |
+
{
|
52 |
+
/**
|
53 |
+
* A queue of responses to be returned by sendRequest()
|
54 |
+
* @var array
|
55 |
+
*/
|
56 |
+
protected $responses = array();
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Returns the next response from the queue built by addResponse()
|
60 |
+
*
|
61 |
+
* Only responses without explicit URLs or with URLs equal to request URL
|
62 |
+
* will be considered. If matching response is not found or the queue is
|
63 |
+
* empty then default empty response with status 400 will be returned,
|
64 |
+
* if an Exception object was added to the queue it will be thrown.
|
65 |
+
*
|
66 |
+
* @param HTTP_Request2 $request HTTP request message
|
67 |
+
*
|
68 |
+
* @return HTTP_Request2_Response
|
69 |
+
* @throws Exception
|
70 |
+
*/
|
71 |
+
public function sendRequest(HTTP_Request2 $request)
|
72 |
+
{
|
73 |
+
$requestUrl = (string)$request->getUrl();
|
74 |
+
$response = null;
|
75 |
+
foreach ($this->responses as $k => $v) {
|
76 |
+
if (!$v[1] || $requestUrl == $v[1]) {
|
77 |
+
$response = $v[0];
|
78 |
+
array_splice($this->responses, $k, 1);
|
79 |
+
break;
|
80 |
+
}
|
81 |
+
}
|
82 |
+
if (!$response) {
|
83 |
+
return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
|
84 |
+
|
85 |
+
} elseif ($response instanceof HTTP_Request2_Response) {
|
86 |
+
return $response;
|
87 |
+
|
88 |
+
} else {
|
89 |
+
// rethrow the exception
|
90 |
+
$class = get_class($response);
|
91 |
+
$message = $response->getMessage();
|
92 |
+
$code = $response->getCode();
|
93 |
+
throw new $class($message, $code);
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Adds response to the queue
|
99 |
+
*
|
100 |
+
* @param mixed $response either a string, a pointer to an open file,
|
101 |
+
* an instance of HTTP_Request2_Response or Exception
|
102 |
+
* @param string $url A request URL this response should be valid for
|
103 |
+
* (see {@link http://pear.php.net/bugs/bug.php?id=19276})
|
104 |
+
*
|
105 |
+
* @throws HTTP_Request2_Exception
|
106 |
+
*/
|
107 |
+
public function addResponse($response, $url = null)
|
108 |
+
{
|
109 |
+
if (is_string($response)) {
|
110 |
+
$response = self::createResponseFromString($response);
|
111 |
+
} elseif (is_resource($response)) {
|
112 |
+
$response = self::createResponseFromFile($response);
|
113 |
+
} elseif (!$response instanceof HTTP_Request2_Response &&
|
114 |
+
!$response instanceof Exception
|
115 |
+
) {
|
116 |
+
throw new HTTP_Request2_Exception('Parameter is not a valid response');
|
117 |
+
}
|
118 |
+
$this->responses[] = array($response, $url);
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Creates a new HTTP_Request2_Response object from a string
|
123 |
+
*
|
124 |
+
* @param string $str string containing HTTP response message
|
125 |
+
*
|
126 |
+
* @return HTTP_Request2_Response
|
127 |
+
* @throws HTTP_Request2_Exception
|
128 |
+
*/
|
129 |
+
public static function createResponseFromString($str)
|
130 |
+
{
|
131 |
+
$parts = preg_split('!(\r?\n){2}!m', $str, 2);
|
132 |
+
$headerLines = explode("\n", $parts[0]);
|
133 |
+
$response = new HTTP_Request2_Response(array_shift($headerLines));
|
134 |
+
foreach ($headerLines as $headerLine) {
|
135 |
+
$response->parseHeaderLine($headerLine);
|
136 |
+
}
|
137 |
+
$response->parseHeaderLine('');
|
138 |
+
if (isset($parts[1])) {
|
139 |
+
$response->appendBody($parts[1]);
|
140 |
+
}
|
141 |
+
return $response;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Creates a new HTTP_Request2_Response object from a file
|
146 |
+
*
|
147 |
+
* @param resource $fp file pointer returned by fopen()
|
148 |
+
*
|
149 |
+
* @return HTTP_Request2_Response
|
150 |
+
* @throws HTTP_Request2_Exception
|
151 |
+
*/
|
152 |
+
public static function createResponseFromFile($fp)
|
153 |
+
{
|
154 |
+
$response = new HTTP_Request2_Response(fgets($fp));
|
155 |
+
do {
|
156 |
+
$headerLine = fgets($fp);
|
157 |
+
$response->parseHeaderLine($headerLine);
|
158 |
+
} while ('' != trim($headerLine));
|
159 |
+
|
160 |
+
while (!feof($fp)) {
|
161 |
+
$response->appendBody(fread($fp, 8192));
|
162 |
+
}
|
163 |
+
return $response;
|
164 |
+
}
|
165 |
+
}
|
166 |
?>
|
vendor/PEAR/HTTP/Request2/Adapter/Socket.php
CHANGED
@@ -1,1121 +1,1121 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Socket-based adapter for HTTP_Request2
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/** Base class for HTTP_Request2 adapters */
|
22 |
-
require_once 'HTTP/Request2/Adapter.php';
|
23 |
-
|
24 |
-
/** Socket wrapper class */
|
25 |
-
require_once 'HTTP/Request2/SocketWrapper.php';
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Socket-based adapter for HTTP_Request2
|
29 |
-
*
|
30 |
-
* This adapter uses only PHP sockets and will work on almost any PHP
|
31 |
-
* environment. Code is based on original HTTP_Request PEAR package.
|
32 |
-
*
|
33 |
-
* @category HTTP
|
34 |
-
* @package HTTP_Request2
|
35 |
-
* @author Alexey Borzov <avb@php.net>
|
36 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
37 |
-
* @version Release: 2.2.1
|
38 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
39 |
-
*/
|
40 |
-
class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
|
41 |
-
{
|
42 |
-
/**
|
43 |
-
* Regular expression for 'token' rule from RFC 2616
|
44 |
-
*/
|
45 |
-
const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Regular expression for 'quoted-string' rule from RFC 2616
|
49 |
-
*/
|
50 |
-
const REGEXP_QUOTED_STRING = '"(?>[^"\\\\]+|\\\\.)*"';
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Connected sockets, needed for Keep-Alive support
|
54 |
-
* @var array
|
55 |
-
* @see connect()
|
56 |
-
*/
|
57 |
-
protected static $sockets = array();
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Data for digest authentication scheme
|
61 |
-
*
|
62 |
-
* The keys for the array are URL prefixes.
|
63 |
-
*
|
64 |
-
* The values are associative arrays with data (realm, nonce, nonce-count,
|
65 |
-
* opaque...) needed for digest authentication. Stored here to prevent making
|
66 |
-
* duplicate requests to digest-protected resources after we have already
|
67 |
-
* received the challenge.
|
68 |
-
*
|
69 |
-
* @var array
|
70 |
-
*/
|
71 |
-
protected static $challenges = array();
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Connected socket
|
75 |
-
* @var HTTP_Request2_SocketWrapper
|
76 |
-
* @see connect()
|
77 |
-
*/
|
78 |
-
protected $socket;
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Challenge used for server digest authentication
|
82 |
-
* @var array
|
83 |
-
*/
|
84 |
-
protected $serverChallenge;
|
85 |
-
|
86 |
-
/**
|
87 |
-
* Challenge used for proxy digest authentication
|
88 |
-
* @var array
|
89 |
-
*/
|
90 |
-
protected $proxyChallenge;
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Remaining length of the current chunk, when reading chunked response
|
94 |
-
* @var integer
|
95 |
-
* @see readChunked()
|
96 |
-
*/
|
97 |
-
protected $chunkLength = 0;
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Remaining amount of redirections to follow
|
101 |
-
*
|
102 |
-
* Starts at 'max_redirects' configuration parameter and is reduced on each
|
103 |
-
* subsequent redirect. An Exception will be thrown once it reaches zero.
|
104 |
-
*
|
105 |
-
* @var integer
|
106 |
-
*/
|
107 |
-
protected $redirectCountdown = null;
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Whether to wait for "100 Continue" response before sending request body
|
111 |
-
* @var bool
|
112 |
-
*/
|
113 |
-
protected $expect100Continue = false;
|
114 |
-
|
115 |
-
/**
|
116 |
-
* Sends request to the remote server and returns its response
|
117 |
-
*
|
118 |
-
* @param HTTP_Request2 $request HTTP request message
|
119 |
-
*
|
120 |
-
* @return HTTP_Request2_Response
|
121 |
-
* @throws HTTP_Request2_Exception
|
122 |
-
*/
|
123 |
-
public function sendRequest(HTTP_Request2 $request)
|
124 |
-
{
|
125 |
-
$this->request = $request;
|
126 |
-
|
127 |
-
try {
|
128 |
-
$keepAlive = $this->connect();
|
129 |
-
$headers = $this->prepareHeaders();
|
130 |
-
$this->socket->write($headers);
|
131 |
-
// provide request headers to the observer, see request #7633
|
132 |
-
$this->request->setLastEvent('sentHeaders', $headers);
|
133 |
-
|
134 |
-
if (!$this->expect100Continue) {
|
135 |
-
$this->writeBody();
|
136 |
-
$response = $this->readResponse();
|
137 |
-
|
138 |
-
} else {
|
139 |
-
$response = $this->readResponse();
|
140 |
-
if (!$response || 100 == $response->getStatus()) {
|
141 |
-
$this->expect100Continue = false;
|
142 |
-
// either got "100 Continue" or timed out -> send body
|
143 |
-
$this->writeBody();
|
144 |
-
$response = $this->readResponse();
|
145 |
-
}
|
146 |
-
}
|
147 |
-
|
148 |
-
|
149 |
-
if ($jar = $request->getCookieJar()) {
|
150 |
-
$jar->addCookiesFromResponse($response, $request->getUrl());
|
151 |
-
}
|
152 |
-
|
153 |
-
if (!$this->canKeepAlive($keepAlive, $response)) {
|
154 |
-
$this->disconnect();
|
155 |
-
}
|
156 |
-
|
157 |
-
if ($this->shouldUseProxyDigestAuth($response)) {
|
158 |
-
return $this->sendRequest($request);
|
159 |
-
}
|
160 |
-
if ($this->shouldUseServerDigestAuth($response)) {
|
161 |
-
return $this->sendRequest($request);
|
162 |
-
}
|
163 |
-
if ($authInfo = $response->getHeader('authentication-info')) {
|
164 |
-
$this->updateChallenge($this->serverChallenge, $authInfo);
|
165 |
-
}
|
166 |
-
if ($proxyInfo = $response->getHeader('proxy-authentication-info')) {
|
167 |
-
$this->updateChallenge($this->proxyChallenge, $proxyInfo);
|
168 |
-
}
|
169 |
-
|
170 |
-
} catch (Exception $e) {
|
171 |
-
$this->disconnect();
|
172 |
-
}
|
173 |
-
|
174 |
-
unset($this->request, $this->requestBody);
|
175 |
-
|
176 |
-
if (!empty($e)) {
|
177 |
-
$this->redirectCountdown = null;
|
178 |
-
throw $e;
|
179 |
-
}
|
180 |
-
|
181 |
-
if (!$request->getConfig('follow_redirects') || !$response->isRedirect()) {
|
182 |
-
$this->redirectCountdown = null;
|
183 |
-
return $response;
|
184 |
-
} else {
|
185 |
-
return $this->handleRedirect($request, $response);
|
186 |
-
}
|
187 |
-
}
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Connects to the remote server
|
191 |
-
*
|
192 |
-
* @return bool whether the connection can be persistent
|
193 |
-
* @throws HTTP_Request2_Exception
|
194 |
-
*/
|
195 |
-
protected function connect()
|
196 |
-
{
|
197 |
-
$secure = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https');
|
198 |
-
$tunnel = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
|
199 |
-
$headers = $this->request->getHeaders();
|
200 |
-
$reqHost = $this->request->getUrl()->getHost();
|
201 |
-
if (!($reqPort = $this->request->getUrl()->getPort())) {
|
202 |
-
$reqPort = $secure? 443: 80;
|
203 |
-
}
|
204 |
-
|
205 |
-
$httpProxy = $socksProxy = false;
|
206 |
-
if (!($host = $this->request->getConfig('proxy_host'))) {
|
207 |
-
$host = $reqHost;
|
208 |
-
$port = $reqPort;
|
209 |
-
} else {
|
210 |
-
if (!($port = $this->request->getConfig('proxy_port'))) {
|
211 |
-
throw new HTTP_Request2_LogicException(
|
212 |
-
'Proxy port not provided',
|
213 |
-
HTTP_Request2_Exception::MISSING_VALUE
|
214 |
-
);
|
215 |
-
}
|
216 |
-
if ('http' == ($type = $this->request->getConfig('proxy_type'))) {
|
217 |
-
$httpProxy = true;
|
218 |
-
} elseif ('socks5' == $type) {
|
219 |
-
$socksProxy = true;
|
220 |
-
} else {
|
221 |
-
throw new HTTP_Request2_NotImplementedException(
|
222 |
-
"Proxy type '{$type}' is not supported"
|
223 |
-
);
|
224 |
-
}
|
225 |
-
}
|
226 |
-
|
227 |
-
if ($tunnel && !$httpProxy) {
|
228 |
-
throw new HTTP_Request2_LogicException(
|
229 |
-
"Trying to perform CONNECT request without proxy",
|
230 |
-
HTTP_Request2_Exception::MISSING_VALUE
|
231 |
-
);
|
232 |
-
}
|
233 |
-
if ($secure && !in_array('ssl', stream_get_transports())) {
|
234 |
-
throw new HTTP_Request2_LogicException(
|
235 |
-
'Need OpenSSL support for https:// requests',
|
236 |
-
HTTP_Request2_Exception::MISCONFIGURATION
|
237 |
-
);
|
238 |
-
}
|
239 |
-
|
240 |
-
// RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
|
241 |
-
// connection token to a proxy server...
|
242 |
-
if ($httpProxy && !$secure && !empty($headers['connection'])
|
243 |
-
&& 'Keep-Alive' == $headers['connection']
|
244 |
-
) {
|
245 |
-
$this->request->setHeader('connection');
|
246 |
-
}
|
247 |
-
|
248 |
-
$keepAlive = ('1.1' == $this->request->getConfig('protocol_version') &&
|
249 |
-
empty($headers['connection'])) ||
|
250 |
-
(!empty($headers['connection']) &&
|
251 |
-
'Keep-Alive' == $headers['connection']);
|
252 |
-
|
253 |
-
$options = array();
|
254 |
-
if ($ip = $this->request->getConfig('local_ip')) {
|
255 |
-
$options['socket'] = array(
|
256 |
-
'bindto' => (false === strpos($ip, ':') ? $ip : '[' . $ip . ']') . ':0'
|
257 |
-
);
|
258 |
-
}
|
259 |
-
if ($secure || $tunnel) {
|
260 |
-
$options['ssl'] = array();
|
261 |
-
foreach ($this->request->getConfig() as $name => $value) {
|
262 |
-
if ('ssl_' == substr($name, 0, 4) && null !== $value) {
|
263 |
-
if ('ssl_verify_host' == $name) {
|
264 |
-
if ($value) {
|
265 |
-
$options['ssl']['CN_match'] = $reqHost;
|
266 |
-
}
|
267 |
-
} else {
|
268 |
-
$options['ssl'][substr($name, 4)] = $value;
|
269 |
-
}
|
270 |
-
}
|
271 |
-
}
|
272 |
-
ksort($options['ssl']);
|
273 |
-
}
|
274 |
-
|
275 |
-
// Use global request timeout if given, see feature requests #5735, #8964
|
276 |
-
if ($timeout = $this->request->getConfig('timeout')) {
|
277 |
-
$deadline = time() + $timeout;
|
278 |
-
} else {
|
279 |
-
$deadline = null;
|
280 |
-
}
|
281 |
-
|
282 |
-
// Changing SSL context options after connection is established does *not*
|
283 |
-
// work, we need a new connection if options change
|
284 |
-
$remote = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')
|
285 |
-
. $host . ':' . $port;
|
286 |
-
$socketKey = $remote . (
|
287 |
-
($secure && $httpProxy || $socksProxy)
|
288 |
-
? "->{$reqHost}:{$reqPort}" : ''
|
289 |
-
) . (empty($options)? '': ':' . serialize($options));
|
290 |
-
unset($this->socket);
|
291 |
-
|
292 |
-
// We use persistent connections and have a connected socket?
|
293 |
-
// Ensure that the socket is still connected, see bug #16149
|
294 |
-
if ($keepAlive && !empty(self::$sockets[$socketKey])
|
295 |
-
&& !self::$sockets[$socketKey]->eof()
|
296 |
-
) {
|
297 |
-
$this->socket =& self::$sockets[$socketKey];
|
298 |
-
|
299 |
-
} else {
|
300 |
-
if ($socksProxy) {
|
301 |
-
require_once 'HTTP/Request2/SOCKS5.php';
|
302 |
-
|
303 |
-
$this->socket = new HTTP_Request2_SOCKS5(
|
304 |
-
$remote, $this->request->getConfig('connect_timeout'),
|
305 |
-
$options, $this->request->getConfig('proxy_user'),
|
306 |
-
$this->request->getConfig('proxy_password')
|
307 |
-
);
|
308 |
-
// handle request timeouts ASAP
|
309 |
-
$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
|
310 |
-
$this->socket->connect($reqHost, $reqPort);
|
311 |
-
if (!$secure) {
|
312 |
-
$conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";
|
313 |
-
} else {
|
314 |
-
$this->socket->enableCrypto();
|
315 |
-
$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
|
316 |
-
}
|
317 |
-
|
318 |
-
} elseif ($secure && $httpProxy && !$tunnel) {
|
319 |
-
$this->establishTunnel();
|
320 |
-
$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
|
321 |
-
|
322 |
-
} else {
|
323 |
-
$this->socket = new HTTP_Request2_SocketWrapper(
|
324 |
-
$remote, $this->request->getConfig('connect_timeout'), $options
|
325 |
-
);
|
326 |
-
}
|
327 |
-
$this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);
|
328 |
-
self::$sockets[$socketKey] =& $this->socket;
|
329 |
-
}
|
330 |
-
$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
|
331 |
-
return $keepAlive;
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Establishes a tunnel to a secure remote server via HTTP CONNECT request
|
336 |
-
*
|
337 |
-
* This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP
|
338 |
-
* sees that we are connected to a proxy server (duh!) rather than the server
|
339 |
-
* that presents its certificate.
|
340 |
-
*
|
341 |
-
* @link http://tools.ietf.org/html/rfc2817#section-5.2
|
342 |
-
* @throws HTTP_Request2_Exception
|
343 |
-
*/
|
344 |
-
protected function establishTunnel()
|
345 |
-
{
|
346 |
-
$donor = new self;
|
347 |
-
$connect = new HTTP_Request2(
|
348 |
-
$this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,
|
349 |
-
array_merge($this->request->getConfig(), array('adapter' => $donor))
|
350 |
-
);
|
351 |
-
$response = $connect->send();
|
352 |
-
// Need any successful (2XX) response
|
353 |
-
if (200 > $response->getStatus() || 300 <= $response->getStatus()) {
|
354 |
-
throw new HTTP_Request2_ConnectionException(
|
355 |
-
'Failed to connect via HTTPS proxy. Proxy response: ' .
|
356 |
-
$response->getStatus() . ' ' . $response->getReasonPhrase()
|
357 |
-
);
|
358 |
-
}
|
359 |
-
$this->socket = $donor->socket;
|
360 |
-
$this->socket->enableCrypto();
|
361 |
-
}
|
362 |
-
|
363 |
-
/**
|
364 |
-
* Checks whether current connection may be reused or should be closed
|
365 |
-
*
|
366 |
-
* @param boolean $requestKeepAlive whether connection could
|
367 |
-
* be persistent in the first place
|
368 |
-
* @param HTTP_Request2_Response $response response object to check
|
369 |
-
*
|
370 |
-
* @return boolean
|
371 |
-
*/
|
372 |
-
protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)
|
373 |
-
{
|
374 |
-
// Do not close socket on successful CONNECT request
|
375 |
-
if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
|
376 |
-
&& 200 <= $response->getStatus() && 300 > $response->getStatus()
|
377 |
-
) {
|
378 |
-
return true;
|
379 |
-
}
|
380 |
-
|
381 |
-
$lengthKnown = 'chunked' == strtolower($response->getHeader('transfer-encoding'))
|
382 |
-
|| null !== $response->getHeader('content-length')
|
383 |
-
// no body possible for such responses, see also request #17031
|
384 |
-
|| HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
|
385 |
-
|| in_array($response->getStatus(), array(204, 304));
|
386 |
-
$persistent = 'keep-alive' == strtolower($response->getHeader('connection')) ||
|
387 |
-
(null === $response->getHeader('connection') &&
|
388 |
-
'1.1' == $response->getVersion());
|
389 |
-
return $requestKeepAlive && $lengthKnown && $persistent;
|
390 |
-
}
|
391 |
-
|
392 |
-
/**
|
393 |
-
* Disconnects from the remote server
|
394 |
-
*/
|
395 |
-
protected function disconnect()
|
396 |
-
{
|
397 |
-
if (!empty($this->socket)) {
|
398 |
-
$this->socket = null;
|
399 |
-
$this->request->setLastEvent('disconnect');
|
400 |
-
}
|
401 |
-
}
|
402 |
-
|
403 |
-
/**
|
404 |
-
* Handles HTTP redirection
|
405 |
-
*
|
406 |
-
* This method will throw an Exception if redirect to a non-HTTP(S) location
|
407 |
-
* is attempted, also if number of redirects performed already is equal to
|
408 |
-
* 'max_redirects' configuration parameter.
|
409 |
-
*
|
410 |
-
* @param HTTP_Request2 $request Original request
|
411 |
-
* @param HTTP_Request2_Response $response Response containing redirect
|
412 |
-
*
|
413 |
-
* @return HTTP_Request2_Response Response from a new location
|
414 |
-
* @throws HTTP_Request2_Exception
|
415 |
-
*/
|
416 |
-
protected function handleRedirect(
|
417 |
-
HTTP_Request2 $request, HTTP_Request2_Response $response
|
418 |
-
) {
|
419 |
-
if (is_null($this->redirectCountdown)) {
|
420 |
-
$this->redirectCountdown = $request->getConfig('max_redirects');
|
421 |
-
}
|
422 |
-
if (0 == $this->redirectCountdown) {
|
423 |
-
$this->redirectCountdown = null;
|
424 |
-
// Copying cURL behaviour
|
425 |
-
throw new HTTP_Request2_MessageException(
|
426 |
-
'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',
|
427 |
-
HTTP_Request2_Exception::TOO_MANY_REDIRECTS
|
428 |
-
);
|
429 |
-
}
|
430 |
-
$redirectUrl = new Net_URL2(
|
431 |
-
$response->getHeader('location'),
|
432 |
-
array(Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))
|
433 |
-
);
|
434 |
-
// refuse non-HTTP redirect
|
435 |
-
if ($redirectUrl->isAbsolute()
|
436 |
-
&& !in_array($redirectUrl->getScheme(), array('http', 'https'))
|
437 |
-
) {
|
438 |
-
$this->redirectCountdown = null;
|
439 |
-
throw new HTTP_Request2_MessageException(
|
440 |
-
'Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(),
|
441 |
-
HTTP_Request2_Exception::NON_HTTP_REDIRECT
|
442 |
-
);
|
443 |
-
}
|
444 |
-
// Theoretically URL should be absolute (see http://tools.ietf.org/html/rfc2616#section-14.30),
|
445 |
-
// but in practice it is often not
|
446 |
-
if (!$redirectUrl->isAbsolute()) {
|
447 |
-
$redirectUrl = $request->getUrl()->resolve($redirectUrl);
|
448 |
-
}
|
449 |
-
$redirect = clone $request;
|
450 |
-
$redirect->setUrl($redirectUrl);
|
451 |
-
if (303 == $response->getStatus()
|
452 |
-
|| (!$request->getConfig('strict_redirects')
|
453 |
-
&& in_array($response->getStatus(), array(301, 302)))
|
454 |
-
) {
|
455 |
-
$redirect->setMethod(HTTP_Request2::METHOD_GET);
|
456 |
-
$redirect->setBody('');
|
457 |
-
}
|
458 |
-
|
459 |
-
if (0 < $this->redirectCountdown) {
|
460 |
-
$this->redirectCountdown--;
|
461 |
-
}
|
462 |
-
return $this->sendRequest($redirect);
|
463 |
-
}
|
464 |
-
|
465 |
-
/**
|
466 |
-
* Checks whether another request should be performed with server digest auth
|
467 |
-
*
|
468 |
-
* Several conditions should be satisfied for it to return true:
|
469 |
-
* - response status should be 401
|
470 |
-
* - auth credentials should be set in the request object
|
471 |
-
* - response should contain WWW-Authenticate header with digest challenge
|
472 |
-
* - there is either no challenge stored for this URL or new challenge
|
473 |
-
* contains stale=true parameter (in other case we probably just failed
|
474 |
-
* due to invalid username / password)
|
475 |
-
*
|
476 |
-
* The method stores challenge values in $challenges static property
|
477 |
-
*
|
478 |
-
* @param HTTP_Request2_Response $response response to check
|
479 |
-
*
|
480 |
-
* @return boolean whether another request should be performed
|
481 |
-
* @throws HTTP_Request2_Exception in case of unsupported challenge parameters
|
482 |
-
*/
|
483 |
-
protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response)
|
484 |
-
{
|
485 |
-
// no sense repeating a request if we don't have credentials
|
486 |
-
if (401 != $response->getStatus() || !$this->request->getAuth()) {
|
487 |
-
return false;
|
488 |
-
}
|
489 |
-
if (!$challenge = $this->parseDigestChallenge($response->getHeader('www-authenticate'))) {
|
490 |
-
return false;
|
491 |
-
}
|
492 |
-
|
493 |
-
$url = $this->request->getUrl();
|
494 |
-
$scheme = $url->getScheme();
|
495 |
-
$host = $scheme . '://' . $url->getHost();
|
496 |
-
if ($port = $url->getPort()) {
|
497 |
-
if ((0 == strcasecmp($scheme, 'http') && 80 != $port)
|
498 |
-
|| (0 == strcasecmp($scheme, 'https') && 443 != $port)
|
499 |
-
) {
|
500 |
-
$host .= ':' . $port;
|
501 |
-
}
|
502 |
-
}
|
503 |
-
|
504 |
-
if (!empty($challenge['domain'])) {
|
505 |
-
$prefixes = array();
|
506 |
-
foreach (preg_split('/\\s+/', $challenge['domain']) as $prefix) {
|
507 |
-
// don't bother with different servers
|
508 |
-
if ('/' == substr($prefix, 0, 1)) {
|
509 |
-
$prefixes[] = $host . $prefix;
|
510 |
-
}
|
511 |
-
}
|
512 |
-
}
|
513 |
-
if (empty($prefixes)) {
|
514 |
-
$prefixes = array($host . '/');
|
515 |
-
}
|
516 |
-
|
517 |
-
$ret = true;
|
518 |
-
foreach ($prefixes as $prefix) {
|
519 |
-
if (!empty(self::$challenges[$prefix])
|
520 |
-
&& (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
|
521 |
-
) {
|
522 |
-
// probably credentials are invalid
|
523 |
-
$ret = false;
|
524 |
-
}
|
525 |
-
self::$challenges[$prefix] =& $challenge;
|
526 |
-
}
|
527 |
-
return $ret;
|
528 |
-
}
|
529 |
-
|
530 |
-
/**
|
531 |
-
* Checks whether another request should be performed with proxy digest auth
|
532 |
-
*
|
533 |
-
* Several conditions should be satisfied for it to return true:
|
534 |
-
* - response status should be 407
|
535 |
-
* - proxy auth credentials should be set in the request object
|
536 |
-
* - response should contain Proxy-Authenticate header with digest challenge
|
537 |
-
* - there is either no challenge stored for this proxy or new challenge
|
538 |
-
* contains stale=true parameter (in other case we probably just failed
|
539 |
-
* due to invalid username / password)
|
540 |
-
*
|
541 |
-
* The method stores challenge values in $challenges static property
|
542 |
-
*
|
543 |
-
* @param HTTP_Request2_Response $response response to check
|
544 |
-
*
|
545 |
-
* @return boolean whether another request should be performed
|
546 |
-
* @throws HTTP_Request2_Exception in case of unsupported challenge parameters
|
547 |
-
*/
|
548 |
-
protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)
|
549 |
-
{
|
550 |
-
if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {
|
551 |
-
return false;
|
552 |
-
}
|
553 |
-
if (!($challenge = $this->parseDigestChallenge($response->getHeader('proxy-authenticate')))) {
|
554 |
-
return false;
|
555 |
-
}
|
556 |
-
|
557 |
-
$key = 'proxy://' . $this->request->getConfig('proxy_host') .
|
558 |
-
':' . $this->request->getConfig('proxy_port');
|
559 |
-
|
560 |
-
if (!empty(self::$challenges[$key])
|
561 |
-
&& (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
|
562 |
-
) {
|
563 |
-
$ret = false;
|
564 |
-
} else {
|
565 |
-
$ret = true;
|
566 |
-
}
|
567 |
-
self::$challenges[$key] = $challenge;
|
568 |
-
return $ret;
|
569 |
-
}
|
570 |
-
|
571 |
-
/**
|
572 |
-
* Extracts digest method challenge from (WWW|Proxy)-Authenticate header value
|
573 |
-
*
|
574 |
-
* There is a problem with implementation of RFC 2617: several of the parameters
|
575 |
-
* are defined as quoted-string there and thus may contain backslash escaped
|
576 |
-
* double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as
|
577 |
-
* just value of quoted-string X without surrounding quotes, it doesn't speak
|
578 |
-
* about removing backslash escaping.
|
579 |
-
*
|
580 |
-
* Now realm parameter is user-defined and human-readable, strange things
|
581 |
-
* happen when it contains quotes:
|
582 |
-
* - Apache allows quotes in realm, but apparently uses realm value without
|
583 |
-
* backslashes for digest computation
|
584 |
-
* - Squid allows (manually escaped) quotes there, but it is impossible to
|
585 |
-
* authorize with either escaped or unescaped quotes used in digest,
|
586 |
-
* probably it can't parse the response (?)
|
587 |
-
* - Both IE and Firefox display realm value with backslashes in
|
588 |
-
* the password popup and apparently use the same value for digest
|
589 |
-
*
|
590 |
-
* HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in
|
591 |
-
* quoted-string handling, unfortunately that means failure to authorize
|
592 |
-
* sometimes
|
593 |
-
*
|
594 |
-
* @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header
|
595 |
-
*
|
596 |
-
* @return mixed associative array with challenge parameters, false if
|
597 |
-
* no challenge is present in header value
|
598 |
-
* @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters
|
599 |
-
*/
|
600 |
-
protected function parseDigestChallenge($headerValue)
|
601 |
-
{
|
602 |
-
$authParam = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
|
603 |
-
self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')';
|
604 |
-
$challenge = "!(?<=^|\\s|,)Digest ({$authParam}\\s*(,\\s*|$))+!";
|
605 |
-
if (!preg_match($challenge, $headerValue, $matches)) {
|
606 |
-
return false;
|
607 |
-
}
|
608 |
-
|
609 |
-
preg_match_all('!' . $authParam . '!', $matches[0], $params);
|
610 |
-
$paramsAry = array();
|
611 |
-
$knownParams = array('realm', 'domain', 'nonce', 'opaque', 'stale',
|
612 |
-
'algorithm', 'qop');
|
613 |
-
for ($i = 0; $i < count($params[0]); $i++) {
|
614 |
-
// section 3.2.1: Any unrecognized directive MUST be ignored.
|
615 |
-
if (in_array($params[1][$i], $knownParams)) {
|
616 |
-
if ('"' == substr($params[2][$i], 0, 1)) {
|
617 |
-
$paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
|
618 |
-
} else {
|
619 |
-
$paramsAry[$params[1][$i]] = $params[2][$i];
|
620 |
-
}
|
621 |
-
}
|
622 |
-
}
|
623 |
-
// we only support qop=auth
|
624 |
-
if (!empty($paramsAry['qop'])
|
625 |
-
&& !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
|
626 |
-
) {
|
627 |
-
throw new HTTP_Request2_NotImplementedException(
|
628 |
-
"Only 'auth' qop is currently supported in digest authentication, " .
|
629 |
-
"server requested '{$paramsAry['qop']}'"
|
630 |
-
);
|
631 |
-
}
|
632 |
-
// we only support algorithm=MD5
|
633 |
-
if (!empty($paramsAry['algorithm']) && 'MD5' != $paramsAry['algorithm']) {
|
634 |
-
throw new HTTP_Request2_NotImplementedException(
|
635 |
-
"Only 'MD5' algorithm is currently supported in digest authentication, " .
|
636 |
-
"server requested '{$paramsAry['algorithm']}'"
|
637 |
-
);
|
638 |
-
}
|
639 |
-
|
640 |
-
return $paramsAry;
|
641 |
-
}
|
642 |
-
|
643 |
-
/**
|
644 |
-
* Parses [Proxy-]Authentication-Info header value and updates challenge
|
645 |
-
*
|
646 |
-
* @param array &$challenge challenge to update
|
647 |
-
* @param string $headerValue value of [Proxy-]Authentication-Info header
|
648 |
-
*
|
649 |
-
* @todo validate server rspauth response
|
650 |
-
*/
|
651 |
-
protected function updateChallenge(&$challenge, $headerValue)
|
652 |
-
{
|
653 |
-
$authParam = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
|
654 |
-
self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')!';
|
655 |
-
$paramsAry = array();
|
656 |
-
|
657 |
-
preg_match_all($authParam, $headerValue, $params);
|
658 |
-
for ($i = 0; $i < count($params[0]); $i++) {
|
659 |
-
if ('"' == substr($params[2][$i], 0, 1)) {
|
660 |
-
$paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
|
661 |
-
} else {
|
662 |
-
$paramsAry[$params[1][$i]] = $params[2][$i];
|
663 |
-
}
|
664 |
-
}
|
665 |
-
// for now, just update the nonce value
|
666 |
-
if (!empty($paramsAry['nextnonce'])) {
|
667 |
-
$challenge['nonce'] = $paramsAry['nextnonce'];
|
668 |
-
$challenge['nc'] = 1;
|
669 |
-
}
|
670 |
-
}
|
671 |
-
|
672 |
-
/**
|
673 |
-
* Creates a value for [Proxy-]Authorization header when using digest authentication
|
674 |
-
*
|
675 |
-
* @param string $user user name
|
676 |
-
* @param string $password password
|
677 |
-
* @param string $url request URL
|
678 |
-
* @param array &$challenge digest challenge parameters
|
679 |
-
*
|
680 |
-
* @return string value of [Proxy-]Authorization request header
|
681 |
-
* @link http://tools.ietf.org/html/rfc2617#section-3.2.2
|
682 |
-
*/
|
683 |
-
protected function createDigestResponse($user, $password, $url, &$challenge)
|
684 |
-
{
|
685 |
-
if (false !== ($q = strpos($url, '?'))
|
686 |
-
&& $this->request->getConfig('digest_compat_ie')
|
687 |
-
) {
|
688 |
-
$url = substr($url, 0, $q);
|
689 |
-
}
|
690 |
-
|
691 |
-
$a1 = md5($user . ':' . $challenge['realm'] . ':' . $password);
|
692 |
-
$a2 = md5($this->request->getMethod() . ':' . $url);
|
693 |
-
|
694 |
-
if (empty($challenge['qop'])) {
|
695 |
-
$digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $a2);
|
696 |
-
} else {
|
697 |
-
$challenge['cnonce'] = 'Req2.' . rand();
|
698 |
-
if (empty($challenge['nc'])) {
|
699 |
-
$challenge['nc'] = 1;
|
700 |
-
}
|
701 |
-
$nc = sprintf('%08x', $challenge['nc']++);
|
702 |
-
$digest = md5(
|
703 |
-
$a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
|
704 |
-
$challenge['cnonce'] . ':auth:' . $a2
|
705 |
-
);
|
706 |
-
}
|
707 |
-
return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
|
708 |
-
'realm="' . $challenge['realm'] . '", ' .
|
709 |
-
'nonce="' . $challenge['nonce'] . '", ' .
|
710 |
-
'uri="' . $url . '", ' .
|
711 |
-
'response="' . $digest . '"' .
|
712 |
-
(!empty($challenge['opaque'])?
|
713 |
-
', opaque="' . $challenge['opaque'] . '"':
|
714 |
-
'') .
|
715 |
-
(!empty($challenge['qop'])?
|
716 |
-
', qop="auth", nc=' . $nc . ', cnonce="' . $challenge['cnonce'] . '"':
|
717 |
-
'');
|
718 |
-
}
|
719 |
-
|
720 |
-
/**
|
721 |
-
* Adds 'Authorization' header (if needed) to request headers array
|
722 |
-
*
|
723 |
-
* @param array &$headers request headers
|
724 |
-
* @param string $requestHost request host (needed for digest authentication)
|
725 |
-
* @param string $requestUrl request URL (needed for digest authentication)
|
726 |
-
*
|
727 |
-
* @throws HTTP_Request2_NotImplementedException
|
728 |
-
*/
|
729 |
-
protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)
|
730 |
-
{
|
731 |
-
if (!($auth = $this->request->getAuth())) {
|
732 |
-
return;
|
733 |
-
}
|
734 |
-
switch ($auth['scheme']) {
|
735 |
-
case HTTP_Request2::AUTH_BASIC:
|
736 |
-
$headers['authorization'] = 'Basic ' . base64_encode(
|
737 |
-
$auth['user'] . ':' . $auth['password']
|
738 |
-
);
|
739 |
-
break;
|
740 |
-
|
741 |
-
case HTTP_Request2::AUTH_DIGEST:
|
742 |
-
unset($this->serverChallenge);
|
743 |
-
$fullUrl = ('/' == $requestUrl[0])?
|
744 |
-
$this->request->getUrl()->getScheme() . '://' .
|
745 |
-
$requestHost . $requestUrl:
|
746 |
-
$requestUrl;
|
747 |
-
foreach (array_keys(self::$challenges) as $key) {
|
748 |
-
if ($key == substr($fullUrl, 0, strlen($key))) {
|
749 |
-
$headers['authorization'] = $this->createDigestResponse(
|
750 |
-
$auth['user'], $auth['password'],
|
751 |
-
$requestUrl, self::$challenges[$key]
|
752 |
-
);
|
753 |
-
$this->serverChallenge =& self::$challenges[$key];
|
754 |
-
break;
|
755 |
-
}
|
756 |
-
}
|
757 |
-
break;
|
758 |
-
|
759 |
-
default:
|
760 |
-
throw new HTTP_Request2_NotImplementedException(
|
761 |
-
"Unknown HTTP authentication scheme '{$auth['scheme']}'"
|
762 |
-
);
|
763 |
-
}
|
764 |
-
}
|
765 |
-
|
766 |
-
/**
|
767 |
-
* Adds 'Proxy-Authorization' header (if needed) to request headers array
|
768 |
-
*
|
769 |
-
* @param array &$headers request headers
|
770 |
-
* @param string $requestUrl request URL (needed for digest authentication)
|
771 |
-
*
|
772 |
-
* @throws HTTP_Request2_NotImplementedException
|
773 |
-
*/
|
774 |
-
protected function addProxyAuthorizationHeader(&$headers, $requestUrl)
|
775 |
-
{
|
776 |
-
if (!$this->request->getConfig('proxy_host')
|
777 |
-
|| !($user = $this->request->getConfig('proxy_user'))
|
778 |
-
|| (0 == strcasecmp('https', $this->request->getUrl()->getScheme())
|
779 |
-
&& HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())
|
780 |
-
) {
|
781 |
-
return;
|
782 |
-
}
|
783 |
-
|
784 |
-
$password = $this->request->getConfig('proxy_password');
|
785 |
-
switch ($this->request->getConfig('proxy_auth_scheme')) {
|
786 |
-
case HTTP_Request2::AUTH_BASIC:
|
787 |
-
$headers['proxy-authorization'] = 'Basic ' . base64_encode(
|
788 |
-
$user . ':' . $password
|
789 |
-
);
|
790 |
-
break;
|
791 |
-
|
792 |
-
case HTTP_Request2::AUTH_DIGEST:
|
793 |
-
unset($this->proxyChallenge);
|
794 |
-
$proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
|
795 |
-
':' . $this->request->getConfig('proxy_port');
|
796 |
-
if (!empty(self::$challenges[$proxyUrl])) {
|
797 |
-
$headers['proxy-authorization'] = $this->createDigestResponse(
|
798 |
-
$user, $password,
|
799 |
-
$requestUrl, self::$challenges[$proxyUrl]
|
800 |
-
);
|
801 |
-
$this->proxyChallenge =& self::$challenges[$proxyUrl];
|
802 |
-
}
|
803 |
-
break;
|
804 |
-
|
805 |
-
default:
|
806 |
-
throw new HTTP_Request2_NotImplementedException(
|
807 |
-
"Unknown HTTP authentication scheme '" .
|
808 |
-
$this->request->getConfig('proxy_auth_scheme') . "'"
|
809 |
-
);
|
810 |
-
}
|
811 |
-
}
|
812 |
-
|
813 |
-
|
814 |
-
/**
|
815 |
-
* Creates the string with the Request-Line and request headers
|
816 |
-
*
|
817 |
-
* @return string
|
818 |
-
* @throws HTTP_Request2_Exception
|
819 |
-
*/
|
820 |
-
protected function prepareHeaders()
|
821 |
-
{
|
822 |
-
$headers = $this->request->getHeaders();
|
823 |
-
$url = $this->request->getUrl();
|
824 |
-
$connect = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
|
825 |
-
$host = $url->getHost();
|
826 |
-
|
827 |
-
$defaultPort = 0 == strcasecmp($url->getScheme(), 'https')? 443: 80;
|
828 |
-
if (($port = $url->getPort()) && $port != $defaultPort || $connect) {
|
829 |
-
$host .= ':' . (empty($port)? $defaultPort: $port);
|
830 |
-
}
|
831 |
-
// Do not overwrite explicitly set 'Host' header, see bug #16146
|
832 |
-
if (!isset($headers['host'])) {
|
833 |
-
$headers['host'] = $host;
|
834 |
-
}
|
835 |
-
|
836 |
-
if ($connect) {
|
837 |
-
$requestUrl = $host;
|
838 |
-
|
839 |
-
} else {
|
840 |
-
if (!$this->request->getConfig('proxy_host')
|
841 |
-
|| 'http' != $this->request->getConfig('proxy_type')
|
842 |
-
|| 0 == strcasecmp($url->getScheme(), 'https')
|
843 |
-
) {
|
844 |
-
$requestUrl = '';
|
845 |
-
} else {
|
846 |
-
$requestUrl = $url->getScheme() . '://' . $host;
|
847 |
-
}
|
848 |
-
$path = $url->getPath();
|
849 |
-
$query = $url->getQuery();
|
850 |
-
$requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
|
851 |
-
}
|
852 |
-
|
853 |
-
if ('1.1' == $this->request->getConfig('protocol_version')
|
854 |
-
&& extension_loaded('zlib') && !isset($headers['accept-encoding'])
|
855 |
-
) {
|
856 |
-
$headers['accept-encoding'] = 'gzip, deflate';
|
857 |
-
}
|
858 |
-
if (($jar = $this->request->getCookieJar())
|
859 |
-
&& ($cookies = $jar->getMatching($this->request->getUrl(), true))
|
860 |
-
) {
|
861 |
-
$headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
|
862 |
-
}
|
863 |
-
|
864 |
-
$this->addAuthorizationHeader($headers, $host, $requestUrl);
|
865 |
-
$this->addProxyAuthorizationHeader($headers, $requestUrl);
|
866 |
-
$this->calculateRequestLength($headers);
|
867 |
-
if ('1.1' == $this->request->getConfig('protocol_version')) {
|
868 |
-
$this->updateExpectHeader($headers);
|
869 |
-
} else {
|
870 |
-
$this->expect100Continue = false;
|
871 |
-
}
|
872 |
-
|
873 |
-
$headersStr = $this->request->getMethod() . ' ' . $requestUrl . ' HTTP/' .
|
874 |
-
$this->request->getConfig('protocol_version') . "\r\n";
|
875 |
-
foreach ($headers as $name => $value) {
|
876 |
-
$canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
|
877 |
-
$headersStr .= $canonicalName . ': ' . $value . "\r\n";
|
878 |
-
}
|
879 |
-
return $headersStr . "\r\n";
|
880 |
-
}
|
881 |
-
|
882 |
-
/**
|
883 |
-
* Adds or removes 'Expect: 100-continue' header from request headers
|
884 |
-
*
|
885 |
-
* Also sets the $expect100Continue property. Parsing of existing header
|
886 |
-
* is somewhat needed due to its complex structure and due to the
|
887 |
-
* requirement in section 8.2.3 of RFC 2616:
|
888 |
-
* > A client MUST NOT send an Expect request-header field (section
|
889 |
-
* > 14.20) with the "100-continue" expectation if it does not intend
|
890 |
-
* > to send a request body.
|
891 |
-
*
|
892 |
-
* @param array &$headers Array of headers prepared for the request
|
893 |
-
*
|
894 |
-
* @throws HTTP_Request2_LogicException
|
895 |
-
* @link http://pear.php.net/bugs/bug.php?id=19233
|
896 |
-
* @link http://tools.ietf.org/html/rfc2616#section-8.2.3
|
897 |
-
*/
|
898 |
-
protected function updateExpectHeader(&$headers)
|
899 |
-
{
|
900 |
-
$this->expect100Continue = false;
|
901 |
-
$expectations = array();
|
902 |
-
if (isset($headers['expect'])) {
|
903 |
-
if ('' === $headers['expect']) {
|
904 |
-
// empty 'Expect' header is technically invalid, so just get rid of it
|
905 |
-
unset($headers['expect']);
|
906 |
-
return;
|
907 |
-
}
|
908 |
-
// build regexp to parse the value of existing Expect header
|
909 |
-
$expectParam = ';\s*' . self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
|
910 |
-
. self::REGEXP_TOKEN . '|'
|
911 |
-
. self::REGEXP_QUOTED_STRING . '))?\s*';
|
912 |
-
$expectExtension = self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
|
913 |
-
. self::REGEXP_TOKEN . '|'
|
914 |
-
. self::REGEXP_QUOTED_STRING . ')\s*(?:'
|
915 |
-
. $expectParam . ')*)?';
|
916 |
-
$expectItem = '!(100-continue|' . $expectExtension . ')!A';
|
917 |
-
|
918 |
-
$pos = 0;
|
919 |
-
$length = strlen($headers['expect']);
|
920 |
-
|
921 |
-
while ($pos < $length) {
|
922 |
-
$pos += strspn($headers['expect'], " \t", $pos);
|
923 |
-
if (',' === substr($headers['expect'], $pos, 1)) {
|
924 |
-
$pos++;
|
925 |
-
continue;
|
926 |
-
|
927 |
-
} elseif (!preg_match($expectItem, $headers['expect'], $m, 0, $pos)) {
|
928 |
-
throw new HTTP_Request2_LogicException(
|
929 |
-
"Cannot parse value '{$headers['expect']}' of Expect header",
|
930 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
931 |
-
);
|
932 |
-
|
933 |
-
} else {
|
934 |
-
$pos += strlen($m[0]);
|
935 |
-
if (strcasecmp('100-continue', $m[0])) {
|
936 |
-
$expectations[] = $m[0];
|
937 |
-
}
|
938 |
-
}
|
939 |
-
}
|
940 |
-
}
|
941 |
-
|
942 |
-
if (1024 < $this->contentLength) {
|
943 |
-
$expectations[] = '100-continue';
|
944 |
-
$this->expect100Continue = true;
|
945 |
-
}
|
946 |
-
|
947 |
-
if (empty($expectations)) {
|
948 |
-
unset($headers['expect']);
|
949 |
-
} else {
|
950 |
-
$headers['expect'] = implode(',', $expectations);
|
951 |
-
}
|
952 |
-
}
|
953 |
-
|
954 |
-
/**
|
955 |
-
* Sends the request body
|
956 |
-
*
|
957 |
-
* @throws HTTP_Request2_MessageException
|
958 |
-
*/
|
959 |
-
protected function writeBody()
|
960 |
-
{
|
961 |
-
if (in_array($this->request->getMethod(), self::$bodyDisallowed)
|
962 |
-
|| 0 == $this->contentLength
|
963 |
-
) {
|
964 |
-
return;
|
965 |
-
}
|
966 |
-
|
967 |
-
$position = 0;
|
968 |
-
$bufferSize = $this->request->getConfig('buffer_size');
|
969 |
-
$headers = $this->request->getHeaders();
|
970 |
-
$chunked = isset($headers['transfer-encoding']);
|
971 |
-
while ($position < $this->contentLength) {
|
972 |
-
if (is_string($this->requestBody)) {
|
973 |
-
$str = substr($this->requestBody, $position, $bufferSize);
|
974 |
-
} elseif (is_resource($this->requestBody)) {
|
975 |
-
$str = fread($this->requestBody, $bufferSize);
|
976 |
-
} else {
|
977 |
-
$str = $this->requestBody->read($bufferSize);
|
978 |
-
}
|
979 |
-
if (!$chunked) {
|
980 |
-
$this->socket->write($str);
|
981 |
-
} else {
|
982 |
-
$this->socket->write(dechex(strlen($str)) . "\r\n{$str}\r\n");
|
983 |
-
}
|
984 |
-
// Provide the length of written string to the observer, request #7630
|
985 |
-
$this->request->setLastEvent('sentBodyPart', strlen($str));
|
986 |
-
$position += strlen($str);
|
987 |
-
}
|
988 |
-
|
989 |
-
// write zero-length chunk
|
990 |
-
if ($chunked) {
|
991 |
-
$this->socket->write("0\r\n\r\n");
|
992 |
-
}
|
993 |
-
$this->request->setLastEvent('sentBody', $this->contentLength);
|
994 |
-
}
|
995 |
-
|
996 |
-
/**
|
997 |
-
* Reads the remote server's response
|
998 |
-
*
|
999 |
-
* @return HTTP_Request2_Response
|
1000 |
-
* @throws HTTP_Request2_Exception
|
1001 |
-
*/
|
1002 |
-
protected function readResponse()
|
1003 |
-
{
|
1004 |
-
$bufferSize = $this->request->getConfig('buffer_size');
|
1005 |
-
// http://tools.ietf.org/html/rfc2616#section-8.2.3
|
1006 |
-
// ...the client SHOULD NOT wait for an indefinite period before sending the request body
|
1007 |
-
$timeout = $this->expect100Continue ? 1 : null;
|
1008 |
-
|
1009 |
-
do {
|
1010 |
-
try {
|
1011 |
-
$response = new HTTP_Request2_Response(
|
1012 |
-
$this->socket->readLine($bufferSize, $timeout), true, $this->request->getUrl()
|
1013 |
-
);
|
1014 |
-
do {
|
1015 |
-
$headerLine = $this->socket->readLine($bufferSize);
|
1016 |
-
$response->parseHeaderLine($headerLine);
|
1017 |
-
} while ('' != $headerLine);
|
1018 |
-
|
1019 |
-
} catch (HTTP_Request2_MessageException $e) {
|
1020 |
-
if (HTTP_Request2_Exception::TIMEOUT === $e->getCode()
|
1021 |
-
&& $this->expect100Continue
|
1022 |
-
) {
|
1023 |
-
return null;
|
1024 |
-
}
|
1025 |
-
throw $e;
|
1026 |
-
}
|
1027 |
-
if ($this->expect100Continue && 100 == $response->getStatus()) {
|
1028 |
-
return $response;
|
1029 |
-
}
|
1030 |
-
} while (in_array($response->getStatus(), array(100, 101)));
|
1031 |
-
|
1032 |
-
$this->request->setLastEvent('receivedHeaders', $response);
|
1033 |
-
|
1034 |
-
// No body possible in such responses
|
1035 |
-
if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
|
1036 |
-
|| (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
|
1037 |
-
&& 200 <= $response->getStatus() && 300 > $response->getStatus())
|
1038 |
-
|| in_array($response->getStatus(), array(204, 304))
|
1039 |
-
) {
|
1040 |
-
return $response;
|
1041 |
-
}
|
1042 |
-
|
1043 |
-
$chunked = 'chunked' == $response->getHeader('transfer-encoding');
|
1044 |
-
$length = $response->getHeader('content-length');
|
1045 |
-
$hasBody = false;
|
1046 |
-
if ($chunked || null === $length || 0 < intval($length)) {
|
1047 |
-
// RFC 2616, section 4.4:
|
1048 |
-
// 3. ... If a message is received with both a
|
1049 |
-
// Transfer-Encoding header field and a Content-Length header field,
|
1050 |
-
// the latter MUST be ignored.
|
1051 |
-
$toRead = ($chunked || null === $length)? null: $length;
|
1052 |
-
$this->chunkLength = 0;
|
1053 |
-
|
1054 |
-
while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {
|
1055 |
-
if ($chunked) {
|
1056 |
-
$data = $this->readChunked($bufferSize);
|
1057 |
-
} elseif (is_null($toRead)) {
|
1058 |
-
$data = $this->socket->read($bufferSize);
|
1059 |
-
} else {
|
1060 |
-
$data = $this->socket->read(min($toRead, $bufferSize));
|
1061 |
-
$toRead -= strlen($data);
|
1062 |
-
}
|
1063 |
-
if ('' == $data && (!$this->chunkLength || $this->socket->eof())) {
|
1064 |
-
break;
|
1065 |
-
}
|
1066 |
-
|
1067 |
-
$hasBody = true;
|
1068 |
-
if ($this->request->getConfig('store_body')) {
|
1069 |
-
$response->appendBody($data);
|
1070 |
-
}
|
1071 |
-
if (!in_array($response->getHeader('content-encoding'), array('identity', null))) {
|
1072 |
-
$this->request->setLastEvent('receivedEncodedBodyPart', $data);
|
1073 |
-
} else {
|
1074 |
-
$this->request->setLastEvent('receivedBodyPart', $data);
|
1075 |
-
}
|
1076 |
-
}
|
1077 |
-
}
|
1078 |
-
|
1079 |
-
if ($hasBody) {
|
1080 |
-
$this->request->setLastEvent('receivedBody', $response);
|
1081 |
-
}
|
1082 |
-
return $response;
|
1083 |
-
}
|
1084 |
-
|
1085 |
-
/**
|
1086 |
-
* Reads a part of response body encoded with chunked Transfer-Encoding
|
1087 |
-
*
|
1088 |
-
* @param int $bufferSize buffer size to use for reading
|
1089 |
-
*
|
1090 |
-
* @return string
|
1091 |
-
* @throws HTTP_Request2_MessageException
|
1092 |
-
*/
|
1093 |
-
protected function readChunked($bufferSize)
|
1094 |
-
{
|
1095 |
-
// at start of the next chunk?
|
1096 |
-
if (0 == $this->chunkLength) {
|
1097 |
-
$line = $this->socket->readLine($bufferSize);
|
1098 |
-
if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
|
1099 |
-
throw new HTTP_Request2_MessageException(
|
1100 |
-
"Cannot decode chunked response, invalid chunk length '{$line}'",
|
1101 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
1102 |
-
);
|
1103 |
-
} else {
|
1104 |
-
$this->chunkLength = hexdec($matches[1]);
|
1105 |
-
// Chunk with zero length indicates the end
|
1106 |
-
if (0 == $this->chunkLength) {
|
1107 |
-
$this->socket->readLine($bufferSize);
|
1108 |
-
return '';
|
1109 |
-
}
|
1110 |
-
}
|
1111 |
-
}
|
1112 |
-
$data = $this->socket->read(min($this->chunkLength, $bufferSize));
|
1113 |
-
$this->chunkLength -= strlen($data);
|
1114 |
-
if (0 == $this->chunkLength) {
|
1115 |
-
$this->socket->readLine($bufferSize); // Trailing CRLF
|
1116 |
-
}
|
1117 |
-
return $data;
|
1118 |
-
}
|
1119 |
-
}
|
1120 |
-
|
1121 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Socket-based adapter for HTTP_Request2
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/** Base class for HTTP_Request2 adapters */
|
22 |
+
require_once 'HTTP/Request2/Adapter.php';
|
23 |
+
|
24 |
+
/** Socket wrapper class */
|
25 |
+
require_once 'HTTP/Request2/SocketWrapper.php';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Socket-based adapter for HTTP_Request2
|
29 |
+
*
|
30 |
+
* This adapter uses only PHP sockets and will work on almost any PHP
|
31 |
+
* environment. Code is based on original HTTP_Request PEAR package.
|
32 |
+
*
|
33 |
+
* @category HTTP
|
34 |
+
* @package HTTP_Request2
|
35 |
+
* @author Alexey Borzov <avb@php.net>
|
36 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
37 |
+
* @version Release: 2.2.1
|
38 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
39 |
+
*/
|
40 |
+
class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
|
41 |
+
{
|
42 |
+
/**
|
43 |
+
* Regular expression for 'token' rule from RFC 2616
|
44 |
+
*/
|
45 |
+
const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Regular expression for 'quoted-string' rule from RFC 2616
|
49 |
+
*/
|
50 |
+
const REGEXP_QUOTED_STRING = '"(?>[^"\\\\]+|\\\\.)*"';
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Connected sockets, needed for Keep-Alive support
|
54 |
+
* @var array
|
55 |
+
* @see connect()
|
56 |
+
*/
|
57 |
+
protected static $sockets = array();
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Data for digest authentication scheme
|
61 |
+
*
|
62 |
+
* The keys for the array are URL prefixes.
|
63 |
+
*
|
64 |
+
* The values are associative arrays with data (realm, nonce, nonce-count,
|
65 |
+
* opaque...) needed for digest authentication. Stored here to prevent making
|
66 |
+
* duplicate requests to digest-protected resources after we have already
|
67 |
+
* received the challenge.
|
68 |
+
*
|
69 |
+
* @var array
|
70 |
+
*/
|
71 |
+
protected static $challenges = array();
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Connected socket
|
75 |
+
* @var HTTP_Request2_SocketWrapper
|
76 |
+
* @see connect()
|
77 |
+
*/
|
78 |
+
protected $socket;
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Challenge used for server digest authentication
|
82 |
+
* @var array
|
83 |
+
*/
|
84 |
+
protected $serverChallenge;
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Challenge used for proxy digest authentication
|
88 |
+
* @var array
|
89 |
+
*/
|
90 |
+
protected $proxyChallenge;
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Remaining length of the current chunk, when reading chunked response
|
94 |
+
* @var integer
|
95 |
+
* @see readChunked()
|
96 |
+
*/
|
97 |
+
protected $chunkLength = 0;
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Remaining amount of redirections to follow
|
101 |
+
*
|
102 |
+
* Starts at 'max_redirects' configuration parameter and is reduced on each
|
103 |
+
* subsequent redirect. An Exception will be thrown once it reaches zero.
|
104 |
+
*
|
105 |
+
* @var integer
|
106 |
+
*/
|
107 |
+
protected $redirectCountdown = null;
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Whether to wait for "100 Continue" response before sending request body
|
111 |
+
* @var bool
|
112 |
+
*/
|
113 |
+
protected $expect100Continue = false;
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Sends request to the remote server and returns its response
|
117 |
+
*
|
118 |
+
* @param HTTP_Request2 $request HTTP request message
|
119 |
+
*
|
120 |
+
* @return HTTP_Request2_Response
|
121 |
+
* @throws HTTP_Request2_Exception
|
122 |
+
*/
|
123 |
+
public function sendRequest(HTTP_Request2 $request)
|
124 |
+
{
|
125 |
+
$this->request = $request;
|
126 |
+
|
127 |
+
try {
|
128 |
+
$keepAlive = $this->connect();
|
129 |
+
$headers = $this->prepareHeaders();
|
130 |
+
$this->socket->write($headers);
|
131 |
+
// provide request headers to the observer, see request #7633
|
132 |
+
$this->request->setLastEvent('sentHeaders', $headers);
|
133 |
+
|
134 |
+
if (!$this->expect100Continue) {
|
135 |
+
$this->writeBody();
|
136 |
+
$response = $this->readResponse();
|
137 |
+
|
138 |
+
} else {
|
139 |
+
$response = $this->readResponse();
|
140 |
+
if (!$response || 100 == $response->getStatus()) {
|
141 |
+
$this->expect100Continue = false;
|
142 |
+
// either got "100 Continue" or timed out -> send body
|
143 |
+
$this->writeBody();
|
144 |
+
$response = $this->readResponse();
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
|
149 |
+
if ($jar = $request->getCookieJar()) {
|
150 |
+
$jar->addCookiesFromResponse($response, $request->getUrl());
|
151 |
+
}
|
152 |
+
|
153 |
+
if (!$this->canKeepAlive($keepAlive, $response)) {
|
154 |
+
$this->disconnect();
|
155 |
+
}
|
156 |
+
|
157 |
+
if ($this->shouldUseProxyDigestAuth($response)) {
|
158 |
+
return $this->sendRequest($request);
|
159 |
+
}
|
160 |
+
if ($this->shouldUseServerDigestAuth($response)) {
|
161 |
+
return $this->sendRequest($request);
|
162 |
+
}
|
163 |
+
if ($authInfo = $response->getHeader('authentication-info')) {
|
164 |
+
$this->updateChallenge($this->serverChallenge, $authInfo);
|
165 |
+
}
|
166 |
+
if ($proxyInfo = $response->getHeader('proxy-authentication-info')) {
|
167 |
+
$this->updateChallenge($this->proxyChallenge, $proxyInfo);
|
168 |
+
}
|
169 |
+
|
170 |
+
} catch (Exception $e) {
|
171 |
+
$this->disconnect();
|
172 |
+
}
|
173 |
+
|
174 |
+
unset($this->request, $this->requestBody);
|
175 |
+
|
176 |
+
if (!empty($e)) {
|
177 |
+
$this->redirectCountdown = null;
|
178 |
+
throw $e;
|
179 |
+
}
|
180 |
+
|
181 |
+
if (!$request->getConfig('follow_redirects') || !$response->isRedirect()) {
|
182 |
+
$this->redirectCountdown = null;
|
183 |
+
return $response;
|
184 |
+
} else {
|
185 |
+
return $this->handleRedirect($request, $response);
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Connects to the remote server
|
191 |
+
*
|
192 |
+
* @return bool whether the connection can be persistent
|
193 |
+
* @throws HTTP_Request2_Exception
|
194 |
+
*/
|
195 |
+
protected function connect()
|
196 |
+
{
|
197 |
+
$secure = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https');
|
198 |
+
$tunnel = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
|
199 |
+
$headers = $this->request->getHeaders();
|
200 |
+
$reqHost = $this->request->getUrl()->getHost();
|
201 |
+
if (!($reqPort = $this->request->getUrl()->getPort())) {
|
202 |
+
$reqPort = $secure? 443: 80;
|
203 |
+
}
|
204 |
+
|
205 |
+
$httpProxy = $socksProxy = false;
|
206 |
+
if (!($host = $this->request->getConfig('proxy_host'))) {
|
207 |
+
$host = $reqHost;
|
208 |
+
$port = $reqPort;
|
209 |
+
} else {
|
210 |
+
if (!($port = $this->request->getConfig('proxy_port'))) {
|
211 |
+
throw new HTTP_Request2_LogicException(
|
212 |
+
'Proxy port not provided',
|
213 |
+
HTTP_Request2_Exception::MISSING_VALUE
|
214 |
+
);
|
215 |
+
}
|
216 |
+
if ('http' == ($type = $this->request->getConfig('proxy_type'))) {
|
217 |
+
$httpProxy = true;
|
218 |
+
} elseif ('socks5' == $type) {
|
219 |
+
$socksProxy = true;
|
220 |
+
} else {
|
221 |
+
throw new HTTP_Request2_NotImplementedException(
|
222 |
+
"Proxy type '{$type}' is not supported"
|
223 |
+
);
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
if ($tunnel && !$httpProxy) {
|
228 |
+
throw new HTTP_Request2_LogicException(
|
229 |
+
"Trying to perform CONNECT request without proxy",
|
230 |
+
HTTP_Request2_Exception::MISSING_VALUE
|
231 |
+
);
|
232 |
+
}
|
233 |
+
if ($secure && !in_array('ssl', stream_get_transports())) {
|
234 |
+
throw new HTTP_Request2_LogicException(
|
235 |
+
'Need OpenSSL support for https:// requests',
|
236 |
+
HTTP_Request2_Exception::MISCONFIGURATION
|
237 |
+
);
|
238 |
+
}
|
239 |
+
|
240 |
+
// RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
|
241 |
+
// connection token to a proxy server...
|
242 |
+
if ($httpProxy && !$secure && !empty($headers['connection'])
|
243 |
+
&& 'Keep-Alive' == $headers['connection']
|
244 |
+
) {
|
245 |
+
$this->request->setHeader('connection');
|
246 |
+
}
|
247 |
+
|
248 |
+
$keepAlive = ('1.1' == $this->request->getConfig('protocol_version') &&
|
249 |
+
empty($headers['connection'])) ||
|
250 |
+
(!empty($headers['connection']) &&
|
251 |
+
'Keep-Alive' == $headers['connection']);
|
252 |
+
|
253 |
+
$options = array();
|
254 |
+
if ($ip = $this->request->getConfig('local_ip')) {
|
255 |
+
$options['socket'] = array(
|
256 |
+
'bindto' => (false === strpos($ip, ':') ? $ip : '[' . $ip . ']') . ':0'
|
257 |
+
);
|
258 |
+
}
|
259 |
+
if ($secure || $tunnel) {
|
260 |
+
$options['ssl'] = array();
|
261 |
+
foreach ($this->request->getConfig() as $name => $value) {
|
262 |
+
if ('ssl_' == substr($name, 0, 4) && null !== $value) {
|
263 |
+
if ('ssl_verify_host' == $name) {
|
264 |
+
if ($value) {
|
265 |
+
$options['ssl']['CN_match'] = $reqHost;
|
266 |
+
}
|
267 |
+
} else {
|
268 |
+
$options['ssl'][substr($name, 4)] = $value;
|
269 |
+
}
|
270 |
+
}
|
271 |
+
}
|
272 |
+
ksort($options['ssl']);
|
273 |
+
}
|
274 |
+
|
275 |
+
// Use global request timeout if given, see feature requests #5735, #8964
|
276 |
+
if ($timeout = $this->request->getConfig('timeout')) {
|
277 |
+
$deadline = time() + $timeout;
|
278 |
+
} else {
|
279 |
+
$deadline = null;
|
280 |
+
}
|
281 |
+
|
282 |
+
// Changing SSL context options after connection is established does *not*
|
283 |
+
// work, we need a new connection if options change
|
284 |
+
$remote = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')
|
285 |
+
. $host . ':' . $port;
|
286 |
+
$socketKey = $remote . (
|
287 |
+
($secure && $httpProxy || $socksProxy)
|
288 |
+
? "->{$reqHost}:{$reqPort}" : ''
|
289 |
+
) . (empty($options)? '': ':' . serialize($options));
|
290 |
+
unset($this->socket);
|
291 |
+
|
292 |
+
// We use persistent connections and have a connected socket?
|
293 |
+
// Ensure that the socket is still connected, see bug #16149
|
294 |
+
if ($keepAlive && !empty(self::$sockets[$socketKey])
|
295 |
+
&& !self::$sockets[$socketKey]->eof()
|
296 |
+
) {
|
297 |
+
$this->socket =& self::$sockets[$socketKey];
|
298 |
+
|
299 |
+
} else {
|
300 |
+
if ($socksProxy) {
|
301 |
+
require_once 'HTTP/Request2/SOCKS5.php';
|
302 |
+
|
303 |
+
$this->socket = new HTTP_Request2_SOCKS5(
|
304 |
+
$remote, $this->request->getConfig('connect_timeout'),
|
305 |
+
$options, $this->request->getConfig('proxy_user'),
|
306 |
+
$this->request->getConfig('proxy_password')
|
307 |
+
);
|
308 |
+
// handle request timeouts ASAP
|
309 |
+
$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
|
310 |
+
$this->socket->connect($reqHost, $reqPort);
|
311 |
+
if (!$secure) {
|
312 |
+
$conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";
|
313 |
+
} else {
|
314 |
+
$this->socket->enableCrypto();
|
315 |
+
$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
|
316 |
+
}
|
317 |
+
|
318 |
+
} elseif ($secure && $httpProxy && !$tunnel) {
|
319 |
+
$this->establishTunnel();
|
320 |
+
$conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";
|
321 |
+
|
322 |
+
} else {
|
323 |
+
$this->socket = new HTTP_Request2_SocketWrapper(
|
324 |
+
$remote, $this->request->getConfig('connect_timeout'), $options
|
325 |
+
);
|
326 |
+
}
|
327 |
+
$this->request->setLastEvent('connect', empty($conninfo)? $remote: $conninfo);
|
328 |
+
self::$sockets[$socketKey] =& $this->socket;
|
329 |
+
}
|
330 |
+
$this->socket->setDeadline($deadline, $this->request->getConfig('timeout'));
|
331 |
+
return $keepAlive;
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Establishes a tunnel to a secure remote server via HTTP CONNECT request
|
336 |
+
*
|
337 |
+
* This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP
|
338 |
+
* sees that we are connected to a proxy server (duh!) rather than the server
|
339 |
+
* that presents its certificate.
|
340 |
+
*
|
341 |
+
* @link http://tools.ietf.org/html/rfc2817#section-5.2
|
342 |
+
* @throws HTTP_Request2_Exception
|
343 |
+
*/
|
344 |
+
protected function establishTunnel()
|
345 |
+
{
|
346 |
+
$donor = new self;
|
347 |
+
$connect = new HTTP_Request2(
|
348 |
+
$this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,
|
349 |
+
array_merge($this->request->getConfig(), array('adapter' => $donor))
|
350 |
+
);
|
351 |
+
$response = $connect->send();
|
352 |
+
// Need any successful (2XX) response
|
353 |
+
if (200 > $response->getStatus() || 300 <= $response->getStatus()) {
|
354 |
+
throw new HTTP_Request2_ConnectionException(
|
355 |
+
'Failed to connect via HTTPS proxy. Proxy response: ' .
|
356 |
+
$response->getStatus() . ' ' . $response->getReasonPhrase()
|
357 |
+
);
|
358 |
+
}
|
359 |
+
$this->socket = $donor->socket;
|
360 |
+
$this->socket->enableCrypto();
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* Checks whether current connection may be reused or should be closed
|
365 |
+
*
|
366 |
+
* @param boolean $requestKeepAlive whether connection could
|
367 |
+
* be persistent in the first place
|
368 |
+
* @param HTTP_Request2_Response $response response object to check
|
369 |
+
*
|
370 |
+
* @return boolean
|
371 |
+
*/
|
372 |
+
protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)
|
373 |
+
{
|
374 |
+
// Do not close socket on successful CONNECT request
|
375 |
+
if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
|
376 |
+
&& 200 <= $response->getStatus() && 300 > $response->getStatus()
|
377 |
+
) {
|
378 |
+
return true;
|
379 |
+
}
|
380 |
+
|
381 |
+
$lengthKnown = 'chunked' == strtolower($response->getHeader('transfer-encoding'))
|
382 |
+
|| null !== $response->getHeader('content-length')
|
383 |
+
// no body possible for such responses, see also request #17031
|
384 |
+
|| HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
|
385 |
+
|| in_array($response->getStatus(), array(204, 304));
|
386 |
+
$persistent = 'keep-alive' == strtolower($response->getHeader('connection')) ||
|
387 |
+
(null === $response->getHeader('connection') &&
|
388 |
+
'1.1' == $response->getVersion());
|
389 |
+
return $requestKeepAlive && $lengthKnown && $persistent;
|
390 |
+
}
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Disconnects from the remote server
|
394 |
+
*/
|
395 |
+
protected function disconnect()
|
396 |
+
{
|
397 |
+
if (!empty($this->socket)) {
|
398 |
+
$this->socket = null;
|
399 |
+
$this->request->setLastEvent('disconnect');
|
400 |
+
}
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Handles HTTP redirection
|
405 |
+
*
|
406 |
+
* This method will throw an Exception if redirect to a non-HTTP(S) location
|
407 |
+
* is attempted, also if number of redirects performed already is equal to
|
408 |
+
* 'max_redirects' configuration parameter.
|
409 |
+
*
|
410 |
+
* @param HTTP_Request2 $request Original request
|
411 |
+
* @param HTTP_Request2_Response $response Response containing redirect
|
412 |
+
*
|
413 |
+
* @return HTTP_Request2_Response Response from a new location
|
414 |
+
* @throws HTTP_Request2_Exception
|
415 |
+
*/
|
416 |
+
protected function handleRedirect(
|
417 |
+
HTTP_Request2 $request, HTTP_Request2_Response $response
|
418 |
+
) {
|
419 |
+
if (is_null($this->redirectCountdown)) {
|
420 |
+
$this->redirectCountdown = $request->getConfig('max_redirects');
|
421 |
+
}
|
422 |
+
if (0 == $this->redirectCountdown) {
|
423 |
+
$this->redirectCountdown = null;
|
424 |
+
// Copying cURL behaviour
|
425 |
+
throw new HTTP_Request2_MessageException(
|
426 |
+
'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',
|
427 |
+
HTTP_Request2_Exception::TOO_MANY_REDIRECTS
|
428 |
+
);
|
429 |
+
}
|
430 |
+
$redirectUrl = new Net_URL2(
|
431 |
+
$response->getHeader('location'),
|
432 |
+
array(Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))
|
433 |
+
);
|
434 |
+
// refuse non-HTTP redirect
|
435 |
+
if ($redirectUrl->isAbsolute()
|
436 |
+
&& !in_array($redirectUrl->getScheme(), array('http', 'https'))
|
437 |
+
) {
|
438 |
+
$this->redirectCountdown = null;
|
439 |
+
throw new HTTP_Request2_MessageException(
|
440 |
+
'Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(),
|
441 |
+
HTTP_Request2_Exception::NON_HTTP_REDIRECT
|
442 |
+
);
|
443 |
+
}
|
444 |
+
// Theoretically URL should be absolute (see http://tools.ietf.org/html/rfc2616#section-14.30),
|
445 |
+
// but in practice it is often not
|
446 |
+
if (!$redirectUrl->isAbsolute()) {
|
447 |
+
$redirectUrl = $request->getUrl()->resolve($redirectUrl);
|
448 |
+
}
|
449 |
+
$redirect = clone $request;
|
450 |
+
$redirect->setUrl($redirectUrl);
|
451 |
+
if (303 == $response->getStatus()
|
452 |
+
|| (!$request->getConfig('strict_redirects')
|
453 |
+
&& in_array($response->getStatus(), array(301, 302)))
|
454 |
+
) {
|
455 |
+
$redirect->setMethod(HTTP_Request2::METHOD_GET);
|
456 |
+
$redirect->setBody('');
|
457 |
+
}
|
458 |
+
|
459 |
+
if (0 < $this->redirectCountdown) {
|
460 |
+
$this->redirectCountdown--;
|
461 |
+
}
|
462 |
+
return $this->sendRequest($redirect);
|
463 |
+
}
|
464 |
+
|
465 |
+
/**
|
466 |
+
* Checks whether another request should be performed with server digest auth
|
467 |
+
*
|
468 |
+
* Several conditions should be satisfied for it to return true:
|
469 |
+
* - response status should be 401
|
470 |
+
* - auth credentials should be set in the request object
|
471 |
+
* - response should contain WWW-Authenticate header with digest challenge
|
472 |
+
* - there is either no challenge stored for this URL or new challenge
|
473 |
+
* contains stale=true parameter (in other case we probably just failed
|
474 |
+
* due to invalid username / password)
|
475 |
+
*
|
476 |
+
* The method stores challenge values in $challenges static property
|
477 |
+
*
|
478 |
+
* @param HTTP_Request2_Response $response response to check
|
479 |
+
*
|
480 |
+
* @return boolean whether another request should be performed
|
481 |
+
* @throws HTTP_Request2_Exception in case of unsupported challenge parameters
|
482 |
+
*/
|
483 |
+
protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response)
|
484 |
+
{
|
485 |
+
// no sense repeating a request if we don't have credentials
|
486 |
+
if (401 != $response->getStatus() || !$this->request->getAuth()) {
|
487 |
+
return false;
|
488 |
+
}
|
489 |
+
if (!$challenge = $this->parseDigestChallenge($response->getHeader('www-authenticate'))) {
|
490 |
+
return false;
|
491 |
+
}
|
492 |
+
|
493 |
+
$url = $this->request->getUrl();
|
494 |
+
$scheme = $url->getScheme();
|
495 |
+
$host = $scheme . '://' . $url->getHost();
|
496 |
+
if ($port = $url->getPort()) {
|
497 |
+
if ((0 == strcasecmp($scheme, 'http') && 80 != $port)
|
498 |
+
|| (0 == strcasecmp($scheme, 'https') && 443 != $port)
|
499 |
+
) {
|
500 |
+
$host .= ':' . $port;
|
501 |
+
}
|
502 |
+
}
|
503 |
+
|
504 |
+
if (!empty($challenge['domain'])) {
|
505 |
+
$prefixes = array();
|
506 |
+
foreach (preg_split('/\\s+/', $challenge['domain']) as $prefix) {
|
507 |
+
// don't bother with different servers
|
508 |
+
if ('/' == substr($prefix, 0, 1)) {
|
509 |
+
$prefixes[] = $host . $prefix;
|
510 |
+
}
|
511 |
+
}
|
512 |
+
}
|
513 |
+
if (empty($prefixes)) {
|
514 |
+
$prefixes = array($host . '/');
|
515 |
+
}
|
516 |
+
|
517 |
+
$ret = true;
|
518 |
+
foreach ($prefixes as $prefix) {
|
519 |
+
if (!empty(self::$challenges[$prefix])
|
520 |
+
&& (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
|
521 |
+
) {
|
522 |
+
// probably credentials are invalid
|
523 |
+
$ret = false;
|
524 |
+
}
|
525 |
+
self::$challenges[$prefix] =& $challenge;
|
526 |
+
}
|
527 |
+
return $ret;
|
528 |
+
}
|
529 |
+
|
530 |
+
/**
|
531 |
+
* Checks whether another request should be performed with proxy digest auth
|
532 |
+
*
|
533 |
+
* Several conditions should be satisfied for it to return true:
|
534 |
+
* - response status should be 407
|
535 |
+
* - proxy auth credentials should be set in the request object
|
536 |
+
* - response should contain Proxy-Authenticate header with digest challenge
|
537 |
+
* - there is either no challenge stored for this proxy or new challenge
|
538 |
+
* contains stale=true parameter (in other case we probably just failed
|
539 |
+
* due to invalid username / password)
|
540 |
+
*
|
541 |
+
* The method stores challenge values in $challenges static property
|
542 |
+
*
|
543 |
+
* @param HTTP_Request2_Response $response response to check
|
544 |
+
*
|
545 |
+
* @return boolean whether another request should be performed
|
546 |
+
* @throws HTTP_Request2_Exception in case of unsupported challenge parameters
|
547 |
+
*/
|
548 |
+
protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)
|
549 |
+
{
|
550 |
+
if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {
|
551 |
+
return false;
|
552 |
+
}
|
553 |
+
if (!($challenge = $this->parseDigestChallenge($response->getHeader('proxy-authenticate')))) {
|
554 |
+
return false;
|
555 |
+
}
|
556 |
+
|
557 |
+
$key = 'proxy://' . $this->request->getConfig('proxy_host') .
|
558 |
+
':' . $this->request->getConfig('proxy_port');
|
559 |
+
|
560 |
+
if (!empty(self::$challenges[$key])
|
561 |
+
&& (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
|
562 |
+
) {
|
563 |
+
$ret = false;
|
564 |
+
} else {
|
565 |
+
$ret = true;
|
566 |
+
}
|
567 |
+
self::$challenges[$key] = $challenge;
|
568 |
+
return $ret;
|
569 |
+
}
|
570 |
+
|
571 |
+
/**
|
572 |
+
* Extracts digest method challenge from (WWW|Proxy)-Authenticate header value
|
573 |
+
*
|
574 |
+
* There is a problem with implementation of RFC 2617: several of the parameters
|
575 |
+
* are defined as quoted-string there and thus may contain backslash escaped
|
576 |
+
* double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as
|
577 |
+
* just value of quoted-string X without surrounding quotes, it doesn't speak
|
578 |
+
* about removing backslash escaping.
|
579 |
+
*
|
580 |
+
* Now realm parameter is user-defined and human-readable, strange things
|
581 |
+
* happen when it contains quotes:
|
582 |
+
* - Apache allows quotes in realm, but apparently uses realm value without
|
583 |
+
* backslashes for digest computation
|
584 |
+
* - Squid allows (manually escaped) quotes there, but it is impossible to
|
585 |
+
* authorize with either escaped or unescaped quotes used in digest,
|
586 |
+
* probably it can't parse the response (?)
|
587 |
+
* - Both IE and Firefox display realm value with backslashes in
|
588 |
+
* the password popup and apparently use the same value for digest
|
589 |
+
*
|
590 |
+
* HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in
|
591 |
+
* quoted-string handling, unfortunately that means failure to authorize
|
592 |
+
* sometimes
|
593 |
+
*
|
594 |
+
* @param string $headerValue value of WWW-Authenticate or Proxy-Authenticate header
|
595 |
+
*
|
596 |
+
* @return mixed associative array with challenge parameters, false if
|
597 |
+
* no challenge is present in header value
|
598 |
+
* @throws HTTP_Request2_NotImplementedException in case of unsupported challenge parameters
|
599 |
+
*/
|
600 |
+
protected function parseDigestChallenge($headerValue)
|
601 |
+
{
|
602 |
+
$authParam = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
|
603 |
+
self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')';
|
604 |
+
$challenge = "!(?<=^|\\s|,)Digest ({$authParam}\\s*(,\\s*|$))+!";
|
605 |
+
if (!preg_match($challenge, $headerValue, $matches)) {
|
606 |
+
return false;
|
607 |
+
}
|
608 |
+
|
609 |
+
preg_match_all('!' . $authParam . '!', $matches[0], $params);
|
610 |
+
$paramsAry = array();
|
611 |
+
$knownParams = array('realm', 'domain', 'nonce', 'opaque', 'stale',
|
612 |
+
'algorithm', 'qop');
|
613 |
+
for ($i = 0; $i < count($params[0]); $i++) {
|
614 |
+
// section 3.2.1: Any unrecognized directive MUST be ignored.
|
615 |
+
if (in_array($params[1][$i], $knownParams)) {
|
616 |
+
if ('"' == substr($params[2][$i], 0, 1)) {
|
617 |
+
$paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
|
618 |
+
} else {
|
619 |
+
$paramsAry[$params[1][$i]] = $params[2][$i];
|
620 |
+
}
|
621 |
+
}
|
622 |
+
}
|
623 |
+
// we only support qop=auth
|
624 |
+
if (!empty($paramsAry['qop'])
|
625 |
+
&& !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
|
626 |
+
) {
|
627 |
+
throw new HTTP_Request2_NotImplementedException(
|
628 |
+
"Only 'auth' qop is currently supported in digest authentication, " .
|
629 |
+
"server requested '{$paramsAry['qop']}'"
|
630 |
+
);
|
631 |
+
}
|
632 |
+
// we only support algorithm=MD5
|
633 |
+
if (!empty($paramsAry['algorithm']) && 'MD5' != $paramsAry['algorithm']) {
|
634 |
+
throw new HTTP_Request2_NotImplementedException(
|
635 |
+
"Only 'MD5' algorithm is currently supported in digest authentication, " .
|
636 |
+
"server requested '{$paramsAry['algorithm']}'"
|
637 |
+
);
|
638 |
+
}
|
639 |
+
|
640 |
+
return $paramsAry;
|
641 |
+
}
|
642 |
+
|
643 |
+
/**
|
644 |
+
* Parses [Proxy-]Authentication-Info header value and updates challenge
|
645 |
+
*
|
646 |
+
* @param array &$challenge challenge to update
|
647 |
+
* @param string $headerValue value of [Proxy-]Authentication-Info header
|
648 |
+
*
|
649 |
+
* @todo validate server rspauth response
|
650 |
+
*/
|
651 |
+
protected function updateChallenge(&$challenge, $headerValue)
|
652 |
+
{
|
653 |
+
$authParam = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
|
654 |
+
self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')!';
|
655 |
+
$paramsAry = array();
|
656 |
+
|
657 |
+
preg_match_all($authParam, $headerValue, $params);
|
658 |
+
for ($i = 0; $i < count($params[0]); $i++) {
|
659 |
+
if ('"' == substr($params[2][$i], 0, 1)) {
|
660 |
+
$paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
|
661 |
+
} else {
|
662 |
+
$paramsAry[$params[1][$i]] = $params[2][$i];
|
663 |
+
}
|
664 |
+
}
|
665 |
+
// for now, just update the nonce value
|
666 |
+
if (!empty($paramsAry['nextnonce'])) {
|
667 |
+
$challenge['nonce'] = $paramsAry['nextnonce'];
|
668 |
+
$challenge['nc'] = 1;
|
669 |
+
}
|
670 |
+
}
|
671 |
+
|
672 |
+
/**
|
673 |
+
* Creates a value for [Proxy-]Authorization header when using digest authentication
|
674 |
+
*
|
675 |
+
* @param string $user user name
|
676 |
+
* @param string $password password
|
677 |
+
* @param string $url request URL
|
678 |
+
* @param array &$challenge digest challenge parameters
|
679 |
+
*
|
680 |
+
* @return string value of [Proxy-]Authorization request header
|
681 |
+
* @link http://tools.ietf.org/html/rfc2617#section-3.2.2
|
682 |
+
*/
|
683 |
+
protected function createDigestResponse($user, $password, $url, &$challenge)
|
684 |
+
{
|
685 |
+
if (false !== ($q = strpos($url, '?'))
|
686 |
+
&& $this->request->getConfig('digest_compat_ie')
|
687 |
+
) {
|
688 |
+
$url = substr($url, 0, $q);
|
689 |
+
}
|
690 |
+
|
691 |
+
$a1 = md5($user . ':' . $challenge['realm'] . ':' . $password);
|
692 |
+
$a2 = md5($this->request->getMethod() . ':' . $url);
|
693 |
+
|
694 |
+
if (empty($challenge['qop'])) {
|
695 |
+
$digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $a2);
|
696 |
+
} else {
|
697 |
+
$challenge['cnonce'] = 'Req2.' . rand();
|
698 |
+
if (empty($challenge['nc'])) {
|
699 |
+
$challenge['nc'] = 1;
|
700 |
+
}
|
701 |
+
$nc = sprintf('%08x', $challenge['nc']++);
|
702 |
+
$digest = md5(
|
703 |
+
$a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
|
704 |
+
$challenge['cnonce'] . ':auth:' . $a2
|
705 |
+
);
|
706 |
+
}
|
707 |
+
return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
|
708 |
+
'realm="' . $challenge['realm'] . '", ' .
|
709 |
+
'nonce="' . $challenge['nonce'] . '", ' .
|
710 |
+
'uri="' . $url . '", ' .
|
711 |
+
'response="' . $digest . '"' .
|
712 |
+
(!empty($challenge['opaque'])?
|
713 |
+
', opaque="' . $challenge['opaque'] . '"':
|
714 |
+
'') .
|
715 |
+
(!empty($challenge['qop'])?
|
716 |
+
', qop="auth", nc=' . $nc . ', cnonce="' . $challenge['cnonce'] . '"':
|
717 |
+
'');
|
718 |
+
}
|
719 |
+
|
720 |
+
/**
|
721 |
+
* Adds 'Authorization' header (if needed) to request headers array
|
722 |
+
*
|
723 |
+
* @param array &$headers request headers
|
724 |
+
* @param string $requestHost request host (needed for digest authentication)
|
725 |
+
* @param string $requestUrl request URL (needed for digest authentication)
|
726 |
+
*
|
727 |
+
* @throws HTTP_Request2_NotImplementedException
|
728 |
+
*/
|
729 |
+
protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)
|
730 |
+
{
|
731 |
+
if (!($auth = $this->request->getAuth())) {
|
732 |
+
return;
|
733 |
+
}
|
734 |
+
switch ($auth['scheme']) {
|
735 |
+
case HTTP_Request2::AUTH_BASIC:
|
736 |
+
$headers['authorization'] = 'Basic ' . base64_encode(
|
737 |
+
$auth['user'] . ':' . $auth['password']
|
738 |
+
);
|
739 |
+
break;
|
740 |
+
|
741 |
+
case HTTP_Request2::AUTH_DIGEST:
|
742 |
+
unset($this->serverChallenge);
|
743 |
+
$fullUrl = ('/' == $requestUrl[0])?
|
744 |
+
$this->request->getUrl()->getScheme() . '://' .
|
745 |
+
$requestHost . $requestUrl:
|
746 |
+
$requestUrl;
|
747 |
+
foreach (array_keys(self::$challenges) as $key) {
|
748 |
+
if ($key == substr($fullUrl, 0, strlen($key))) {
|
749 |
+
$headers['authorization'] = $this->createDigestResponse(
|
750 |
+
$auth['user'], $auth['password'],
|
751 |
+
$requestUrl, self::$challenges[$key]
|
752 |
+
);
|
753 |
+
$this->serverChallenge =& self::$challenges[$key];
|
754 |
+
break;
|
755 |
+
}
|
756 |
+
}
|
757 |
+
break;
|
758 |
+
|
759 |
+
default:
|
760 |
+
throw new HTTP_Request2_NotImplementedException(
|
761 |
+
"Unknown HTTP authentication scheme '{$auth['scheme']}'"
|
762 |
+
);
|
763 |
+
}
|
764 |
+
}
|
765 |
+
|
766 |
+
/**
|
767 |
+
* Adds 'Proxy-Authorization' header (if needed) to request headers array
|
768 |
+
*
|
769 |
+
* @param array &$headers request headers
|
770 |
+
* @param string $requestUrl request URL (needed for digest authentication)
|
771 |
+
*
|
772 |
+
* @throws HTTP_Request2_NotImplementedException
|
773 |
+
*/
|
774 |
+
protected function addProxyAuthorizationHeader(&$headers, $requestUrl)
|
775 |
+
{
|
776 |
+
if (!$this->request->getConfig('proxy_host')
|
777 |
+
|| !($user = $this->request->getConfig('proxy_user'))
|
778 |
+
|| (0 == strcasecmp('https', $this->request->getUrl()->getScheme())
|
779 |
+
&& HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())
|
780 |
+
) {
|
781 |
+
return;
|
782 |
+
}
|
783 |
+
|
784 |
+
$password = $this->request->getConfig('proxy_password');
|
785 |
+
switch ($this->request->getConfig('proxy_auth_scheme')) {
|
786 |
+
case HTTP_Request2::AUTH_BASIC:
|
787 |
+
$headers['proxy-authorization'] = 'Basic ' . base64_encode(
|
788 |
+
$user . ':' . $password
|
789 |
+
);
|
790 |
+
break;
|
791 |
+
|
792 |
+
case HTTP_Request2::AUTH_DIGEST:
|
793 |
+
unset($this->proxyChallenge);
|
794 |
+
$proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
|
795 |
+
':' . $this->request->getConfig('proxy_port');
|
796 |
+
if (!empty(self::$challenges[$proxyUrl])) {
|
797 |
+
$headers['proxy-authorization'] = $this->createDigestResponse(
|
798 |
+
$user, $password,
|
799 |
+
$requestUrl, self::$challenges[$proxyUrl]
|
800 |
+
);
|
801 |
+
$this->proxyChallenge =& self::$challenges[$proxyUrl];
|
802 |
+
}
|
803 |
+
break;
|
804 |
+
|
805 |
+
default:
|
806 |
+
throw new HTTP_Request2_NotImplementedException(
|
807 |
+
"Unknown HTTP authentication scheme '" .
|
808 |
+
$this->request->getConfig('proxy_auth_scheme') . "'"
|
809 |
+
);
|
810 |
+
}
|
811 |
+
}
|
812 |
+
|
813 |
+
|
814 |
+
/**
|
815 |
+
* Creates the string with the Request-Line and request headers
|
816 |
+
*
|
817 |
+
* @return string
|
818 |
+
* @throws HTTP_Request2_Exception
|
819 |
+
*/
|
820 |
+
protected function prepareHeaders()
|
821 |
+
{
|
822 |
+
$headers = $this->request->getHeaders();
|
823 |
+
$url = $this->request->getUrl();
|
824 |
+
$connect = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
|
825 |
+
$host = $url->getHost();
|
826 |
+
|
827 |
+
$defaultPort = 0 == strcasecmp($url->getScheme(), 'https')? 443: 80;
|
828 |
+
if (($port = $url->getPort()) && $port != $defaultPort || $connect) {
|
829 |
+
$host .= ':' . (empty($port)? $defaultPort: $port);
|
830 |
+
}
|
831 |
+
// Do not overwrite explicitly set 'Host' header, see bug #16146
|
832 |
+
if (!isset($headers['host'])) {
|
833 |
+
$headers['host'] = $host;
|
834 |
+
}
|
835 |
+
|
836 |
+
if ($connect) {
|
837 |
+
$requestUrl = $host;
|
838 |
+
|
839 |
+
} else {
|
840 |
+
if (!$this->request->getConfig('proxy_host')
|
841 |
+
|| 'http' != $this->request->getConfig('proxy_type')
|
842 |
+
|| 0 == strcasecmp($url->getScheme(), 'https')
|
843 |
+
) {
|
844 |
+
$requestUrl = '';
|
845 |
+
} else {
|
846 |
+
$requestUrl = $url->getScheme() . '://' . $host;
|
847 |
+
}
|
848 |
+
$path = $url->getPath();
|
849 |
+
$query = $url->getQuery();
|
850 |
+
$requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
|
851 |
+
}
|
852 |
+
|
853 |
+
if ('1.1' == $this->request->getConfig('protocol_version')
|
854 |
+
&& extension_loaded('zlib') && !isset($headers['accept-encoding'])
|
855 |
+
) {
|
856 |
+
$headers['accept-encoding'] = 'gzip, deflate';
|
857 |
+
}
|
858 |
+
if (($jar = $this->request->getCookieJar())
|
859 |
+
&& ($cookies = $jar->getMatching($this->request->getUrl(), true))
|
860 |
+
) {
|
861 |
+
$headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
|
862 |
+
}
|
863 |
+
|
864 |
+
$this->addAuthorizationHeader($headers, $host, $requestUrl);
|
865 |
+
$this->addProxyAuthorizationHeader($headers, $requestUrl);
|
866 |
+
$this->calculateRequestLength($headers);
|
867 |
+
if ('1.1' == $this->request->getConfig('protocol_version')) {
|
868 |
+
$this->updateExpectHeader($headers);
|
869 |
+
} else {
|
870 |
+
$this->expect100Continue = false;
|
871 |
+
}
|
872 |
+
|
873 |
+
$headersStr = $this->request->getMethod() . ' ' . $requestUrl . ' HTTP/' .
|
874 |
+
$this->request->getConfig('protocol_version') . "\r\n";
|
875 |
+
foreach ($headers as $name => $value) {
|
876 |
+
$canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
|
877 |
+
$headersStr .= $canonicalName . ': ' . $value . "\r\n";
|
878 |
+
}
|
879 |
+
return $headersStr . "\r\n";
|
880 |
+
}
|
881 |
+
|
882 |
+
/**
|
883 |
+
* Adds or removes 'Expect: 100-continue' header from request headers
|
884 |
+
*
|
885 |
+
* Also sets the $expect100Continue property. Parsing of existing header
|
886 |
+
* is somewhat needed due to its complex structure and due to the
|
887 |
+
* requirement in section 8.2.3 of RFC 2616:
|
888 |
+
* > A client MUST NOT send an Expect request-header field (section
|
889 |
+
* > 14.20) with the "100-continue" expectation if it does not intend
|
890 |
+
* > to send a request body.
|
891 |
+
*
|
892 |
+
* @param array &$headers Array of headers prepared for the request
|
893 |
+
*
|
894 |
+
* @throws HTTP_Request2_LogicException
|
895 |
+
* @link http://pear.php.net/bugs/bug.php?id=19233
|
896 |
+
* @link http://tools.ietf.org/html/rfc2616#section-8.2.3
|
897 |
+
*/
|
898 |
+
protected function updateExpectHeader(&$headers)
|
899 |
+
{
|
900 |
+
$this->expect100Continue = false;
|
901 |
+
$expectations = array();
|
902 |
+
if (isset($headers['expect'])) {
|
903 |
+
if ('' === $headers['expect']) {
|
904 |
+
// empty 'Expect' header is technically invalid, so just get rid of it
|
905 |
+
unset($headers['expect']);
|
906 |
+
return;
|
907 |
+
}
|
908 |
+
// build regexp to parse the value of existing Expect header
|
909 |
+
$expectParam = ';\s*' . self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
|
910 |
+
. self::REGEXP_TOKEN . '|'
|
911 |
+
. self::REGEXP_QUOTED_STRING . '))?\s*';
|
912 |
+
$expectExtension = self::REGEXP_TOKEN . '(?:\s*=\s*(?:'
|
913 |
+
. self::REGEXP_TOKEN . '|'
|
914 |
+
. self::REGEXP_QUOTED_STRING . ')\s*(?:'
|
915 |
+
. $expectParam . ')*)?';
|
916 |
+
$expectItem = '!(100-continue|' . $expectExtension . ')!A';
|
917 |
+
|
918 |
+
$pos = 0;
|
919 |
+
$length = strlen($headers['expect']);
|
920 |
+
|
921 |
+
while ($pos < $length) {
|
922 |
+
$pos += strspn($headers['expect'], " \t", $pos);
|
923 |
+
if (',' === substr($headers['expect'], $pos, 1)) {
|
924 |
+
$pos++;
|
925 |
+
continue;
|
926 |
+
|
927 |
+
} elseif (!preg_match($expectItem, $headers['expect'], $m, 0, $pos)) {
|
928 |
+
throw new HTTP_Request2_LogicException(
|
929 |
+
"Cannot parse value '{$headers['expect']}' of Expect header",
|
930 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
931 |
+
);
|
932 |
+
|
933 |
+
} else {
|
934 |
+
$pos += strlen($m[0]);
|
935 |
+
if (strcasecmp('100-continue', $m[0])) {
|
936 |
+
$expectations[] = $m[0];
|
937 |
+
}
|
938 |
+
}
|
939 |
+
}
|
940 |
+
}
|
941 |
+
|
942 |
+
if (1024 < $this->contentLength) {
|
943 |
+
$expectations[] = '100-continue';
|
944 |
+
$this->expect100Continue = true;
|
945 |
+
}
|
946 |
+
|
947 |
+
if (empty($expectations)) {
|
948 |
+
unset($headers['expect']);
|
949 |
+
} else {
|
950 |
+
$headers['expect'] = implode(',', $expectations);
|
951 |
+
}
|
952 |
+
}
|
953 |
+
|
954 |
+
/**
|
955 |
+
* Sends the request body
|
956 |
+
*
|
957 |
+
* @throws HTTP_Request2_MessageException
|
958 |
+
*/
|
959 |
+
protected function writeBody()
|
960 |
+
{
|
961 |
+
if (in_array($this->request->getMethod(), self::$bodyDisallowed)
|
962 |
+
|| 0 == $this->contentLength
|
963 |
+
) {
|
964 |
+
return;
|
965 |
+
}
|
966 |
+
|
967 |
+
$position = 0;
|
968 |
+
$bufferSize = $this->request->getConfig('buffer_size');
|
969 |
+
$headers = $this->request->getHeaders();
|
970 |
+
$chunked = isset($headers['transfer-encoding']);
|
971 |
+
while ($position < $this->contentLength) {
|
972 |
+
if (is_string($this->requestBody)) {
|
973 |
+
$str = substr($this->requestBody, $position, $bufferSize);
|
974 |
+
} elseif (is_resource($this->requestBody)) {
|
975 |
+
$str = fread($this->requestBody, $bufferSize);
|
976 |
+
} else {
|
977 |
+
$str = $this->requestBody->read($bufferSize);
|
978 |
+
}
|
979 |
+
if (!$chunked) {
|
980 |
+
$this->socket->write($str);
|
981 |
+
} else {
|
982 |
+
$this->socket->write(dechex(strlen($str)) . "\r\n{$str}\r\n");
|
983 |
+
}
|
984 |
+
// Provide the length of written string to the observer, request #7630
|
985 |
+
$this->request->setLastEvent('sentBodyPart', strlen($str));
|
986 |
+
$position += strlen($str);
|
987 |
+
}
|
988 |
+
|
989 |
+
// write zero-length chunk
|
990 |
+
if ($chunked) {
|
991 |
+
$this->socket->write("0\r\n\r\n");
|
992 |
+
}
|
993 |
+
$this->request->setLastEvent('sentBody', $this->contentLength);
|
994 |
+
}
|
995 |
+
|
996 |
+
/**
|
997 |
+
* Reads the remote server's response
|
998 |
+
*
|
999 |
+
* @return HTTP_Request2_Response
|
1000 |
+
* @throws HTTP_Request2_Exception
|
1001 |
+
*/
|
1002 |
+
protected function readResponse()
|
1003 |
+
{
|
1004 |
+
$bufferSize = $this->request->getConfig('buffer_size');
|
1005 |
+
// http://tools.ietf.org/html/rfc2616#section-8.2.3
|
1006 |
+
// ...the client SHOULD NOT wait for an indefinite period before sending the request body
|
1007 |
+
$timeout = $this->expect100Continue ? 1 : null;
|
1008 |
+
|
1009 |
+
do {
|
1010 |
+
try {
|
1011 |
+
$response = new HTTP_Request2_Response(
|
1012 |
+
$this->socket->readLine($bufferSize, $timeout), true, $this->request->getUrl()
|
1013 |
+
);
|
1014 |
+
do {
|
1015 |
+
$headerLine = $this->socket->readLine($bufferSize);
|
1016 |
+
$response->parseHeaderLine($headerLine);
|
1017 |
+
} while ('' != $headerLine);
|
1018 |
+
|
1019 |
+
} catch (HTTP_Request2_MessageException $e) {
|
1020 |
+
if (HTTP_Request2_Exception::TIMEOUT === $e->getCode()
|
1021 |
+
&& $this->expect100Continue
|
1022 |
+
) {
|
1023 |
+
return null;
|
1024 |
+
}
|
1025 |
+
throw $e;
|
1026 |
+
}
|
1027 |
+
if ($this->expect100Continue && 100 == $response->getStatus()) {
|
1028 |
+
return $response;
|
1029 |
+
}
|
1030 |
+
} while (in_array($response->getStatus(), array(100, 101)));
|
1031 |
+
|
1032 |
+
$this->request->setLastEvent('receivedHeaders', $response);
|
1033 |
+
|
1034 |
+
// No body possible in such responses
|
1035 |
+
if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
|
1036 |
+
|| (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod()
|
1037 |
+
&& 200 <= $response->getStatus() && 300 > $response->getStatus())
|
1038 |
+
|| in_array($response->getStatus(), array(204, 304))
|
1039 |
+
) {
|
1040 |
+
return $response;
|
1041 |
+
}
|
1042 |
+
|
1043 |
+
$chunked = 'chunked' == $response->getHeader('transfer-encoding');
|
1044 |
+
$length = $response->getHeader('content-length');
|
1045 |
+
$hasBody = false;
|
1046 |
+
if ($chunked || null === $length || 0 < intval($length)) {
|
1047 |
+
// RFC 2616, section 4.4:
|
1048 |
+
// 3. ... If a message is received with both a
|
1049 |
+
// Transfer-Encoding header field and a Content-Length header field,
|
1050 |
+
// the latter MUST be ignored.
|
1051 |
+
$toRead = ($chunked || null === $length)? null: $length;
|
1052 |
+
$this->chunkLength = 0;
|
1053 |
+
|
1054 |
+
while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {
|
1055 |
+
if ($chunked) {
|
1056 |
+
$data = $this->readChunked($bufferSize);
|
1057 |
+
} elseif (is_null($toRead)) {
|
1058 |
+
$data = $this->socket->read($bufferSize);
|
1059 |
+
} else {
|
1060 |
+
$data = $this->socket->read(min($toRead, $bufferSize));
|
1061 |
+
$toRead -= strlen($data);
|
1062 |
+
}
|
1063 |
+
if ('' == $data && (!$this->chunkLength || $this->socket->eof())) {
|
1064 |
+
break;
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
$hasBody = true;
|
1068 |
+
if ($this->request->getConfig('store_body')) {
|
1069 |
+
$response->appendBody($data);
|
1070 |
+
}
|
1071 |
+
if (!in_array($response->getHeader('content-encoding'), array('identity', null))) {
|
1072 |
+
$this->request->setLastEvent('receivedEncodedBodyPart', $data);
|
1073 |
+
} else {
|
1074 |
+
$this->request->setLastEvent('receivedBodyPart', $data);
|
1075 |
+
}
|
1076 |
+
}
|
1077 |
+
}
|
1078 |
+
|
1079 |
+
if ($hasBody) {
|
1080 |
+
$this->request->setLastEvent('receivedBody', $response);
|
1081 |
+
}
|
1082 |
+
return $response;
|
1083 |
+
}
|
1084 |
+
|
1085 |
+
/**
|
1086 |
+
* Reads a part of response body encoded with chunked Transfer-Encoding
|
1087 |
+
*
|
1088 |
+
* @param int $bufferSize buffer size to use for reading
|
1089 |
+
*
|
1090 |
+
* @return string
|
1091 |
+
* @throws HTTP_Request2_MessageException
|
1092 |
+
*/
|
1093 |
+
protected function readChunked($bufferSize)
|
1094 |
+
{
|
1095 |
+
// at start of the next chunk?
|
1096 |
+
if (0 == $this->chunkLength) {
|
1097 |
+
$line = $this->socket->readLine($bufferSize);
|
1098 |
+
if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
|
1099 |
+
throw new HTTP_Request2_MessageException(
|
1100 |
+
"Cannot decode chunked response, invalid chunk length '{$line}'",
|
1101 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
1102 |
+
);
|
1103 |
+
} else {
|
1104 |
+
$this->chunkLength = hexdec($matches[1]);
|
1105 |
+
// Chunk with zero length indicates the end
|
1106 |
+
if (0 == $this->chunkLength) {
|
1107 |
+
$this->socket->readLine($bufferSize);
|
1108 |
+
return '';
|
1109 |
+
}
|
1110 |
+
}
|
1111 |
+
}
|
1112 |
+
$data = $this->socket->read(min($this->chunkLength, $bufferSize));
|
1113 |
+
$this->chunkLength -= strlen($data);
|
1114 |
+
if (0 == $this->chunkLength) {
|
1115 |
+
$this->socket->readLine($bufferSize); // Trailing CRLF
|
1116 |
+
}
|
1117 |
+
return $data;
|
1118 |
+
}
|
1119 |
+
}
|
1120 |
+
|
1121 |
?>
|
vendor/PEAR/HTTP/Request2/CookieJar.php
CHANGED
@@ -1,494 +1,494 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Stores cookies and passes them between HTTP requests
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/** Class representing a HTTP request message */
|
22 |
-
require_once 'HTTP/Request2.php';
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Stores cookies and passes them between HTTP requests
|
26 |
-
*
|
27 |
-
* @category HTTP
|
28 |
-
* @package HTTP_Request2
|
29 |
-
* @author Alexey Borzov <avb@php.net>
|
30 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
31 |
-
* @version Release: @package_version@
|
32 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
33 |
-
*/
|
34 |
-
class HTTP_Request2_CookieJar implements Serializable
|
35 |
-
{
|
36 |
-
/**
|
37 |
-
* Array of stored cookies
|
38 |
-
*
|
39 |
-
* The array is indexed by domain, path and cookie name
|
40 |
-
* .example.com
|
41 |
-
* /
|
42 |
-
* some_cookie => cookie data
|
43 |
-
* /subdir
|
44 |
-
* other_cookie => cookie data
|
45 |
-
* .example.org
|
46 |
-
* ...
|
47 |
-
*
|
48 |
-
* @var array
|
49 |
-
*/
|
50 |
-
protected $cookies = array();
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Whether session cookies should be serialized when serializing the jar
|
54 |
-
* @var bool
|
55 |
-
*/
|
56 |
-
protected $serializeSession = false;
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Whether Public Suffix List should be used for domain matching
|
60 |
-
* @var bool
|
61 |
-
*/
|
62 |
-
protected $useList = true;
|
63 |
-
|
64 |
-
/**
|
65 |
-
* Array with Public Suffix List data
|
66 |
-
* @var array
|
67 |
-
* @link http://publicsuffix.org/
|
68 |
-
*/
|
69 |
-
protected static $psl = array();
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Class constructor, sets various options
|
73 |
-
*
|
74 |
-
* @param bool $serializeSessionCookies Controls serializing session cookies,
|
75 |
-
* see {@link serializeSessionCookies()}
|
76 |
-
* @param bool $usePublicSuffixList Controls using Public Suffix List,
|
77 |
-
* see {@link usePublicSuffixList()}
|
78 |
-
*/
|
79 |
-
public function __construct(
|
80 |
-
$serializeSessionCookies = false, $usePublicSuffixList = true
|
81 |
-
) {
|
82 |
-
$this->serializeSessionCookies($serializeSessionCookies);
|
83 |
-
$this->usePublicSuffixList($usePublicSuffixList);
|
84 |
-
}
|
85 |
-
|
86 |
-
/**
|
87 |
-
* Returns current time formatted in ISO-8601 at UTC timezone
|
88 |
-
*
|
89 |
-
* @return string
|
90 |
-
*/
|
91 |
-
protected function now()
|
92 |
-
{
|
93 |
-
$dt = new DateTime();
|
94 |
-
$dt->setTimezone(new DateTimeZone('UTC'));
|
95 |
-
return $dt->format(DateTime::ISO8601);
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields
|
100 |
-
*
|
101 |
-
* The checks are as follows:
|
102 |
-
* - cookie array should contain 'name' and 'value' fields;
|
103 |
-
* - name and value should not contain disallowed symbols;
|
104 |
-
* - 'expires' should be either empty parseable by DateTime;
|
105 |
-
* - 'domain' and 'path' should be either not empty or an URL where
|
106 |
-
* cookie was set should be provided.
|
107 |
-
* - if $setter is provided, then document at that URL should be allowed
|
108 |
-
* to set a cookie for that 'domain'. If $setter is not provided,
|
109 |
-
* then no domain checks will be made.
|
110 |
-
*
|
111 |
-
* 'expires' field will be converted to ISO8601 format from COOKIE format,
|
112 |
-
* 'domain' and 'path' will be set from setter URL if empty.
|
113 |
-
*
|
114 |
-
* @param array $cookie cookie data, as returned by
|
115 |
-
* {@link HTTP_Request2_Response::getCookies()}
|
116 |
-
* @param Net_URL2 $setter URL of the document that sent Set-Cookie header
|
117 |
-
*
|
118 |
-
* @return array Updated cookie array
|
119 |
-
* @throws HTTP_Request2_LogicException
|
120 |
-
* @throws HTTP_Request2_MessageException
|
121 |
-
*/
|
122 |
-
protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)
|
123 |
-
{
|
124 |
-
if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {
|
125 |
-
throw new HTTP_Request2_LogicException(
|
126 |
-
"Cookie array should contain 'name' and 'value' fields",
|
127 |
-
HTTP_Request2_Exception::MISSING_VALUE
|
128 |
-
);
|
129 |
-
}
|
130 |
-
if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['name'])) {
|
131 |
-
throw new HTTP_Request2_LogicException(
|
132 |
-
"Invalid cookie name: '{$cookie['name']}'",
|
133 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
134 |
-
);
|
135 |
-
}
|
136 |
-
if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['value'])) {
|
137 |
-
throw new HTTP_Request2_LogicException(
|
138 |
-
"Invalid cookie value: '{$cookie['value']}'",
|
139 |
-
HTTP_Request2_Exception::INVALID_ARGUMENT
|
140 |
-
);
|
141 |
-
}
|
142 |
-
$cookie += array('domain' => '', 'path' => '', 'expires' => null, 'secure' => false);
|
143 |
-
|
144 |
-
// Need ISO-8601 date @ UTC timezone
|
145 |
-
if (!empty($cookie['expires'])
|
146 |
-
&& !preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+0000$/', $cookie['expires'])
|
147 |
-
) {
|
148 |
-
try {
|
149 |
-
$dt = new DateTime($cookie['expires']);
|
150 |
-
$dt->setTimezone(new DateTimeZone('UTC'));
|
151 |
-
$cookie['expires'] = $dt->format(DateTime::ISO8601);
|
152 |
-
} catch (Exception $e) {
|
153 |
-
throw new HTTP_Request2_LogicException($e->getMessage());
|
154 |
-
}
|
155 |
-
}
|
156 |
-
|
157 |
-
if (empty($cookie['domain']) || empty($cookie['path'])) {
|
158 |
-
if (!$setter) {
|
159 |
-
throw new HTTP_Request2_LogicException(
|
160 |
-
'Cookie misses domain and/or path component, cookie setter URL needed',
|
161 |
-
HTTP_Request2_Exception::MISSING_VALUE
|
162 |
-
);
|
163 |
-
}
|
164 |
-
if (empty($cookie['domain'])) {
|
165 |
-
if ($host = $setter->getHost()) {
|
166 |
-
$cookie['domain'] = $host;
|
167 |
-
} else {
|
168 |
-
throw new HTTP_Request2_LogicException(
|
169 |
-
'Setter URL does not contain host part, can\'t set cookie domain',
|
170 |
-
HTTP_Request2_Exception::MISSING_VALUE
|
171 |
-
);
|
172 |
-
}
|
173 |
-
}
|
174 |
-
if (empty($cookie['path'])) {
|
175 |
-
$path = $setter->getPath();
|
176 |
-
$cookie['path'] = empty($path)? '/': substr($path, 0, strrpos($path, '/') + 1);
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
if ($setter && !$this->domainMatch($setter->getHost(), $cookie['domain'])) {
|
181 |
-
throw new HTTP_Request2_MessageException(
|
182 |
-
"Domain " . $setter->getHost() . " cannot set cookies for "
|
183 |
-
. $cookie['domain']
|
184 |
-
);
|
185 |
-
}
|
186 |
-
|
187 |
-
return $cookie;
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Stores a cookie in the jar
|
192 |
-
*
|
193 |
-
* @param array $cookie cookie data, as returned by
|
194 |
-
* {@link HTTP_Request2_Response::getCookies()}
|
195 |
-
* @param Net_URL2 $setter URL of the document that sent Set-Cookie header
|
196 |
-
*
|
197 |
-
* @throws HTTP_Request2_Exception
|
198 |
-
*/
|
199 |
-
public function store(array $cookie, Net_URL2 $setter = null)
|
200 |
-
{
|
201 |
-
$cookie = $this->checkAndUpdateFields($cookie, $setter);
|
202 |
-
|
203 |
-
if (strlen($cookie['value'])
|
204 |
-
&& (is_null($cookie['expires']) || $cookie['expires'] > $this->now())
|
205 |
-
) {
|
206 |
-
if (!isset($this->cookies[$cookie['domain']])) {
|
207 |
-
$this->cookies[$cookie['domain']] = array();
|
208 |
-
}
|
209 |
-
if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
|
210 |
-
$this->cookies[$cookie['domain']][$cookie['path']] = array();
|
211 |
-
}
|
212 |
-
$this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
|
213 |
-
|
214 |
-
} elseif (isset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']])) {
|
215 |
-
unset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']]);
|
216 |
-
}
|
217 |
-
}
|
218 |
-
|
219 |
-
/**
|
220 |
-
* Adds cookies set in HTTP response to the jar
|
221 |
-
*
|
222 |
-
* @param HTTP_Request2_Response $response HTTP response message
|
223 |
-
* @param Net_URL2 $setter original request URL, needed for
|
224 |
-
* setting default domain/path
|
225 |
-
*/
|
226 |
-
public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)
|
227 |
-
{
|
228 |
-
foreach ($response->getCookies() as $cookie) {
|
229 |
-
$this->store($cookie, $setter);
|
230 |
-
}
|
231 |
-
}
|
232 |
-
|
233 |
-
/**
|
234 |
-
* Returns all cookies matching a given request URL
|
235 |
-
*
|
236 |
-
* The following checks are made:
|
237 |
-
* - cookie domain should match request host
|
238 |
-
* - cookie path should be a prefix for request path
|
239 |
-
* - 'secure' cookies will only be sent for HTTPS requests
|
240 |
-
*
|
241 |
-
* @param Net_URL2 $url Request url
|
242 |
-
* @param bool $asString Whether to return cookies as string for "Cookie: " header
|
243 |
-
*
|
244 |
-
* @return array|string Matching cookies
|
245 |
-
*/
|
246 |
-
public function getMatching(Net_URL2 $url, $asString = false)
|
247 |
-
{
|
248 |
-
$host = $url->getHost();
|
249 |
-
$path = $url->getPath();
|
250 |
-
$secure = 0 == strcasecmp($url->getScheme(), 'https');
|
251 |
-
|
252 |
-
$matched = $ret = array();
|
253 |
-
foreach (array_keys($this->cookies) as $domain) {
|
254 |
-
if ($this->domainMatch($host, $domain)) {
|
255 |
-
foreach (array_keys($this->cookies[$domain]) as $cPath) {
|
256 |
-
if (0 === strpos($path, $cPath)) {
|
257 |
-
foreach ($this->cookies[$domain][$cPath] as $name => $cookie) {
|
258 |
-
if (!$cookie['secure'] || $secure) {
|
259 |
-
$matched[$name][strlen($cookie['path'])] = $cookie;
|
260 |
-
}
|
261 |
-
}
|
262 |
-
}
|
263 |
-
}
|
264 |
-
}
|
265 |
-
}
|
266 |
-
foreach ($matched as $cookies) {
|
267 |
-
krsort($cookies);
|
268 |
-
$ret = array_merge($ret, $cookies);
|
269 |
-
}
|
270 |
-
if (!$asString) {
|
271 |
-
return $ret;
|
272 |
-
} else {
|
273 |
-
$str = '';
|
274 |
-
foreach ($ret as $c) {
|
275 |
-
$str .= (empty($str)? '': '; ') . $c['name'] . '=' . $c['value'];
|
276 |
-
}
|
277 |
-
return $str;
|
278 |
-
}
|
279 |
-
}
|
280 |
-
|
281 |
-
/**
|
282 |
-
* Returns all cookies stored in a jar
|
283 |
-
*
|
284 |
-
* @return array
|
285 |
-
*/
|
286 |
-
public function getAll()
|
287 |
-
{
|
288 |
-
$cookies = array();
|
289 |
-
foreach (array_keys($this->cookies) as $domain) {
|
290 |
-
foreach (array_keys($this->cookies[$domain]) as $path) {
|
291 |
-
foreach ($this->cookies[$domain][$path] as $name => $cookie) {
|
292 |
-
$cookies[] = $cookie;
|
293 |
-
}
|
294 |
-
}
|
295 |
-
}
|
296 |
-
return $cookies;
|
297 |
-
}
|
298 |
-
|
299 |
-
/**
|
300 |
-
* Sets whether session cookies should be serialized when serializing the jar
|
301 |
-
*
|
302 |
-
* @param boolean $serialize serialize?
|
303 |
-
*/
|
304 |
-
public function serializeSessionCookies($serialize)
|
305 |
-
{
|
306 |
-
$this->serializeSession = (bool)$serialize;
|
307 |
-
}
|
308 |
-
|
309 |
-
/**
|
310 |
-
* Sets whether Public Suffix List should be used for restricting cookie-setting
|
311 |
-
*
|
312 |
-
* Without PSL {@link domainMatch()} will only prevent setting cookies for
|
313 |
-
* top-level domains like '.com' or '.org'. However, it will not prevent
|
314 |
-
* setting a cookie for '.co.uk' even though only third-level registrations
|
315 |
-
* are possible in .uk domain.
|
316 |
-
*
|
317 |
-
* With the List it is possible to find the highest level at which a domain
|
318 |
-
* may be registered for a particular top-level domain and consequently
|
319 |
-
* prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by
|
320 |
-
* Firefox, Chrome and Opera browsers to restrict cookie setting.
|
321 |
-
*
|
322 |
-
* Note that PSL is licensed differently to HTTP_Request2 package (refer to
|
323 |
-
* the license information in public-suffix-list.php), so you can disable
|
324 |
-
* its use if this is an issue for you.
|
325 |
-
*
|
326 |
-
* @param boolean $useList use the list?
|
327 |
-
*
|
328 |
-
* @link http://publicsuffix.org/learn/
|
329 |
-
*/
|
330 |
-
public function usePublicSuffixList($useList)
|
331 |
-
{
|
332 |
-
$this->useList = (bool)$useList;
|
333 |
-
}
|
334 |
-
|
335 |
-
/**
|
336 |
-
* Returns string representation of object
|
337 |
-
*
|
338 |
-
* @return string
|
339 |
-
*
|
340 |
-
* @see Serializable::serialize()
|
341 |
-
*/
|
342 |
-
public function serialize()
|
343 |
-
{
|
344 |
-
$cookies = $this->getAll();
|
345 |
-
if (!$this->serializeSession) {
|
346 |
-
for ($i = count($cookies) - 1; $i >= 0; $i--) {
|
347 |
-
if (empty($cookies[$i]['expires'])) {
|
348 |
-
unset($cookies[$i]);
|
349 |
-
}
|
350 |
-
}
|
351 |
-
}
|
352 |
-
return serialize(array(
|
353 |
-
'cookies' => $cookies,
|
354 |
-
'serializeSession' => $this->serializeSession,
|
355 |
-
'useList' => $this->useList
|
356 |
-
));
|
357 |
-
}
|
358 |
-
|
359 |
-
/**
|
360 |
-
* Constructs the object from serialized string
|
361 |
-
*
|
362 |
-
* @param string $serialized string representation
|
363 |
-
*
|
364 |
-
* @see Serializable::unserialize()
|
365 |
-
*/
|
366 |
-
public function unserialize($serialized)
|
367 |
-
{
|
368 |
-
$data = unserialize($serialized);
|
369 |
-
$now = $this->now();
|
370 |
-
$this->serializeSessionCookies($data['serializeSession']);
|
371 |
-
$this->usePublicSuffixList($data['useList']);
|
372 |
-
foreach ($data['cookies'] as $cookie) {
|
373 |
-
if (!empty($cookie['expires']) && $cookie['expires'] <= $now) {
|
374 |
-
continue;
|
375 |
-
}
|
376 |
-
if (!isset($this->cookies[$cookie['domain']])) {
|
377 |
-
$this->cookies[$cookie['domain']] = array();
|
378 |
-
}
|
379 |
-
if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
|
380 |
-
$this->cookies[$cookie['domain']][$cookie['path']] = array();
|
381 |
-
}
|
382 |
-
$this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
|
383 |
-
}
|
384 |
-
}
|
385 |
-
|
386 |
-
/**
|
387 |
-
* Checks whether a cookie domain matches a request host.
|
388 |
-
*
|
389 |
-
* The method is used by {@link store()} to check for whether a document
|
390 |
-
* at given URL can set a cookie with a given domain attribute and by
|
391 |
-
* {@link getMatching()} to find cookies matching the request URL.
|
392 |
-
*
|
393 |
-
* @param string $requestHost request host
|
394 |
-
* @param string $cookieDomain cookie domain
|
395 |
-
*
|
396 |
-
* @return bool match success
|
397 |
-
*/
|
398 |
-
public function domainMatch($requestHost, $cookieDomain)
|
399 |
-
{
|
400 |
-
if ($requestHost == $cookieDomain) {
|
401 |
-
return true;
|
402 |
-
}
|
403 |
-
// IP address, we require exact match
|
404 |
-
if (preg_match('/^(?:\d{1,3}\.){3}\d{1,3}$/', $requestHost)) {
|
405 |
-
return false;
|
406 |
-
}
|
407 |
-
if ('.' != $cookieDomain[0]) {
|
408 |
-
$cookieDomain = '.' . $cookieDomain;
|
409 |
-
}
|
410 |
-
// prevents setting cookies for '.com' and similar domains
|
411 |
-
if (!$this->useList && substr_count($cookieDomain, '.') < 2
|
412 |
-
|| $this->useList && !self::getRegisteredDomain($cookieDomain)
|
413 |
-
) {
|
414 |
-
return false;
|
415 |
-
}
|
416 |
-
return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;
|
417 |
-
}
|
418 |
-
|
419 |
-
/**
|
420 |
-
* Removes subdomains to get the registered domain (the first after top-level)
|
421 |
-
*
|
422 |
-
* The method will check Public Suffix List to find out where top-level
|
423 |
-
* domain ends and registered domain starts. It will remove domain parts
|
424 |
-
* to the left of registered one.
|
425 |
-
*
|
426 |
-
* @param string $domain domain name
|
427 |
-
*
|
428 |
-
* @return string|bool registered domain, will return false if $domain is
|
429 |
-
* either invalid or a TLD itself
|
430 |
-
*/
|
431 |
-
public static function getRegisteredDomain($domain)
|
432 |
-
{
|
433 |
-
$domainParts = explode('.', ltrim($domain, '.'));
|
434 |
-
|
435 |
-
// load the list if needed
|
436 |
-
if (empty(self::$psl)) {
|
437 |
-
$path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2';
|
438 |
-
if (0 === strpos($path, '@' . 'data_dir@')) {
|
439 |
-
$path = realpath(
|
440 |
-
dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'
|
441 |
-
. DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'
|
442 |
-
);
|
443 |
-
}
|
444 |
-
self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';
|
445 |
-
}
|
446 |
-
|
447 |
-
if (!($result = self::checkDomainsList($domainParts, self::$psl))) {
|
448 |
-
// known TLD, invalid domain name
|
449 |
-
return false;
|
450 |
-
}
|
451 |
-
|
452 |
-
// unknown TLD
|
453 |
-
if (!strpos($result, '.')) {
|
454 |
-
// fallback to checking that domain "has at least two dots"
|
455 |
-
if (2 > ($count = count($domainParts))) {
|
456 |
-
return false;
|
457 |
-
}
|
458 |
-
return $domainParts[$count - 2] . '.' . $domainParts[$count - 1];
|
459 |
-
}
|
460 |
-
return $result;
|
461 |
-
}
|
462 |
-
|
463 |
-
/**
|
464 |
-
* Recursive helper method for {@link getRegisteredDomain()}
|
465 |
-
*
|
466 |
-
* @param array $domainParts remaining domain parts
|
467 |
-
* @param mixed $listNode node in {@link HTTP_Request2_CookieJar::$psl} to check
|
468 |
-
*
|
469 |
-
* @return string|null concatenated domain parts, null in case of error
|
470 |
-
*/
|
471 |
-
protected static function checkDomainsList(array $domainParts, $listNode)
|
472 |
-
{
|
473 |
-
$sub = array_pop($domainParts);
|
474 |
-
$result = null;
|
475 |
-
|
476 |
-
if (!is_array($listNode) || is_null($sub)
|
477 |
-
|| array_key_exists('!' . $sub, $listNode)
|
478 |
-
) {
|
479 |
-
return $sub;
|
480 |
-
|
481 |
-
} elseif (array_key_exists($sub, $listNode)) {
|
482 |
-
$result = self::checkDomainsList($domainParts, $listNode[$sub]);
|
483 |
-
|
484 |
-
} elseif (array_key_exists('*', $listNode)) {
|
485 |
-
$result = self::checkDomainsList($domainParts, $listNode['*']);
|
486 |
-
|
487 |
-
} else {
|
488 |
-
return $sub;
|
489 |
-
}
|
490 |
-
|
491 |
-
return (strlen($result) > 0) ? ($result . '.' . $sub) : null;
|
492 |
-
}
|
493 |
-
}
|
494 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Stores cookies and passes them between HTTP requests
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/** Class representing a HTTP request message */
|
22 |
+
require_once 'HTTP/Request2.php';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Stores cookies and passes them between HTTP requests
|
26 |
+
*
|
27 |
+
* @category HTTP
|
28 |
+
* @package HTTP_Request2
|
29 |
+
* @author Alexey Borzov <avb@php.net>
|
30 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
31 |
+
* @version Release: @package_version@
|
32 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
33 |
+
*/
|
34 |
+
class HTTP_Request2_CookieJar implements Serializable
|
35 |
+
{
|
36 |
+
/**
|
37 |
+
* Array of stored cookies
|
38 |
+
*
|
39 |
+
* The array is indexed by domain, path and cookie name
|
40 |
+
* .example.com
|
41 |
+
* /
|
42 |
+
* some_cookie => cookie data
|
43 |
+
* /subdir
|
44 |
+
* other_cookie => cookie data
|
45 |
+
* .example.org
|
46 |
+
* ...
|
47 |
+
*
|
48 |
+
* @var array
|
49 |
+
*/
|
50 |
+
protected $cookies = array();
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Whether session cookies should be serialized when serializing the jar
|
54 |
+
* @var bool
|
55 |
+
*/
|
56 |
+
protected $serializeSession = false;
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Whether Public Suffix List should be used for domain matching
|
60 |
+
* @var bool
|
61 |
+
*/
|
62 |
+
protected $useList = true;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Array with Public Suffix List data
|
66 |
+
* @var array
|
67 |
+
* @link http://publicsuffix.org/
|
68 |
+
*/
|
69 |
+
protected static $psl = array();
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Class constructor, sets various options
|
73 |
+
*
|
74 |
+
* @param bool $serializeSessionCookies Controls serializing session cookies,
|
75 |
+
* see {@link serializeSessionCookies()}
|
76 |
+
* @param bool $usePublicSuffixList Controls using Public Suffix List,
|
77 |
+
* see {@link usePublicSuffixList()}
|
78 |
+
*/
|
79 |
+
public function __construct(
|
80 |
+
$serializeSessionCookies = false, $usePublicSuffixList = true
|
81 |
+
) {
|
82 |
+
$this->serializeSessionCookies($serializeSessionCookies);
|
83 |
+
$this->usePublicSuffixList($usePublicSuffixList);
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Returns current time formatted in ISO-8601 at UTC timezone
|
88 |
+
*
|
89 |
+
* @return string
|
90 |
+
*/
|
91 |
+
protected function now()
|
92 |
+
{
|
93 |
+
$dt = new DateTime();
|
94 |
+
$dt->setTimezone(new DateTimeZone('UTC'));
|
95 |
+
return $dt->format(DateTime::ISO8601);
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields
|
100 |
+
*
|
101 |
+
* The checks are as follows:
|
102 |
+
* - cookie array should contain 'name' and 'value' fields;
|
103 |
+
* - name and value should not contain disallowed symbols;
|
104 |
+
* - 'expires' should be either empty parseable by DateTime;
|
105 |
+
* - 'domain' and 'path' should be either not empty or an URL where
|
106 |
+
* cookie was set should be provided.
|
107 |
+
* - if $setter is provided, then document at that URL should be allowed
|
108 |
+
* to set a cookie for that 'domain'. If $setter is not provided,
|
109 |
+
* then no domain checks will be made.
|
110 |
+
*
|
111 |
+
* 'expires' field will be converted to ISO8601 format from COOKIE format,
|
112 |
+
* 'domain' and 'path' will be set from setter URL if empty.
|
113 |
+
*
|
114 |
+
* @param array $cookie cookie data, as returned by
|
115 |
+
* {@link HTTP_Request2_Response::getCookies()}
|
116 |
+
* @param Net_URL2 $setter URL of the document that sent Set-Cookie header
|
117 |
+
*
|
118 |
+
* @return array Updated cookie array
|
119 |
+
* @throws HTTP_Request2_LogicException
|
120 |
+
* @throws HTTP_Request2_MessageException
|
121 |
+
*/
|
122 |
+
protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)
|
123 |
+
{
|
124 |
+
if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {
|
125 |
+
throw new HTTP_Request2_LogicException(
|
126 |
+
"Cookie array should contain 'name' and 'value' fields",
|
127 |
+
HTTP_Request2_Exception::MISSING_VALUE
|
128 |
+
);
|
129 |
+
}
|
130 |
+
if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['name'])) {
|
131 |
+
throw new HTTP_Request2_LogicException(
|
132 |
+
"Invalid cookie name: '{$cookie['name']}'",
|
133 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
134 |
+
);
|
135 |
+
}
|
136 |
+
if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['value'])) {
|
137 |
+
throw new HTTP_Request2_LogicException(
|
138 |
+
"Invalid cookie value: '{$cookie['value']}'",
|
139 |
+
HTTP_Request2_Exception::INVALID_ARGUMENT
|
140 |
+
);
|
141 |
+
}
|
142 |
+
$cookie += array('domain' => '', 'path' => '', 'expires' => null, 'secure' => false);
|
143 |
+
|
144 |
+
// Need ISO-8601 date @ UTC timezone
|
145 |
+
if (!empty($cookie['expires'])
|
146 |
+
&& !preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+0000$/', $cookie['expires'])
|
147 |
+
) {
|
148 |
+
try {
|
149 |
+
$dt = new DateTime($cookie['expires']);
|
150 |
+
$dt->setTimezone(new DateTimeZone('UTC'));
|
151 |
+
$cookie['expires'] = $dt->format(DateTime::ISO8601);
|
152 |
+
} catch (Exception $e) {
|
153 |
+
throw new HTTP_Request2_LogicException($e->getMessage());
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
if (empty($cookie['domain']) || empty($cookie['path'])) {
|
158 |
+
if (!$setter) {
|
159 |
+
throw new HTTP_Request2_LogicException(
|
160 |
+
'Cookie misses domain and/or path component, cookie setter URL needed',
|
161 |
+
HTTP_Request2_Exception::MISSING_VALUE
|
162 |
+
);
|
163 |
+
}
|
164 |
+
if (empty($cookie['domain'])) {
|
165 |
+
if ($host = $setter->getHost()) {
|
166 |
+
$cookie['domain'] = $host;
|
167 |
+
} else {
|
168 |
+
throw new HTTP_Request2_LogicException(
|
169 |
+
'Setter URL does not contain host part, can\'t set cookie domain',
|
170 |
+
HTTP_Request2_Exception::MISSING_VALUE
|
171 |
+
);
|
172 |
+
}
|
173 |
+
}
|
174 |
+
if (empty($cookie['path'])) {
|
175 |
+
$path = $setter->getPath();
|
176 |
+
$cookie['path'] = empty($path)? '/': substr($path, 0, strrpos($path, '/') + 1);
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
if ($setter && !$this->domainMatch($setter->getHost(), $cookie['domain'])) {
|
181 |
+
throw new HTTP_Request2_MessageException(
|
182 |
+
"Domain " . $setter->getHost() . " cannot set cookies for "
|
183 |
+
. $cookie['domain']
|
184 |
+
);
|
185 |
+
}
|
186 |
+
|
187 |
+
return $cookie;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Stores a cookie in the jar
|
192 |
+
*
|
193 |
+
* @param array $cookie cookie data, as returned by
|
194 |
+
* {@link HTTP_Request2_Response::getCookies()}
|
195 |
+
* @param Net_URL2 $setter URL of the document that sent Set-Cookie header
|
196 |
+
*
|
197 |
+
* @throws HTTP_Request2_Exception
|
198 |
+
*/
|
199 |
+
public function store(array $cookie, Net_URL2 $setter = null)
|
200 |
+
{
|
201 |
+
$cookie = $this->checkAndUpdateFields($cookie, $setter);
|
202 |
+
|
203 |
+
if (strlen($cookie['value'])
|
204 |
+
&& (is_null($cookie['expires']) || $cookie['expires'] > $this->now())
|
205 |
+
) {
|
206 |
+
if (!isset($this->cookies[$cookie['domain']])) {
|
207 |
+
$this->cookies[$cookie['domain']] = array();
|
208 |
+
}
|
209 |
+
if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
|
210 |
+
$this->cookies[$cookie['domain']][$cookie['path']] = array();
|
211 |
+
}
|
212 |
+
$this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
|
213 |
+
|
214 |
+
} elseif (isset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']])) {
|
215 |
+
unset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']]);
|
216 |
+
}
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Adds cookies set in HTTP response to the jar
|
221 |
+
*
|
222 |
+
* @param HTTP_Request2_Response $response HTTP response message
|
223 |
+
* @param Net_URL2 $setter original request URL, needed for
|
224 |
+
* setting default domain/path
|
225 |
+
*/
|
226 |
+
public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)
|
227 |
+
{
|
228 |
+
foreach ($response->getCookies() as $cookie) {
|
229 |
+
$this->store($cookie, $setter);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Returns all cookies matching a given request URL
|
235 |
+
*
|
236 |
+
* The following checks are made:
|
237 |
+
* - cookie domain should match request host
|
238 |
+
* - cookie path should be a prefix for request path
|
239 |
+
* - 'secure' cookies will only be sent for HTTPS requests
|
240 |
+
*
|
241 |
+
* @param Net_URL2 $url Request url
|
242 |
+
* @param bool $asString Whether to return cookies as string for "Cookie: " header
|
243 |
+
*
|
244 |
+
* @return array|string Matching cookies
|
245 |
+
*/
|
246 |
+
public function getMatching(Net_URL2 $url, $asString = false)
|
247 |
+
{
|
248 |
+
$host = $url->getHost();
|
249 |
+
$path = $url->getPath();
|
250 |
+
$secure = 0 == strcasecmp($url->getScheme(), 'https');
|
251 |
+
|
252 |
+
$matched = $ret = array();
|
253 |
+
foreach (array_keys($this->cookies) as $domain) {
|
254 |
+
if ($this->domainMatch($host, $domain)) {
|
255 |
+
foreach (array_keys($this->cookies[$domain]) as $cPath) {
|
256 |
+
if (0 === strpos($path, $cPath)) {
|
257 |
+
foreach ($this->cookies[$domain][$cPath] as $name => $cookie) {
|
258 |
+
if (!$cookie['secure'] || $secure) {
|
259 |
+
$matched[$name][strlen($cookie['path'])] = $cookie;
|
260 |
+
}
|
261 |
+
}
|
262 |
+
}
|
263 |
+
}
|
264 |
+
}
|
265 |
+
}
|
266 |
+
foreach ($matched as $cookies) {
|
267 |
+
krsort($cookies);
|
268 |
+
$ret = array_merge($ret, $cookies);
|
269 |
+
}
|
270 |
+
if (!$asString) {
|
271 |
+
return $ret;
|
272 |
+
} else {
|
273 |
+
$str = '';
|
274 |
+
foreach ($ret as $c) {
|
275 |
+
$str .= (empty($str)? '': '; ') . $c['name'] . '=' . $c['value'];
|
276 |
+
}
|
277 |
+
return $str;
|
278 |
+
}
|
279 |
+
}
|
280 |
+
|
281 |
+
/**
|
282 |
+
* Returns all cookies stored in a jar
|
283 |
+
*
|
284 |
+
* @return array
|
285 |
+
*/
|
286 |
+
public function getAll()
|
287 |
+
{
|
288 |
+
$cookies = array();
|
289 |
+
foreach (array_keys($this->cookies) as $domain) {
|
290 |
+
foreach (array_keys($this->cookies[$domain]) as $path) {
|
291 |
+
foreach ($this->cookies[$domain][$path] as $name => $cookie) {
|
292 |
+
$cookies[] = $cookie;
|
293 |
+
}
|
294 |
+
}
|
295 |
+
}
|
296 |
+
return $cookies;
|
297 |
+
}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Sets whether session cookies should be serialized when serializing the jar
|
301 |
+
*
|
302 |
+
* @param boolean $serialize serialize?
|
303 |
+
*/
|
304 |
+
public function serializeSessionCookies($serialize)
|
305 |
+
{
|
306 |
+
$this->serializeSession = (bool)$serialize;
|
307 |
+
}
|
308 |
+
|
309 |
+
/**
|
310 |
+
* Sets whether Public Suffix List should be used for restricting cookie-setting
|
311 |
+
*
|
312 |
+
* Without PSL {@link domainMatch()} will only prevent setting cookies for
|
313 |
+
* top-level domains like '.com' or '.org'. However, it will not prevent
|
314 |
+
* setting a cookie for '.co.uk' even though only third-level registrations
|
315 |
+
* are possible in .uk domain.
|
316 |
+
*
|
317 |
+
* With the List it is possible to find the highest level at which a domain
|
318 |
+
* may be registered for a particular top-level domain and consequently
|
319 |
+
* prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by
|
320 |
+
* Firefox, Chrome and Opera browsers to restrict cookie setting.
|
321 |
+
*
|
322 |
+
* Note that PSL is licensed differently to HTTP_Request2 package (refer to
|
323 |
+
* the license information in public-suffix-list.php), so you can disable
|
324 |
+
* its use if this is an issue for you.
|
325 |
+
*
|
326 |
+
* @param boolean $useList use the list?
|
327 |
+
*
|
328 |
+
* @link http://publicsuffix.org/learn/
|
329 |
+
*/
|
330 |
+
public function usePublicSuffixList($useList)
|
331 |
+
{
|
332 |
+
$this->useList = (bool)$useList;
|
333 |
+
}
|
334 |
+
|
335 |
+
/**
|
336 |
+
* Returns string representation of object
|
337 |
+
*
|
338 |
+
* @return string
|
339 |
+
*
|
340 |
+
* @see Serializable::serialize()
|
341 |
+
*/
|
342 |
+
public function serialize()
|
343 |
+
{
|
344 |
+
$cookies = $this->getAll();
|
345 |
+
if (!$this->serializeSession) {
|
346 |
+
for ($i = count($cookies) - 1; $i >= 0; $i--) {
|
347 |
+
if (empty($cookies[$i]['expires'])) {
|
348 |
+
unset($cookies[$i]);
|
349 |
+
}
|
350 |
+
}
|
351 |
+
}
|
352 |
+
return serialize(array(
|
353 |
+
'cookies' => $cookies,
|
354 |
+
'serializeSession' => $this->serializeSession,
|
355 |
+
'useList' => $this->useList
|
356 |
+
));
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* Constructs the object from serialized string
|
361 |
+
*
|
362 |
+
* @param string $serialized string representation
|
363 |
+
*
|
364 |
+
* @see Serializable::unserialize()
|
365 |
+
*/
|
366 |
+
public function unserialize($serialized)
|
367 |
+
{
|
368 |
+
$data = unserialize($serialized);
|
369 |
+
$now = $this->now();
|
370 |
+
$this->serializeSessionCookies($data['serializeSession']);
|
371 |
+
$this->usePublicSuffixList($data['useList']);
|
372 |
+
foreach ($data['cookies'] as $cookie) {
|
373 |
+
if (!empty($cookie['expires']) && $cookie['expires'] <= $now) {
|
374 |
+
continue;
|
375 |
+
}
|
376 |
+
if (!isset($this->cookies[$cookie['domain']])) {
|
377 |
+
$this->cookies[$cookie['domain']] = array();
|
378 |
+
}
|
379 |
+
if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
|
380 |
+
$this->cookies[$cookie['domain']][$cookie['path']] = array();
|
381 |
+
}
|
382 |
+
$this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
|
383 |
+
}
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Checks whether a cookie domain matches a request host.
|
388 |
+
*
|
389 |
+
* The method is used by {@link store()} to check for whether a document
|
390 |
+
* at given URL can set a cookie with a given domain attribute and by
|
391 |
+
* {@link getMatching()} to find cookies matching the request URL.
|
392 |
+
*
|
393 |
+
* @param string $requestHost request host
|
394 |
+
* @param string $cookieDomain cookie domain
|
395 |
+
*
|
396 |
+
* @return bool match success
|
397 |
+
*/
|
398 |
+
public function domainMatch($requestHost, $cookieDomain)
|
399 |
+
{
|
400 |
+
if ($requestHost == $cookieDomain) {
|
401 |
+
return true;
|
402 |
+
}
|
403 |
+
// IP address, we require exact match
|
404 |
+
if (preg_match('/^(?:\d{1,3}\.){3}\d{1,3}$/', $requestHost)) {
|
405 |
+
return false;
|
406 |
+
}
|
407 |
+
if ('.' != $cookieDomain[0]) {
|
408 |
+
$cookieDomain = '.' . $cookieDomain;
|
409 |
+
}
|
410 |
+
// prevents setting cookies for '.com' and similar domains
|
411 |
+
if (!$this->useList && substr_count($cookieDomain, '.') < 2
|
412 |
+
|| $this->useList && !self::getRegisteredDomain($cookieDomain)
|
413 |
+
) {
|
414 |
+
return false;
|
415 |
+
}
|
416 |
+
return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;
|
417 |
+
}
|
418 |
+
|
419 |
+
/**
|
420 |
+
* Removes subdomains to get the registered domain (the first after top-level)
|
421 |
+
*
|
422 |
+
* The method will check Public Suffix List to find out where top-level
|
423 |
+
* domain ends and registered domain starts. It will remove domain parts
|
424 |
+
* to the left of registered one.
|
425 |
+
*
|
426 |
+
* @param string $domain domain name
|
427 |
+
*
|
428 |
+
* @return string|bool registered domain, will return false if $domain is
|
429 |
+
* either invalid or a TLD itself
|
430 |
+
*/
|
431 |
+
public static function getRegisteredDomain($domain)
|
432 |
+
{
|
433 |
+
$domainParts = explode('.', ltrim($domain, '.'));
|
434 |
+
|
435 |
+
// load the list if needed
|
436 |
+
if (empty(self::$psl)) {
|
437 |
+
$path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2';
|
438 |
+
if (0 === strpos($path, '@' . 'data_dir@')) {
|
439 |
+
$path = realpath(
|
440 |
+
dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'
|
441 |
+
. DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'
|
442 |
+
);
|
443 |
+
}
|
444 |
+
self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';
|
445 |
+
}
|
446 |
+
|
447 |
+
if (!($result = self::checkDomainsList($domainParts, self::$psl))) {
|
448 |
+
// known TLD, invalid domain name
|
449 |
+
return false;
|
450 |
+
}
|
451 |
+
|
452 |
+
// unknown TLD
|
453 |
+
if (!strpos($result, '.')) {
|
454 |
+
// fallback to checking that domain "has at least two dots"
|
455 |
+
if (2 > ($count = count($domainParts))) {
|
456 |
+
return false;
|
457 |
+
}
|
458 |
+
return $domainParts[$count - 2] . '.' . $domainParts[$count - 1];
|
459 |
+
}
|
460 |
+
return $result;
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* Recursive helper method for {@link getRegisteredDomain()}
|
465 |
+
*
|
466 |
+
* @param array $domainParts remaining domain parts
|
467 |
+
* @param mixed $listNode node in {@link HTTP_Request2_CookieJar::$psl} to check
|
468 |
+
*
|
469 |
+
* @return string|null concatenated domain parts, null in case of error
|
470 |
+
*/
|
471 |
+
protected static function checkDomainsList(array $domainParts, $listNode)
|
472 |
+
{
|
473 |
+
$sub = array_pop($domainParts);
|
474 |
+
$result = null;
|
475 |
+
|
476 |
+
if (!is_array($listNode) || is_null($sub)
|
477 |
+
|| array_key_exists('!' . $sub, $listNode)
|
478 |
+
) {
|
479 |
+
return $sub;
|
480 |
+
|
481 |
+
} elseif (array_key_exists($sub, $listNode)) {
|
482 |
+
$result = self::checkDomainsList($domainParts, $listNode[$sub]);
|
483 |
+
|
484 |
+
} elseif (array_key_exists('*', $listNode)) {
|
485 |
+
$result = self::checkDomainsList($domainParts, $listNode['*']);
|
486 |
+
|
487 |
+
} else {
|
488 |
+
return $sub;
|
489 |
+
}
|
490 |
+
|
491 |
+
return (strlen($result) > 0) ? ($result . '.' . $sub) : null;
|
492 |
+
}
|
493 |
+
}
|
494 |
?>
|
vendor/PEAR/HTTP/Request2/Exception.php
CHANGED
@@ -1,160 +1,160 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Exception classes for HTTP_Request2 package
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Base class for exceptions in PEAR
|
23 |
-
*/
|
24 |
-
require_once 'PEAR/Exception.php';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Base exception class for HTTP_Request2 package
|
28 |
-
*
|
29 |
-
* @category HTTP
|
30 |
-
* @package HTTP_Request2
|
31 |
-
* @author Alexey Borzov <avb@php.net>
|
32 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
33 |
-
* @version Release: 2.2.1
|
34 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
35 |
-
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132
|
36 |
-
*/
|
37 |
-
class HTTP_Request2_Exception extends PEAR_Exception
|
38 |
-
{
|
39 |
-
/** An invalid argument was passed to a method */
|
40 |
-
const INVALID_ARGUMENT = 1;
|
41 |
-
/** Some required value was not available */
|
42 |
-
const MISSING_VALUE = 2;
|
43 |
-
/** Request cannot be processed due to errors in PHP configuration */
|
44 |
-
const MISCONFIGURATION = 3;
|
45 |
-
/** Error reading the local file */
|
46 |
-
const READ_ERROR = 4;
|
47 |
-
|
48 |
-
/** Server returned a response that does not conform to HTTP protocol */
|
49 |
-
const MALFORMED_RESPONSE = 10;
|
50 |
-
/** Failure decoding Content-Encoding or Transfer-Encoding of response */
|
51 |
-
const DECODE_ERROR = 20;
|
52 |
-
/** Operation timed out */
|
53 |
-
const TIMEOUT = 30;
|
54 |
-
/** Number of redirects exceeded 'max_redirects' configuration parameter */
|
55 |
-
const TOO_MANY_REDIRECTS = 40;
|
56 |
-
/** Redirect to a protocol other than http(s):// */
|
57 |
-
const NON_HTTP_REDIRECT = 50;
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Native error code
|
61 |
-
* @var int
|
62 |
-
*/
|
63 |
-
private $_nativeCode;
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Constructor, can set package error code and native error code
|
67 |
-
*
|
68 |
-
* @param string $message exception message
|
69 |
-
* @param int $code package error code, one of class constants
|
70 |
-
* @param int $nativeCode error code from underlying PHP extension
|
71 |
-
*/
|
72 |
-
public function __construct($message = null, $code = null, $nativeCode = null)
|
73 |
-
{
|
74 |
-
parent::__construct($message, $code);
|
75 |
-
$this->_nativeCode = $nativeCode;
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* Returns error code produced by underlying PHP extension
|
80 |
-
*
|
81 |
-
* For Socket Adapter this may contain error number returned by
|
82 |
-
* stream_socket_client(), for Curl Adapter this will contain error number
|
83 |
-
* returned by curl_errno()
|
84 |
-
*
|
85 |
-
* @return integer
|
86 |
-
*/
|
87 |
-
public function getNativeCode()
|
88 |
-
{
|
89 |
-
return $this->_nativeCode;
|
90 |
-
}
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Exception thrown in case of missing features
|
95 |
-
*
|
96 |
-
* @category HTTP
|
97 |
-
* @package HTTP_Request2
|
98 |
-
* @author Alexey Borzov <avb@php.net>
|
99 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
100 |
-
* @version Release: 2.2.1
|
101 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
102 |
-
*/
|
103 |
-
class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception
|
104 |
-
{
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Exception that represents error in the program logic
|
109 |
-
*
|
110 |
-
* This exception usually implies a programmer's error, like passing invalid
|
111 |
-
* data to methods or trying to use PHP extensions that weren't installed or
|
112 |
-
* enabled. Usually exceptions of this kind will be thrown before request even
|
113 |
-
* starts.
|
114 |
-
*
|
115 |
-
* The exception will usually contain a package error code.
|
116 |
-
*
|
117 |
-
* @category HTTP
|
118 |
-
* @package HTTP_Request2
|
119 |
-
* @author Alexey Borzov <avb@php.net>
|
120 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
121 |
-
* @version Release: 2.2.1
|
122 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
123 |
-
*/
|
124 |
-
class HTTP_Request2_LogicException extends HTTP_Request2_Exception
|
125 |
-
{
|
126 |
-
}
|
127 |
-
|
128 |
-
/**
|
129 |
-
* Exception thrown when connection to a web or proxy server fails
|
130 |
-
*
|
131 |
-
* The exception will not contain a package error code, but will contain
|
132 |
-
* native error code, as returned by stream_socket_client() or curl_errno().
|
133 |
-
*
|
134 |
-
* @category HTTP
|
135 |
-
* @package HTTP_Request2
|
136 |
-
* @author Alexey Borzov <avb@php.net>
|
137 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
138 |
-
* @version Release: 2.2.1
|
139 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
140 |
-
*/
|
141 |
-
class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception
|
142 |
-
{
|
143 |
-
}
|
144 |
-
|
145 |
-
/**
|
146 |
-
* Exception thrown when sending or receiving HTTP message fails
|
147 |
-
*
|
148 |
-
* The exception may contain both package error code and native error code.
|
149 |
-
*
|
150 |
-
* @category HTTP
|
151 |
-
* @package HTTP_Request2
|
152 |
-
* @author Alexey Borzov <avb@php.net>
|
153 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
154 |
-
* @version Release: 2.2.1
|
155 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
156 |
-
*/
|
157 |
-
class HTTP_Request2_MessageException extends HTTP_Request2_Exception
|
158 |
-
{
|
159 |
-
}
|
160 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Exception classes for HTTP_Request2 package
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Base class for exceptions in PEAR
|
23 |
+
*/
|
24 |
+
require_once 'PEAR/Exception.php';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Base exception class for HTTP_Request2 package
|
28 |
+
*
|
29 |
+
* @category HTTP
|
30 |
+
* @package HTTP_Request2
|
31 |
+
* @author Alexey Borzov <avb@php.net>
|
32 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
33 |
+
* @version Release: 2.2.1
|
34 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
35 |
+
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=132
|
36 |
+
*/
|
37 |
+
class HTTP_Request2_Exception extends PEAR_Exception
|
38 |
+
{
|
39 |
+
/** An invalid argument was passed to a method */
|
40 |
+
const INVALID_ARGUMENT = 1;
|
41 |
+
/** Some required value was not available */
|
42 |
+
const MISSING_VALUE = 2;
|
43 |
+
/** Request cannot be processed due to errors in PHP configuration */
|
44 |
+
const MISCONFIGURATION = 3;
|
45 |
+
/** Error reading the local file */
|
46 |
+
const READ_ERROR = 4;
|
47 |
+
|
48 |
+
/** Server returned a response that does not conform to HTTP protocol */
|
49 |
+
const MALFORMED_RESPONSE = 10;
|
50 |
+
/** Failure decoding Content-Encoding or Transfer-Encoding of response */
|
51 |
+
const DECODE_ERROR = 20;
|
52 |
+
/** Operation timed out */
|
53 |
+
const TIMEOUT = 30;
|
54 |
+
/** Number of redirects exceeded 'max_redirects' configuration parameter */
|
55 |
+
const TOO_MANY_REDIRECTS = 40;
|
56 |
+
/** Redirect to a protocol other than http(s):// */
|
57 |
+
const NON_HTTP_REDIRECT = 50;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Native error code
|
61 |
+
* @var int
|
62 |
+
*/
|
63 |
+
private $_nativeCode;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Constructor, can set package error code and native error code
|
67 |
+
*
|
68 |
+
* @param string $message exception message
|
69 |
+
* @param int $code package error code, one of class constants
|
70 |
+
* @param int $nativeCode error code from underlying PHP extension
|
71 |
+
*/
|
72 |
+
public function __construct($message = null, $code = null, $nativeCode = null)
|
73 |
+
{
|
74 |
+
parent::__construct($message, $code);
|
75 |
+
$this->_nativeCode = $nativeCode;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Returns error code produced by underlying PHP extension
|
80 |
+
*
|
81 |
+
* For Socket Adapter this may contain error number returned by
|
82 |
+
* stream_socket_client(), for Curl Adapter this will contain error number
|
83 |
+
* returned by curl_errno()
|
84 |
+
*
|
85 |
+
* @return integer
|
86 |
+
*/
|
87 |
+
public function getNativeCode()
|
88 |
+
{
|
89 |
+
return $this->_nativeCode;
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Exception thrown in case of missing features
|
95 |
+
*
|
96 |
+
* @category HTTP
|
97 |
+
* @package HTTP_Request2
|
98 |
+
* @author Alexey Borzov <avb@php.net>
|
99 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
100 |
+
* @version Release: 2.2.1
|
101 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
102 |
+
*/
|
103 |
+
class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception
|
104 |
+
{
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Exception that represents error in the program logic
|
109 |
+
*
|
110 |
+
* This exception usually implies a programmer's error, like passing invalid
|
111 |
+
* data to methods or trying to use PHP extensions that weren't installed or
|
112 |
+
* enabled. Usually exceptions of this kind will be thrown before request even
|
113 |
+
* starts.
|
114 |
+
*
|
115 |
+
* The exception will usually contain a package error code.
|
116 |
+
*
|
117 |
+
* @category HTTP
|
118 |
+
* @package HTTP_Request2
|
119 |
+
* @author Alexey Borzov <avb@php.net>
|
120 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
121 |
+
* @version Release: 2.2.1
|
122 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
123 |
+
*/
|
124 |
+
class HTTP_Request2_LogicException extends HTTP_Request2_Exception
|
125 |
+
{
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Exception thrown when connection to a web or proxy server fails
|
130 |
+
*
|
131 |
+
* The exception will not contain a package error code, but will contain
|
132 |
+
* native error code, as returned by stream_socket_client() or curl_errno().
|
133 |
+
*
|
134 |
+
* @category HTTP
|
135 |
+
* @package HTTP_Request2
|
136 |
+
* @author Alexey Borzov <avb@php.net>
|
137 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
138 |
+
* @version Release: 2.2.1
|
139 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
140 |
+
*/
|
141 |
+
class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception
|
142 |
+
{
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Exception thrown when sending or receiving HTTP message fails
|
147 |
+
*
|
148 |
+
* The exception may contain both package error code and native error code.
|
149 |
+
*
|
150 |
+
* @category HTTP
|
151 |
+
* @package HTTP_Request2
|
152 |
+
* @author Alexey Borzov <avb@php.net>
|
153 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
154 |
+
* @version Release: 2.2.1
|
155 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
156 |
+
*/
|
157 |
+
class HTTP_Request2_MessageException extends HTTP_Request2_Exception
|
158 |
+
{
|
159 |
+
}
|
160 |
?>
|
vendor/PEAR/HTTP/Request2/MultipartBody.php
CHANGED
@@ -1,268 +1,268 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Helper class for building multipart/form-data request body
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/** Exception class for HTTP_Request2 package */
|
22 |
-
require_once 'HTTP/Request2/Exception.php';
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Class for building multipart/form-data request body
|
26 |
-
*
|
27 |
-
* The class helps to reduce memory consumption by streaming large file uploads
|
28 |
-
* from disk, it also allows monitoring of upload progress (see request #7630)
|
29 |
-
*
|
30 |
-
* @category HTTP
|
31 |
-
* @package HTTP_Request2
|
32 |
-
* @author Alexey Borzov <avb@php.net>
|
33 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
34 |
-
* @version Release: 2.2.1
|
35 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
36 |
-
* @link http://tools.ietf.org/html/rfc1867
|
37 |
-
*/
|
38 |
-
class HTTP_Request2_MultipartBody
|
39 |
-
{
|
40 |
-
/**
|
41 |
-
* MIME boundary
|
42 |
-
* @var string
|
43 |
-
*/
|
44 |
-
private $_boundary;
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Form parameters added via {@link HTTP_Request2::addPostParameter()}
|
48 |
-
* @var array
|
49 |
-
*/
|
50 |
-
private $_params = array();
|
51 |
-
|
52 |
-
/**
|
53 |
-
* File uploads added via {@link HTTP_Request2::addUpload()}
|
54 |
-
* @var array
|
55 |
-
*/
|
56 |
-
private $_uploads = array();
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Header for parts with parameters
|
60 |
-
* @var string
|
61 |
-
*/
|
62 |
-
private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";
|
63 |
-
|
64 |
-
/**
|
65 |
-
* Header for parts with uploads
|
66 |
-
* @var string
|
67 |
-
*/
|
68 |
-
private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Current position in parameter and upload arrays
|
72 |
-
*
|
73 |
-
* First number is index of "current" part, second number is position within
|
74 |
-
* "current" part
|
75 |
-
*
|
76 |
-
* @var array
|
77 |
-
*/
|
78 |
-
private $_pos = array(0, 0);
|
79 |
-
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Constructor. Sets the arrays with POST data.
|
83 |
-
*
|
84 |
-
* @param array $params values of form fields set via
|
85 |
-
* {@link HTTP_Request2::addPostParameter()}
|
86 |
-
* @param array $uploads file uploads set via
|
87 |
-
* {@link HTTP_Request2::addUpload()}
|
88 |
-
* @param bool $useBrackets whether to append brackets to array variable names
|
89 |
-
*/
|
90 |
-
public function __construct(array $params, array $uploads, $useBrackets = true)
|
91 |
-
{
|
92 |
-
$this->_params = self::_flattenArray('', $params, $useBrackets);
|
93 |
-
foreach ($uploads as $fieldName => $f) {
|
94 |
-
if (!is_array($f['fp'])) {
|
95 |
-
$this->_uploads[] = $f + array('name' => $fieldName);
|
96 |
-
} else {
|
97 |
-
for ($i = 0; $i < count($f['fp']); $i++) {
|
98 |
-
$upload = array(
|
99 |
-
'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName)
|
100 |
-
);
|
101 |
-
foreach (array('fp', 'filename', 'size', 'type') as $key) {
|
102 |
-
$upload[$key] = $f[$key][$i];
|
103 |
-
}
|
104 |
-
$this->_uploads[] = $upload;
|
105 |
-
}
|
106 |
-
}
|
107 |
-
}
|
108 |
-
}
|
109 |
-
|
110 |
-
/**
|
111 |
-
* Returns the length of the body to use in Content-Length header
|
112 |
-
*
|
113 |
-
* @return integer
|
114 |
-
*/
|
115 |
-
public function getLength()
|
116 |
-
{
|
117 |
-
$boundaryLength = strlen($this->getBoundary());
|
118 |
-
$headerParamLength = strlen($this->_headerParam) - 4 + $boundaryLength;
|
119 |
-
$headerUploadLength = strlen($this->_headerUpload) - 8 + $boundaryLength;
|
120 |
-
$length = $boundaryLength + 6;
|
121 |
-
foreach ($this->_params as $p) {
|
122 |
-
$length += $headerParamLength + strlen($p[0]) + strlen($p[1]) + 2;
|
123 |
-
}
|
124 |
-
foreach ($this->_uploads as $u) {
|
125 |
-
$length += $headerUploadLength + strlen($u['name']) + strlen($u['type']) +
|
126 |
-
strlen($u['filename']) + $u['size'] + 2;
|
127 |
-
}
|
128 |
-
return $length;
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Returns the boundary to use in Content-Type header
|
133 |
-
*
|
134 |
-
* @return string
|
135 |
-
*/
|
136 |
-
public function getBoundary()
|
137 |
-
{
|
138 |
-
if (empty($this->_boundary)) {
|
139 |
-
$this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime());
|
140 |
-
}
|
141 |
-
return $this->_boundary;
|
142 |
-
}
|
143 |
-
|
144 |
-
/**
|
145 |
-
* Returns next chunk of request body
|
146 |
-
*
|
147 |
-
* @param integer $length Number of bytes to read
|
148 |
-
*
|
149 |
-
* @return string Up to $length bytes of data, empty string if at end
|
150 |
-
* @throws HTTP_Request2_LogicException
|
151 |
-
*/
|
152 |
-
public function read($length)
|
153 |
-
{
|
154 |
-
$ret = '';
|
155 |
-
$boundary = $this->getBoundary();
|
156 |
-
$paramCount = count($this->_params);
|
157 |
-
$uploadCount = count($this->_uploads);
|
158 |
-
while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {
|
159 |
-
$oldLength = $length;
|
160 |
-
if ($this->_pos[0] < $paramCount) {
|
161 |
-
$param = sprintf(
|
162 |
-
$this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]
|
163 |
-
) . $this->_params[$this->_pos[0]][1] . "\r\n";
|
164 |
-
$ret .= substr($param, $this->_pos[1], $length);
|
165 |
-
$length -= min(strlen($param) - $this->_pos[1], $length);
|
166 |
-
|
167 |
-
} elseif ($this->_pos[0] < $paramCount + $uploadCount) {
|
168 |
-
$pos = $this->_pos[0] - $paramCount;
|
169 |
-
$header = sprintf(
|
170 |
-
$this->_headerUpload, $boundary, $this->_uploads[$pos]['name'],
|
171 |
-
$this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type']
|
172 |
-
);
|
173 |
-
if ($this->_pos[1] < strlen($header)) {
|
174 |
-
$ret .= substr($header, $this->_pos[1], $length);
|
175 |
-
$length -= min(strlen($header) - $this->_pos[1], $length);
|
176 |
-
}
|
177 |
-
$filePos = max(0, $this->_pos[1] - strlen($header));
|
178 |
-
if ($filePos < $this->_uploads[$pos]['size']) {
|
179 |
-
while ($length > 0 && !feof($this->_uploads[$pos]['fp'])) {
|
180 |
-
if (false === ($chunk = fread($this->_uploads[$pos]['fp'], $length))) {
|
181 |
-
throw new HTTP_Request2_LogicException(
|
182 |
-
'Failed reading file upload', HTTP_Request2_Exception::READ_ERROR
|
183 |
-
);
|
184 |
-
}
|
185 |
-
$ret .= $chunk;
|
186 |
-
$length -= strlen($chunk);
|
187 |
-
}
|
188 |
-
}
|
189 |
-
if ($length > 0) {
|
190 |
-
$start = $this->_pos[1] + ($oldLength - $length) -
|
191 |
-
strlen($header) - $this->_uploads[$pos]['size'];
|
192 |
-
$ret .= substr("\r\n", $start, $length);
|
193 |
-
$length -= min(2 - $start, $length);
|
194 |
-
}
|
195 |
-
|
196 |
-
} else {
|
197 |
-
$closing = '--' . $boundary . "--\r\n";
|
198 |
-
$ret .= substr($closing, $this->_pos[1], $length);
|
199 |
-
$length -= min(strlen($closing) - $this->_pos[1], $length);
|
200 |
-
}
|
201 |
-
if ($length > 0) {
|
202 |
-
$this->_pos = array($this->_pos[0] + 1, 0);
|
203 |
-
} else {
|
204 |
-
$this->_pos[1] += $oldLength;
|
205 |
-
}
|
206 |
-
}
|
207 |
-
return $ret;
|
208 |
-
}
|
209 |
-
|
210 |
-
/**
|
211 |
-
* Sets the current position to the start of the body
|
212 |
-
*
|
213 |
-
* This allows reusing the same body in another request
|
214 |
-
*/
|
215 |
-
public function rewind()
|
216 |
-
{
|
217 |
-
$this->_pos = array(0, 0);
|
218 |
-
foreach ($this->_uploads as $u) {
|
219 |
-
rewind($u['fp']);
|
220 |
-
}
|
221 |
-
}
|
222 |
-
|
223 |
-
/**
|
224 |
-
* Returns the body as string
|
225 |
-
*
|
226 |
-
* Note that it reads all file uploads into memory so it is a good idea not
|
227 |
-
* to use this method with large file uploads and rely on read() instead.
|
228 |
-
*
|
229 |
-
* @return string
|
230 |
-
*/
|
231 |
-
public function __toString()
|
232 |
-
{
|
233 |
-
$this->rewind();
|
234 |
-
return $this->read($this->getLength());
|
235 |
-
}
|
236 |
-
|
237 |
-
|
238 |
-
/**
|
239 |
-
* Helper function to change the (probably multidimensional) associative array
|
240 |
-
* into the simple one.
|
241 |
-
*
|
242 |
-
* @param string $name name for item
|
243 |
-
* @param mixed $values item's values
|
244 |
-
* @param bool $useBrackets whether to append [] to array variables' names
|
245 |
-
*
|
246 |
-
* @return array array with the following items: array('item name', 'item value');
|
247 |
-
*/
|
248 |
-
private static function _flattenArray($name, $values, $useBrackets)
|
249 |
-
{
|
250 |
-
if (!is_array($values)) {
|
251 |
-
return array(array($name, $values));
|
252 |
-
} else {
|
253 |
-
$ret = array();
|
254 |
-
foreach ($values as $k => $v) {
|
255 |
-
if (empty($name)) {
|
256 |
-
$newName = $k;
|
257 |
-
} elseif ($useBrackets) {
|
258 |
-
$newName = $name . '[' . $k . ']';
|
259 |
-
} else {
|
260 |
-
$newName = $name;
|
261 |
-
}
|
262 |
-
$ret = array_merge($ret, self::_flattenArray($newName, $v, $useBrackets));
|
263 |
-
}
|
264 |
-
return $ret;
|
265 |
-
}
|
266 |
-
}
|
267 |
-
}
|
268 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Helper class for building multipart/form-data request body
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/** Exception class for HTTP_Request2 package */
|
22 |
+
require_once 'HTTP/Request2/Exception.php';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Class for building multipart/form-data request body
|
26 |
+
*
|
27 |
+
* The class helps to reduce memory consumption by streaming large file uploads
|
28 |
+
* from disk, it also allows monitoring of upload progress (see request #7630)
|
29 |
+
*
|
30 |
+
* @category HTTP
|
31 |
+
* @package HTTP_Request2
|
32 |
+
* @author Alexey Borzov <avb@php.net>
|
33 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
34 |
+
* @version Release: 2.2.1
|
35 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
36 |
+
* @link http://tools.ietf.org/html/rfc1867
|
37 |
+
*/
|
38 |
+
class HTTP_Request2_MultipartBody
|
39 |
+
{
|
40 |
+
/**
|
41 |
+
* MIME boundary
|
42 |
+
* @var string
|
43 |
+
*/
|
44 |
+
private $_boundary;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Form parameters added via {@link HTTP_Request2::addPostParameter()}
|
48 |
+
* @var array
|
49 |
+
*/
|
50 |
+
private $_params = array();
|
51 |
+
|
52 |
+
/**
|
53 |
+
* File uploads added via {@link HTTP_Request2::addUpload()}
|
54 |
+
* @var array
|
55 |
+
*/
|
56 |
+
private $_uploads = array();
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Header for parts with parameters
|
60 |
+
* @var string
|
61 |
+
*/
|
62 |
+
private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Header for parts with uploads
|
66 |
+
* @var string
|
67 |
+
*/
|
68 |
+
private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Current position in parameter and upload arrays
|
72 |
+
*
|
73 |
+
* First number is index of "current" part, second number is position within
|
74 |
+
* "current" part
|
75 |
+
*
|
76 |
+
* @var array
|
77 |
+
*/
|
78 |
+
private $_pos = array(0, 0);
|
79 |
+
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Constructor. Sets the arrays with POST data.
|
83 |
+
*
|
84 |
+
* @param array $params values of form fields set via
|
85 |
+
* {@link HTTP_Request2::addPostParameter()}
|
86 |
+
* @param array $uploads file uploads set via
|
87 |
+
* {@link HTTP_Request2::addUpload()}
|
88 |
+
* @param bool $useBrackets whether to append brackets to array variable names
|
89 |
+
*/
|
90 |
+
public function __construct(array $params, array $uploads, $useBrackets = true)
|
91 |
+
{
|
92 |
+
$this->_params = self::_flattenArray('', $params, $useBrackets);
|
93 |
+
foreach ($uploads as $fieldName => $f) {
|
94 |
+
if (!is_array($f['fp'])) {
|
95 |
+
$this->_uploads[] = $f + array('name' => $fieldName);
|
96 |
+
} else {
|
97 |
+
for ($i = 0; $i < count($f['fp']); $i++) {
|
98 |
+
$upload = array(
|
99 |
+
'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName)
|
100 |
+
);
|
101 |
+
foreach (array('fp', 'filename', 'size', 'type') as $key) {
|
102 |
+
$upload[$key] = $f[$key][$i];
|
103 |
+
}
|
104 |
+
$this->_uploads[] = $upload;
|
105 |
+
}
|
106 |
+
}
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Returns the length of the body to use in Content-Length header
|
112 |
+
*
|
113 |
+
* @return integer
|
114 |
+
*/
|
115 |
+
public function getLength()
|
116 |
+
{
|
117 |
+
$boundaryLength = strlen($this->getBoundary());
|
118 |
+
$headerParamLength = strlen($this->_headerParam) - 4 + $boundaryLength;
|
119 |
+
$headerUploadLength = strlen($this->_headerUpload) - 8 + $boundaryLength;
|
120 |
+
$length = $boundaryLength + 6;
|
121 |
+
foreach ($this->_params as $p) {
|
122 |
+
$length += $headerParamLength + strlen($p[0]) + strlen($p[1]) + 2;
|
123 |
+
}
|
124 |
+
foreach ($this->_uploads as $u) {
|
125 |
+
$length += $headerUploadLength + strlen($u['name']) + strlen($u['type']) +
|
126 |
+
strlen($u['filename']) + $u['size'] + 2;
|
127 |
+
}
|
128 |
+
return $length;
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Returns the boundary to use in Content-Type header
|
133 |
+
*
|
134 |
+
* @return string
|
135 |
+
*/
|
136 |
+
public function getBoundary()
|
137 |
+
{
|
138 |
+
if (empty($this->_boundary)) {
|
139 |
+
$this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime());
|
140 |
+
}
|
141 |
+
return $this->_boundary;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Returns next chunk of request body
|
146 |
+
*
|
147 |
+
* @param integer $length Number of bytes to read
|
148 |
+
*
|
149 |
+
* @return string Up to $length bytes of data, empty string if at end
|
150 |
+
* @throws HTTP_Request2_LogicException
|
151 |
+
*/
|
152 |
+
public function read($length)
|
153 |
+
{
|
154 |
+
$ret = '';
|
155 |
+
$boundary = $this->getBoundary();
|
156 |
+
$paramCount = count($this->_params);
|
157 |
+
$uploadCount = count($this->_uploads);
|
158 |
+
while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {
|
159 |
+
$oldLength = $length;
|
160 |
+
if ($this->_pos[0] < $paramCount) {
|
161 |
+
$param = sprintf(
|
162 |
+
$this->_headerParam, $boundary, $this->_params[$this->_pos[0]][0]
|
163 |
+
) . $this->_params[$this->_pos[0]][1] . "\r\n";
|
164 |
+
$ret .= substr($param, $this->_pos[1], $length);
|
165 |
+
$length -= min(strlen($param) - $this->_pos[1], $length);
|
166 |
+
|
167 |
+
} elseif ($this->_pos[0] < $paramCount + $uploadCount) {
|
168 |
+
$pos = $this->_pos[0] - $paramCount;
|
169 |
+
$header = sprintf(
|
170 |
+
$this->_headerUpload, $boundary, $this->_uploads[$pos]['name'],
|
171 |
+
$this->_uploads[$pos]['filename'], $this->_uploads[$pos]['type']
|
172 |
+
);
|
173 |
+
if ($this->_pos[1] < strlen($header)) {
|
174 |
+
$ret .= substr($header, $this->_pos[1], $length);
|
175 |
+
$length -= min(strlen($header) - $this->_pos[1], $length);
|
176 |
+
}
|
177 |
+
$filePos = max(0, $this->_pos[1] - strlen($header));
|
178 |
+
if ($filePos < $this->_uploads[$pos]['size']) {
|
179 |
+
while ($length > 0 && !feof($this->_uploads[$pos]['fp'])) {
|
180 |
+
if (false === ($chunk = fread($this->_uploads[$pos]['fp'], $length))) {
|
181 |
+
throw new HTTP_Request2_LogicException(
|
182 |
+
'Failed reading file upload', HTTP_Request2_Exception::READ_ERROR
|
183 |
+
);
|
184 |
+
}
|
185 |
+
$ret .= $chunk;
|
186 |
+
$length -= strlen($chunk);
|
187 |
+
}
|
188 |
+
}
|
189 |
+
if ($length > 0) {
|
190 |
+
$start = $this->_pos[1] + ($oldLength - $length) -
|
191 |
+
strlen($header) - $this->_uploads[$pos]['size'];
|
192 |
+
$ret .= substr("\r\n", $start, $length);
|
193 |
+
$length -= min(2 - $start, $length);
|
194 |
+
}
|
195 |
+
|
196 |
+
} else {
|
197 |
+
$closing = '--' . $boundary . "--\r\n";
|
198 |
+
$ret .= substr($closing, $this->_pos[1], $length);
|
199 |
+
$length -= min(strlen($closing) - $this->_pos[1], $length);
|
200 |
+
}
|
201 |
+
if ($length > 0) {
|
202 |
+
$this->_pos = array($this->_pos[0] + 1, 0);
|
203 |
+
} else {
|
204 |
+
$this->_pos[1] += $oldLength;
|
205 |
+
}
|
206 |
+
}
|
207 |
+
return $ret;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Sets the current position to the start of the body
|
212 |
+
*
|
213 |
+
* This allows reusing the same body in another request
|
214 |
+
*/
|
215 |
+
public function rewind()
|
216 |
+
{
|
217 |
+
$this->_pos = array(0, 0);
|
218 |
+
foreach ($this->_uploads as $u) {
|
219 |
+
rewind($u['fp']);
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Returns the body as string
|
225 |
+
*
|
226 |
+
* Note that it reads all file uploads into memory so it is a good idea not
|
227 |
+
* to use this method with large file uploads and rely on read() instead.
|
228 |
+
*
|
229 |
+
* @return string
|
230 |
+
*/
|
231 |
+
public function __toString()
|
232 |
+
{
|
233 |
+
$this->rewind();
|
234 |
+
return $this->read($this->getLength());
|
235 |
+
}
|
236 |
+
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Helper function to change the (probably multidimensional) associative array
|
240 |
+
* into the simple one.
|
241 |
+
*
|
242 |
+
* @param string $name name for item
|
243 |
+
* @param mixed $values item's values
|
244 |
+
* @param bool $useBrackets whether to append [] to array variables' names
|
245 |
+
*
|
246 |
+
* @return array array with the following items: array('item name', 'item value');
|
247 |
+
*/
|
248 |
+
private static function _flattenArray($name, $values, $useBrackets)
|
249 |
+
{
|
250 |
+
if (!is_array($values)) {
|
251 |
+
return array(array($name, $values));
|
252 |
+
} else {
|
253 |
+
$ret = array();
|
254 |
+
foreach ($values as $k => $v) {
|
255 |
+
if (empty($name)) {
|
256 |
+
$newName = $k;
|
257 |
+
} elseif ($useBrackets) {
|
258 |
+
$newName = $name . '[' . $k . ']';
|
259 |
+
} else {
|
260 |
+
$newName = $name;
|
261 |
+
}
|
262 |
+
$ret = array_merge($ret, self::_flattenArray($newName, $v, $useBrackets));
|
263 |
+
}
|
264 |
+
return $ret;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
?>
|
vendor/PEAR/HTTP/Request2/Observer/Log.php
CHANGED
@@ -1,192 +1,192 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* An observer useful for debugging / testing.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author David Jean Louis <izi@php.net>
|
16 |
-
* @author Alexey Borzov <avb@php.net>
|
17 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
18 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
19 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
20 |
-
*/
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Exception class for HTTP_Request2 package
|
24 |
-
*/
|
25 |
-
require_once 'HTTP/Request2/Exception.php';
|
26 |
-
|
27 |
-
/**
|
28 |
-
* A debug observer useful for debugging / testing.
|
29 |
-
*
|
30 |
-
* This observer logs to a log target data corresponding to the various request
|
31 |
-
* and response events, it logs by default to php://output but can be configured
|
32 |
-
* to log to a file or via the PEAR Log package.
|
33 |
-
*
|
34 |
-
* A simple example:
|
35 |
-
* <code>
|
36 |
-
* require_once 'HTTP/Request2.php';
|
37 |
-
* require_once 'HTTP/Request2/Observer/Log.php';
|
38 |
-
*
|
39 |
-
* $request = new HTTP_Request2('http://www.example.com');
|
40 |
-
* $observer = new HTTP_Request2_Observer_Log();
|
41 |
-
* $request->attach($observer);
|
42 |
-
* $request->send();
|
43 |
-
* </code>
|
44 |
-
*
|
45 |
-
* A more complex example with PEAR Log:
|
46 |
-
* <code>
|
47 |
-
* require_once 'HTTP/Request2.php';
|
48 |
-
* require_once 'HTTP/Request2/Observer/Log.php';
|
49 |
-
* require_once 'Log.php';
|
50 |
-
*
|
51 |
-
* $request = new HTTP_Request2('http://www.example.com');
|
52 |
-
* // we want to log with PEAR log
|
53 |
-
* $observer = new HTTP_Request2_Observer_Log(Log::factory('console'));
|
54 |
-
*
|
55 |
-
* // we only want to log received headers
|
56 |
-
* $observer->events = array('receivedHeaders');
|
57 |
-
*
|
58 |
-
* $request->attach($observer);
|
59 |
-
* $request->send();
|
60 |
-
* </code>
|
61 |
-
*
|
62 |
-
* @category HTTP
|
63 |
-
* @package HTTP_Request2
|
64 |
-
* @author David Jean Louis <izi@php.net>
|
65 |
-
* @author Alexey Borzov <avb@php.net>
|
66 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
67 |
-
* @version Release: 2.2.1
|
68 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
69 |
-
*/
|
70 |
-
class HTTP_Request2_Observer_Log implements SplObserver
|
71 |
-
{
|
72 |
-
// properties {{{
|
73 |
-
|
74 |
-
/**
|
75 |
-
* The log target, it can be a a resource or a PEAR Log instance.
|
76 |
-
*
|
77 |
-
* @var resource|Log $target
|
78 |
-
*/
|
79 |
-
protected $target = null;
|
80 |
-
|
81 |
-
/**
|
82 |
-
* The events to log.
|
83 |
-
*
|
84 |
-
* @var array $events
|
85 |
-
*/
|
86 |
-
public $events = array(
|
87 |
-
'connect',
|
88 |
-
'sentHeaders',
|
89 |
-
'sentBody',
|
90 |
-
'receivedHeaders',
|
91 |
-
'receivedBody',
|
92 |
-
'disconnect',
|
93 |
-
);
|
94 |
-
|
95 |
-
// }}}
|
96 |
-
// __construct() {{{
|
97 |
-
|
98 |
-
/**
|
99 |
-
* Constructor.
|
100 |
-
*
|
101 |
-
* @param mixed $target Can be a file path (default: php://output), a resource,
|
102 |
-
* or an instance of the PEAR Log class.
|
103 |
-
* @param array $events Array of events to listen to (default: all events)
|
104 |
-
*
|
105 |
-
* @return void
|
106 |
-
*/
|
107 |
-
public function __construct($target = 'php://output', array $events = array())
|
108 |
-
{
|
109 |
-
if (!empty($events)) {
|
110 |
-
$this->events = $events;
|
111 |
-
}
|
112 |
-
if (is_resource($target) || $target instanceof Log) {
|
113 |
-
$this->target = $target;
|
114 |
-
} elseif (false === ($this->target = @fopen($target, 'ab'))) {
|
115 |
-
throw new HTTP_Request2_Exception("Unable to open '{$target}'");
|
116 |
-
}
|
117 |
-
}
|
118 |
-
|
119 |
-
// }}}
|
120 |
-
// update() {{{
|
121 |
-
|
122 |
-
/**
|
123 |
-
* Called when the request notifies us of an event.
|
124 |
-
*
|
125 |
-
* @param HTTP_Request2 $subject The HTTP_Request2 instance
|
126 |
-
*
|
127 |
-
* @return void
|
128 |
-
*/
|
129 |
-
public function update(SplSubject $subject)
|
130 |
-
{
|
131 |
-
$event = $subject->getLastEvent();
|
132 |
-
if (!in_array($event['name'], $this->events)) {
|
133 |
-
return;
|
134 |
-
}
|
135 |
-
|
136 |
-
switch ($event['name']) {
|
137 |
-
case 'connect':
|
138 |
-
$this->log('* Connected to ' . $event['data']);
|
139 |
-
break;
|
140 |
-
case 'sentHeaders':
|
141 |
-
$headers = explode("\r\n", $event['data']);
|
142 |
-
array_pop($headers);
|
143 |
-
foreach ($headers as $header) {
|
144 |
-
$this->log('> ' . $header);
|
145 |
-
}
|
146 |
-
break;
|
147 |
-
case 'sentBody':
|
148 |
-
$this->log('> ' . $event['data'] . ' byte(s) sent');
|
149 |
-
break;
|
150 |
-
case 'receivedHeaders':
|
151 |
-
$this->log(sprintf(
|
152 |
-
'< HTTP/%s %s %s', $event['data']->getVersion(),
|
153 |
-
$event['data']->getStatus(), $event['data']->getReasonPhrase()
|
154 |
-
));
|
155 |
-
$headers = $event['data']->getHeader();
|
156 |
-
foreach ($headers as $key => $val) {
|
157 |
-
$this->log('< ' . $key . ': ' . $val);
|
158 |
-
}
|
159 |
-
$this->log('< ');
|
160 |
-
break;
|
161 |
-
case 'receivedBody':
|
162 |
-
$this->log($event['data']->getBody());
|
163 |
-
break;
|
164 |
-
case 'disconnect':
|
165 |
-
$this->log('* Disconnected');
|
166 |
-
break;
|
167 |
-
}
|
168 |
-
}
|
169 |
-
|
170 |
-
// }}}
|
171 |
-
// log() {{{
|
172 |
-
|
173 |
-
/**
|
174 |
-
* Logs the given message to the configured target.
|
175 |
-
*
|
176 |
-
* @param string $message Message to display
|
177 |
-
*
|
178 |
-
* @return void
|
179 |
-
*/
|
180 |
-
protected function log($message)
|
181 |
-
{
|
182 |
-
if ($this->target instanceof Log) {
|
183 |
-
$this->target->debug($message);
|
184 |
-
} elseif (is_resource($this->target)) {
|
185 |
-
fwrite($this->target, $message . "\r\n");
|
186 |
-
}
|
187 |
-
}
|
188 |
-
|
189 |
-
// }}}
|
190 |
-
}
|
191 |
-
|
192 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* An observer useful for debugging / testing.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author David Jean Louis <izi@php.net>
|
16 |
+
* @author Alexey Borzov <avb@php.net>
|
17 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
18 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
19 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
20 |
+
*/
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Exception class for HTTP_Request2 package
|
24 |
+
*/
|
25 |
+
require_once 'HTTP/Request2/Exception.php';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* A debug observer useful for debugging / testing.
|
29 |
+
*
|
30 |
+
* This observer logs to a log target data corresponding to the various request
|
31 |
+
* and response events, it logs by default to php://output but can be configured
|
32 |
+
* to log to a file or via the PEAR Log package.
|
33 |
+
*
|
34 |
+
* A simple example:
|
35 |
+
* <code>
|
36 |
+
* require_once 'HTTP/Request2.php';
|
37 |
+
* require_once 'HTTP/Request2/Observer/Log.php';
|
38 |
+
*
|
39 |
+
* $request = new HTTP_Request2('http://www.example.com');
|
40 |
+
* $observer = new HTTP_Request2_Observer_Log();
|
41 |
+
* $request->attach($observer);
|
42 |
+
* $request->send();
|
43 |
+
* </code>
|
44 |
+
*
|
45 |
+
* A more complex example with PEAR Log:
|
46 |
+
* <code>
|
47 |
+
* require_once 'HTTP/Request2.php';
|
48 |
+
* require_once 'HTTP/Request2/Observer/Log.php';
|
49 |
+
* require_once 'Log.php';
|
50 |
+
*
|
51 |
+
* $request = new HTTP_Request2('http://www.example.com');
|
52 |
+
* // we want to log with PEAR log
|
53 |
+
* $observer = new HTTP_Request2_Observer_Log(Log::factory('console'));
|
54 |
+
*
|
55 |
+
* // we only want to log received headers
|
56 |
+
* $observer->events = array('receivedHeaders');
|
57 |
+
*
|
58 |
+
* $request->attach($observer);
|
59 |
+
* $request->send();
|
60 |
+
* </code>
|
61 |
+
*
|
62 |
+
* @category HTTP
|
63 |
+
* @package HTTP_Request2
|
64 |
+
* @author David Jean Louis <izi@php.net>
|
65 |
+
* @author Alexey Borzov <avb@php.net>
|
66 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
67 |
+
* @version Release: 2.2.1
|
68 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
69 |
+
*/
|
70 |
+
class HTTP_Request2_Observer_Log implements SplObserver
|
71 |
+
{
|
72 |
+
// properties {{{
|
73 |
+
|
74 |
+
/**
|
75 |
+
* The log target, it can be a a resource or a PEAR Log instance.
|
76 |
+
*
|
77 |
+
* @var resource|Log $target
|
78 |
+
*/
|
79 |
+
protected $target = null;
|
80 |
+
|
81 |
+
/**
|
82 |
+
* The events to log.
|
83 |
+
*
|
84 |
+
* @var array $events
|
85 |
+
*/
|
86 |
+
public $events = array(
|
87 |
+
'connect',
|
88 |
+
'sentHeaders',
|
89 |
+
'sentBody',
|
90 |
+
'receivedHeaders',
|
91 |
+
'receivedBody',
|
92 |
+
'disconnect',
|
93 |
+
);
|
94 |
+
|
95 |
+
// }}}
|
96 |
+
// __construct() {{{
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Constructor.
|
100 |
+
*
|
101 |
+
* @param mixed $target Can be a file path (default: php://output), a resource,
|
102 |
+
* or an instance of the PEAR Log class.
|
103 |
+
* @param array $events Array of events to listen to (default: all events)
|
104 |
+
*
|
105 |
+
* @return void
|
106 |
+
*/
|
107 |
+
public function __construct($target = 'php://output', array $events = array())
|
108 |
+
{
|
109 |
+
if (!empty($events)) {
|
110 |
+
$this->events = $events;
|
111 |
+
}
|
112 |
+
if (is_resource($target) || $target instanceof Log) {
|
113 |
+
$this->target = $target;
|
114 |
+
} elseif (false === ($this->target = @fopen($target, 'ab'))) {
|
115 |
+
throw new HTTP_Request2_Exception("Unable to open '{$target}'");
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
// }}}
|
120 |
+
// update() {{{
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Called when the request notifies us of an event.
|
124 |
+
*
|
125 |
+
* @param HTTP_Request2 $subject The HTTP_Request2 instance
|
126 |
+
*
|
127 |
+
* @return void
|
128 |
+
*/
|
129 |
+
public function update(SplSubject $subject)
|
130 |
+
{
|
131 |
+
$event = $subject->getLastEvent();
|
132 |
+
if (!in_array($event['name'], $this->events)) {
|
133 |
+
return;
|
134 |
+
}
|
135 |
+
|
136 |
+
switch ($event['name']) {
|
137 |
+
case 'connect':
|
138 |
+
$this->log('* Connected to ' . $event['data']);
|
139 |
+
break;
|
140 |
+
case 'sentHeaders':
|
141 |
+
$headers = explode("\r\n", $event['data']);
|
142 |
+
array_pop($headers);
|
143 |
+
foreach ($headers as $header) {
|
144 |
+
$this->log('> ' . $header);
|
145 |
+
}
|
146 |
+
break;
|
147 |
+
case 'sentBody':
|
148 |
+
$this->log('> ' . $event['data'] . ' byte(s) sent');
|
149 |
+
break;
|
150 |
+
case 'receivedHeaders':
|
151 |
+
$this->log(sprintf(
|
152 |
+
'< HTTP/%s %s %s', $event['data']->getVersion(),
|
153 |
+
$event['data']->getStatus(), $event['data']->getReasonPhrase()
|
154 |
+
));
|
155 |
+
$headers = $event['data']->getHeader();
|
156 |
+
foreach ($headers as $key => $val) {
|
157 |
+
$this->log('< ' . $key . ': ' . $val);
|
158 |
+
}
|
159 |
+
$this->log('< ');
|
160 |
+
break;
|
161 |
+
case 'receivedBody':
|
162 |
+
$this->log($event['data']->getBody());
|
163 |
+
break;
|
164 |
+
case 'disconnect':
|
165 |
+
$this->log('* Disconnected');
|
166 |
+
break;
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
// }}}
|
171 |
+
// log() {{{
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Logs the given message to the configured target.
|
175 |
+
*
|
176 |
+
* @param string $message Message to display
|
177 |
+
*
|
178 |
+
* @return void
|
179 |
+
*/
|
180 |
+
protected function log($message)
|
181 |
+
{
|
182 |
+
if ($this->target instanceof Log) {
|
183 |
+
$this->target->debug($message);
|
184 |
+
} elseif (is_resource($this->target)) {
|
185 |
+
fwrite($this->target, $message . "\r\n");
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
// }}}
|
190 |
+
}
|
191 |
+
|
192 |
?>
|
vendor/PEAR/HTTP/Request2/Response.php
CHANGED
@@ -1,631 +1,631 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class representing a HTTP response
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Exception class for HTTP_Request2 package
|
23 |
-
*/
|
24 |
-
require_once 'HTTP/Request2/Exception.php';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Class representing a HTTP response
|
28 |
-
*
|
29 |
-
* The class is designed to be used in "streaming" scenario, building the
|
30 |
-
* response as it is being received:
|
31 |
-
* <code>
|
32 |
-
* $statusLine = read_status_line();
|
33 |
-
* $response = new HTTP_Request2_Response($statusLine);
|
34 |
-
* do {
|
35 |
-
* $headerLine = read_header_line();
|
36 |
-
* $response->parseHeaderLine($headerLine);
|
37 |
-
* } while ($headerLine != '');
|
38 |
-
*
|
39 |
-
* while ($chunk = read_body()) {
|
40 |
-
* $response->appendBody($chunk);
|
41 |
-
* }
|
42 |
-
*
|
43 |
-
* var_dump($response->getHeader(), $response->getCookies(), $response->getBody());
|
44 |
-
* </code>
|
45 |
-
*
|
46 |
-
* @category HTTP
|
47 |
-
* @package HTTP_Request2
|
48 |
-
* @author Alexey Borzov <avb@php.net>
|
49 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
50 |
-
* @version Release: 2.2.1
|
51 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
52 |
-
* @link http://tools.ietf.org/html/rfc2616#section-6
|
53 |
-
*/
|
54 |
-
class HTTP_Request2_Response
|
55 |
-
{
|
56 |
-
/**
|
57 |
-
* HTTP protocol version (e.g. 1.0, 1.1)
|
58 |
-
* @var string
|
59 |
-
*/
|
60 |
-
protected $version;
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Status code
|
64 |
-
* @var integer
|
65 |
-
* @link http://tools.ietf.org/html/rfc2616#section-6.1.1
|
66 |
-
*/
|
67 |
-
protected $code;
|
68 |
-
|
69 |
-
/**
|
70 |
-
* Reason phrase
|
71 |
-
* @var string
|
72 |
-
* @link http://tools.ietf.org/html/rfc2616#section-6.1.1
|
73 |
-
*/
|
74 |
-
protected $reasonPhrase;
|
75 |
-
|
76 |
-
/**
|
77 |
-
* Effective URL (may be different from original request URL in case of redirects)
|
78 |
-
* @var string
|
79 |
-
*/
|
80 |
-
protected $effectiveUrl;
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Associative array of response headers
|
84 |
-
* @var array
|
85 |
-
*/
|
86 |
-
protected $headers = array();
|
87 |
-
|
88 |
-
/**
|
89 |
-
* Cookies set in the response
|
90 |
-
* @var array
|
91 |
-
*/
|
92 |
-
protected $cookies = array();
|
93 |
-
|
94 |
-
/**
|
95 |
-
* Name of last header processed by parseHederLine()
|
96 |
-
*
|
97 |
-
* Used to handle the headers that span multiple lines
|
98 |
-
*
|
99 |
-
* @var string
|
100 |
-
*/
|
101 |
-
protected $lastHeader = null;
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Response body
|
105 |
-
* @var string
|
106 |
-
*/
|
107 |
-
protected $body = '';
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Whether the body is still encoded by Content-Encoding
|
111 |
-
*
|
112 |
-
* cURL provides the decoded body to the callback; if we are reading from
|
113 |
-
* socket the body is still gzipped / deflated
|
114 |
-
*
|
115 |
-
* @var bool
|
116 |
-
*/
|
117 |
-
protected $bodyEncoded;
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Associative array of HTTP status code / reason phrase.
|
121 |
-
*
|
122 |
-
* @var array
|
123 |
-
* @link http://tools.ietf.org/html/rfc2616#section-10
|
124 |
-
*/
|
125 |
-
protected static $phrases = array(
|
126 |
-
|
127 |
-
// 1xx: Informational - Request received, continuing process
|
128 |
-
100 => 'Continue',
|
129 |
-
101 => 'Switching Protocols',
|
130 |
-
|
131 |
-
// 2xx: Success - The action was successfully received, understood and
|
132 |
-
// accepted
|
133 |
-
200 => 'OK',
|
134 |
-
201 => 'Created',
|
135 |
-
202 => 'Accepted',
|
136 |
-
203 => 'Non-Authoritative Information',
|
137 |
-
204 => 'No Content',
|
138 |
-
205 => 'Reset Content',
|
139 |
-
206 => 'Partial Content',
|
140 |
-
|
141 |
-
// 3xx: Redirection - Further action must be taken in order to complete
|
142 |
-
// the request
|
143 |
-
300 => 'Multiple Choices',
|
144 |
-
301 => 'Moved Permanently',
|
145 |
-
302 => 'Found', // 1.1
|
146 |
-
303 => 'See Other',
|
147 |
-
304 => 'Not Modified',
|
148 |
-
305 => 'Use Proxy',
|
149 |
-
307 => 'Temporary Redirect',
|
150 |
-
|
151 |
-
// 4xx: Client Error - The request contains bad syntax or cannot be
|
152 |
-
// fulfilled
|
153 |
-
400 => 'Bad Request',
|
154 |
-
401 => 'Unauthorized',
|
155 |
-
402 => 'Payment Required',
|
156 |
-
403 => 'Forbidden',
|
157 |
-
404 => 'Not Found',
|
158 |
-
405 => 'Method Not Allowed',
|
159 |
-
406 => 'Not Acceptable',
|
160 |
-
407 => 'Proxy Authentication Required',
|
161 |
-
408 => 'Request Timeout',
|
162 |
-
409 => 'Conflict',
|
163 |
-
410 => 'Gone',
|
164 |
-
411 => 'Length Required',
|
165 |
-
412 => 'Precondition Failed',
|
166 |
-
413 => 'Request Entity Too Large',
|
167 |
-
414 => 'Request-URI Too Long',
|
168 |
-
415 => 'Unsupported Media Type',
|
169 |
-
416 => 'Requested Range Not Satisfiable',
|
170 |
-
417 => 'Expectation Failed',
|
171 |
-
|
172 |
-
// 5xx: Server Error - The server failed to fulfill an apparently
|
173 |
-
// valid request
|
174 |
-
500 => 'Internal Server Error',
|
175 |
-
501 => 'Not Implemented',
|
176 |
-
502 => 'Bad Gateway',
|
177 |
-
503 => 'Service Unavailable',
|
178 |
-
504 => 'Gateway Timeout',
|
179 |
-
505 => 'HTTP Version Not Supported',
|
180 |
-
509 => 'Bandwidth Limit Exceeded',
|
181 |
-
|
182 |
-
);
|
183 |
-
|
184 |
-
/**
|
185 |
-
* Returns the default reason phrase for the given code or all reason phrases
|
186 |
-
*
|
187 |
-
* @param int $code Response code
|
188 |
-
*
|
189 |
-
* @return string|array|null Default reason phrase for $code if $code is given
|
190 |
-
* (null if no phrase is available), array of all
|
191 |
-
* reason phrases if $code is null
|
192 |
-
* @link http://pear.php.net/bugs/18716
|
193 |
-
*/
|
194 |
-
public static function getDefaultReasonPhrase($code = null)
|
195 |
-
{
|
196 |
-
if (null === $code) {
|
197 |
-
return self::$phrases;
|
198 |
-
} else {
|
199 |
-
return isset(self::$phrases[$code]) ? self::$phrases[$code] : null;
|
200 |
-
}
|
201 |
-
}
|
202 |
-
|
203 |
-
/**
|
204 |
-
* Constructor, parses the response status line
|
205 |
-
*
|
206 |
-
* @param string $statusLine Response status line (e.g. "HTTP/1.1 200 OK")
|
207 |
-
* @param bool $bodyEncoded Whether body is still encoded by Content-Encoding
|
208 |
-
* @param string $effectiveUrl Effective URL of the response
|
209 |
-
*
|
210 |
-
* @throws HTTP_Request2_MessageException if status line is invalid according to spec
|
211 |
-
*/
|
212 |
-
public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)
|
213 |
-
{
|
214 |
-
if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {
|
215 |
-
throw new HTTP_Request2_MessageException(
|
216 |
-
"Malformed response: {$statusLine}",
|
217 |
-
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
218 |
-
);
|
219 |
-
}
|
220 |
-
$this->version = $m[1];
|
221 |
-
$this->code = intval($m[2]);
|
222 |
-
$this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);
|
223 |
-
$this->bodyEncoded = (bool)$bodyEncoded;
|
224 |
-
$this->effectiveUrl = (string)$effectiveUrl;
|
225 |
-
}
|
226 |
-
|
227 |
-
/**
|
228 |
-
* Parses the line from HTTP response filling $headers array
|
229 |
-
*
|
230 |
-
* The method should be called after reading the line from socket or receiving
|
231 |
-
* it into cURL callback. Passing an empty string here indicates the end of
|
232 |
-
* response headers and triggers additional processing, so be sure to pass an
|
233 |
-
* empty string in the end.
|
234 |
-
*
|
235 |
-
* @param string $headerLine Line from HTTP response
|
236 |
-
*/
|
237 |
-
public function parseHeaderLine($headerLine)
|
238 |
-
{
|
239 |
-
$headerLine = trim($headerLine, "\r\n");
|
240 |
-
|
241 |
-
if ('' == $headerLine) {
|
242 |
-
// empty string signals the end of headers, process the received ones
|
243 |
-
if (!empty($this->headers['set-cookie'])) {
|
244 |
-
$cookies = is_array($this->headers['set-cookie'])?
|
245 |
-
$this->headers['set-cookie']:
|
246 |
-
array($this->headers['set-cookie']);
|
247 |
-
foreach ($cookies as $cookieString) {
|
248 |
-
$this->parseCookie($cookieString);
|
249 |
-
}
|
250 |
-
unset($this->headers['set-cookie']);
|
251 |
-
}
|
252 |
-
foreach (array_keys($this->headers) as $k) {
|
253 |
-
if (is_array($this->headers[$k])) {
|
254 |
-
$this->headers[$k] = implode(', ', $this->headers[$k]);
|
255 |
-
}
|
256 |
-
}
|
257 |
-
|
258 |
-
} elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {
|
259 |
-
// string of the form header-name: header value
|
260 |
-
$name = strtolower($m[1]);
|
261 |
-
$value = trim($m[2]);
|
262 |
-
if (empty($this->headers[$name])) {
|
263 |
-
$this->headers[$name] = $value;
|
264 |
-
} else {
|
265 |
-
if (!is_array($this->headers[$name])) {
|
266 |
-
$this->headers[$name] = array($this->headers[$name]);
|
267 |
-
}
|
268 |
-
$this->headers[$name][] = $value;
|
269 |
-
}
|
270 |
-
$this->lastHeader = $name;
|
271 |
-
|
272 |
-
} elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
|
273 |
-
// continuation of a previous header
|
274 |
-
if (!is_array($this->headers[$this->lastHeader])) {
|
275 |
-
$this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
|
276 |
-
} else {
|
277 |
-
$key = count($this->headers[$this->lastHeader]) - 1;
|
278 |
-
$this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);
|
279 |
-
}
|
280 |
-
}
|
281 |
-
}
|
282 |
-
|
283 |
-
/**
|
284 |
-
* Parses a Set-Cookie header to fill $cookies array
|
285 |
-
*
|
286 |
-
* @param string $cookieString value of Set-Cookie header
|
287 |
-
*
|
288 |
-
* @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
|
289 |
-
*/
|
290 |
-
protected function parseCookie($cookieString)
|
291 |
-
{
|
292 |
-
$cookie = array(
|
293 |
-
'expires' => null,
|
294 |
-
'domain' => null,
|
295 |
-
'path' => null,
|
296 |
-
'secure' => false
|
297 |
-
);
|
298 |
-
|
299 |
-
if (!strpos($cookieString, ';')) {
|
300 |
-
// Only a name=value pair
|
301 |
-
$pos = strpos($cookieString, '=');
|
302 |
-
$cookie['name'] = trim(substr($cookieString, 0, $pos));
|
303 |
-
$cookie['value'] = trim(substr($cookieString, $pos + 1));
|
304 |
-
|
305 |
-
} else {
|
306 |
-
// Some optional parameters are supplied
|
307 |
-
$elements = explode(';', $cookieString);
|
308 |
-
$pos = strpos($elements[0], '=');
|
309 |
-
$cookie['name'] = trim(substr($elements[0], 0, $pos));
|
310 |
-
$cookie['value'] = trim(substr($elements[0], $pos + 1));
|
311 |
-
|
312 |
-
for ($i = 1; $i < count($elements); $i++) {
|
313 |
-
if (false === strpos($elements[$i], '=')) {
|
314 |
-
$elName = trim($elements[$i]);
|
315 |
-
$elValue = null;
|
316 |
-
} else {
|
317 |
-
list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
|
318 |
-
}
|
319 |
-
$elName = strtolower($elName);
|
320 |
-
if ('secure' == $elName) {
|
321 |
-
$cookie['secure'] = true;
|
322 |
-
} elseif ('expires' == $elName) {
|
323 |
-
$cookie['expires'] = str_replace('"', '', $elValue);
|
324 |
-
} elseif ('path' == $elName || 'domain' == $elName) {
|
325 |
-
$cookie[$elName] = urldecode($elValue);
|
326 |
-
} else {
|
327 |
-
$cookie[$elName] = $elValue;
|
328 |
-
}
|
329 |
-
}
|
330 |
-
}
|
331 |
-
$this->cookies[] = $cookie;
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Appends a string to the response body
|
336 |
-
*
|
337 |
-
* @param string $bodyChunk part of response body
|
338 |
-
*/
|
339 |
-
public function appendBody($bodyChunk)
|
340 |
-
{
|
341 |
-
$this->body .= $bodyChunk;
|
342 |
-
}
|
343 |
-
|
344 |
-
/**
|
345 |
-
* Returns the effective URL of the response
|
346 |
-
*
|
347 |
-
* This may be different from the request URL if redirects were followed.
|
348 |
-
*
|
349 |
-
* @return string
|
350 |
-
* @link http://pear.php.net/bugs/bug.php?id=18412
|
351 |
-
*/
|
352 |
-
public function getEffectiveUrl()
|
353 |
-
{
|
354 |
-
return $this->effectiveUrl;
|
355 |
-
}
|
356 |
-
|
357 |
-
/**
|
358 |
-
* Returns the status code
|
359 |
-
*
|
360 |
-
* @return integer
|
361 |
-
*/
|
362 |
-
public function getStatus()
|
363 |
-
{
|
364 |
-
return $this->code;
|
365 |
-
}
|
366 |
-
|
367 |
-
/**
|
368 |
-
* Returns the reason phrase
|
369 |
-
*
|
370 |
-
* @return string
|
371 |
-
*/
|
372 |
-
public function getReasonPhrase()
|
373 |
-
{
|
374 |
-
return $this->reasonPhrase;
|
375 |
-
}
|
376 |
-
|
377 |
-
/**
|
378 |
-
* Whether response is a redirect that can be automatically handled by HTTP_Request2
|
379 |
-
*
|
380 |
-
* @return bool
|
381 |
-
*/
|
382 |
-
public function isRedirect()
|
383 |
-
{
|
384 |
-
return in_array($this->code, array(300, 301, 302, 303, 307))
|
385 |
-
&& isset($this->headers['location']);
|
386 |
-
}
|
387 |
-
|
388 |
-
/**
|
389 |
-
* Returns either the named header or all response headers
|
390 |
-
*
|
391 |
-
* @param string $headerName Name of header to return
|
392 |
-
*
|
393 |
-
* @return string|array Value of $headerName header (null if header is
|
394 |
-
* not present), array of all response headers if
|
395 |
-
* $headerName is null
|
396 |
-
*/
|
397 |
-
public function getHeader($headerName = null)
|
398 |
-
{
|
399 |
-
if (null === $headerName) {
|
400 |
-
return $this->headers;
|
401 |
-
} else {
|
402 |
-
$headerName = strtolower($headerName);
|
403 |
-
return isset($this->headers[$headerName])? $this->headers[$headerName]: null;
|
404 |
-
}
|
405 |
-
}
|
406 |
-
|
407 |
-
/**
|
408 |
-
* Returns cookies set in response
|
409 |
-
*
|
410 |
-
* @return array
|
411 |
-
*/
|
412 |
-
public function getCookies()
|
413 |
-
{
|
414 |
-
return $this->cookies;
|
415 |
-
}
|
416 |
-
|
417 |
-
/**
|
418 |
-
* Returns the body of the response
|
419 |
-
*
|
420 |
-
* @return string
|
421 |
-
* @throws HTTP_Request2_Exception if body cannot be decoded
|
422 |
-
*/
|
423 |
-
public function getBody()
|
424 |
-
{
|
425 |
-
if (0 == strlen($this->body) || !$this->bodyEncoded
|
426 |
-
|| !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))
|
427 |
-
) {
|
428 |
-
return $this->body;
|
429 |
-
|
430 |
-
} else {
|
431 |
-
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
|
432 |
-
$oldEncoding = mb_internal_encoding();
|
433 |
-
mb_internal_encoding('8bit');
|
434 |
-
}
|
435 |
-
|
436 |
-
try {
|
437 |
-
switch (strtolower($this->getHeader('content-encoding'))) {
|
438 |
-
case 'gzip':
|
439 |
-
$decoded = self::decodeGzip($this->body);
|
440 |
-
break;
|
441 |
-
case 'deflate':
|
442 |
-
$decoded = self::decodeDeflate($this->body);
|
443 |
-
}
|
444 |
-
} catch (Exception $e) {
|
445 |
-
}
|
446 |
-
|
447 |
-
if (!empty($oldEncoding)) {
|
448 |
-
mb_internal_encoding($oldEncoding);
|
449 |
-
}
|
450 |
-
if (!empty($e)) {
|
451 |
-
throw $e;
|
452 |
-
}
|
453 |
-
return $decoded;
|
454 |
-
}
|
455 |
-
}
|
456 |
-
|
457 |
-
/**
|
458 |
-
* Get the HTTP version of the response
|
459 |
-
*
|
460 |
-
* @return string
|
461 |
-
*/
|
462 |
-
public function getVersion()
|
463 |
-
{
|
464 |
-
return $this->version;
|
465 |
-
}
|
466 |
-
|
467 |
-
/**
|
468 |
-
* Decodes the message-body encoded by gzip
|
469 |
-
*
|
470 |
-
* The real decoding work is done by gzinflate() built-in function, this
|
471 |
-
* method only parses the header and checks data for compliance with
|
472 |
-
* RFC 1952
|
473 |
-
*
|
474 |
-
* @param string $data gzip-encoded data
|
475 |
-
*
|
476 |
-
* @return string decoded data
|
477 |
-
* @throws HTTP_Request2_LogicException
|
478 |
-
* @throws HTTP_Request2_MessageException
|
479 |
-
* @link http://tools.ietf.org/html/rfc1952
|
480 |
-
*/
|
481 |
-
public static function decodeGzip($data)
|
482 |
-
{
|
483 |
-
$length = strlen($data);
|
484 |
-
// If it doesn't look like gzip-encoded data, don't bother
|
485 |
-
if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
|
486 |
-
return $data;
|
487 |
-
}
|
488 |
-
if (!function_exists('gzinflate')) {
|
489 |
-
throw new HTTP_Request2_LogicException(
|
490 |
-
'Unable to decode body: gzip extension not available',
|
491 |
-
HTTP_Request2_Exception::MISCONFIGURATION
|
492 |
-
);
|
493 |
-
}
|
494 |
-
$method = ord(substr($data, 2, 1));
|
495 |
-
if (8 != $method) {
|
496 |
-
throw new HTTP_Request2_MessageException(
|
497 |
-
'Error parsing gzip header: unknown compression method',
|
498 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
499 |
-
);
|
500 |
-
}
|
501 |
-
$flags = ord(substr($data, 3, 1));
|
502 |
-
if ($flags & 224) {
|
503 |
-
throw new HTTP_Request2_MessageException(
|
504 |
-
'Error parsing gzip header: reserved bits are set',
|
505 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
506 |
-
);
|
507 |
-
}
|
508 |
-
|
509 |
-
// header is 10 bytes minimum. may be longer, though.
|
510 |
-
$headerLength = 10;
|
511 |
-
// extra fields, need to skip 'em
|
512 |
-
if ($flags & 4) {
|
513 |
-
if ($length - $headerLength - 2 < 8) {
|
514 |
-
throw new HTTP_Request2_MessageException(
|
515 |
-
'Error parsing gzip header: data too short',
|
516 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
517 |
-
);
|
518 |
-
}
|
519 |
-
$extraLength = unpack('v', substr($data, 10, 2));
|
520 |
-
if ($length - $headerLength - 2 - $extraLength[1] < 8) {
|
521 |
-
throw new HTTP_Request2_MessageException(
|
522 |
-
'Error parsing gzip header: data too short',
|
523 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
524 |
-
);
|
525 |
-
}
|
526 |
-
$headerLength += $extraLength[1] + 2;
|
527 |
-
}
|
528 |
-
// file name, need to skip that
|
529 |
-
if ($flags & 8) {
|
530 |
-
if ($length - $headerLength - 1 < 8) {
|
531 |
-
throw new HTTP_Request2_MessageException(
|
532 |
-
'Error parsing gzip header: data too short',
|
533 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
534 |
-
);
|
535 |
-
}
|
536 |
-
$filenameLength = strpos(substr($data, $headerLength), chr(0));
|
537 |
-
if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
|
538 |
-
throw new HTTP_Request2_MessageException(
|
539 |
-
'Error parsing gzip header: data too short',
|
540 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
541 |
-
);
|
542 |
-
}
|
543 |
-
$headerLength += $filenameLength + 1;
|
544 |
-
}
|
545 |
-
// comment, need to skip that also
|
546 |
-
if ($flags & 16) {
|
547 |
-
if ($length - $headerLength - 1 < 8) {
|
548 |
-
throw new HTTP_Request2_MessageException(
|
549 |
-
'Error parsing gzip header: data too short',
|
550 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
551 |
-
);
|
552 |
-
}
|
553 |
-
$commentLength = strpos(substr($data, $headerLength), chr(0));
|
554 |
-
if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
|
555 |
-
throw new HTTP_Request2_MessageException(
|
556 |
-
'Error parsing gzip header: data too short',
|
557 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
558 |
-
);
|
559 |
-
}
|
560 |
-
$headerLength += $commentLength + 1;
|
561 |
-
}
|
562 |
-
// have a CRC for header. let's check
|
563 |
-
if ($flags & 2) {
|
564 |
-
if ($length - $headerLength - 2 < 8) {
|
565 |
-
throw new HTTP_Request2_MessageException(
|
566 |
-
'Error parsing gzip header: data too short',
|
567 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
568 |
-
);
|
569 |
-
}
|
570 |
-
$crcReal = 0xffff & crc32(substr($data, 0, $headerLength));
|
571 |
-
$crcStored = unpack('v', substr($data, $headerLength, 2));
|
572 |
-
if ($crcReal != $crcStored[1]) {
|
573 |
-
throw new HTTP_Request2_MessageException(
|
574 |
-
'Header CRC check failed',
|
575 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
576 |
-
);
|
577 |
-
}
|
578 |
-
$headerLength += 2;
|
579 |
-
}
|
580 |
-
// unpacked data CRC and size at the end of encoded data
|
581 |
-
$tmp = unpack('V2', substr($data, -8));
|
582 |
-
$dataCrc = $tmp[1];
|
583 |
-
$dataSize = $tmp[2];
|
584 |
-
|
585 |
-
// finally, call the gzinflate() function
|
586 |
-
// don't pass $dataSize to gzinflate, see bugs #13135, #14370
|
587 |
-
$unpacked = gzinflate(substr($data, $headerLength, -8));
|
588 |
-
if (false === $unpacked) {
|
589 |
-
throw new HTTP_Request2_MessageException(
|
590 |
-
'gzinflate() call failed',
|
591 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
592 |
-
);
|
593 |
-
} elseif ($dataSize != strlen($unpacked)) {
|
594 |
-
throw new HTTP_Request2_MessageException(
|
595 |
-
'Data size check failed',
|
596 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
597 |
-
);
|
598 |
-
} elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
|
599 |
-
throw new HTTP_Request2_Exception(
|
600 |
-
'Data CRC check failed',
|
601 |
-
HTTP_Request2_Exception::DECODE_ERROR
|
602 |
-
);
|
603 |
-
}
|
604 |
-
return $unpacked;
|
605 |
-
}
|
606 |
-
|
607 |
-
/**
|
608 |
-
* Decodes the message-body encoded by deflate
|
609 |
-
*
|
610 |
-
* @param string $data deflate-encoded data
|
611 |
-
*
|
612 |
-
* @return string decoded data
|
613 |
-
* @throws HTTP_Request2_LogicException
|
614 |
-
*/
|
615 |
-
public static function decodeDeflate($data)
|
616 |
-
{
|
617 |
-
if (!function_exists('gzuncompress')) {
|
618 |
-
throw new HTTP_Request2_LogicException(
|
619 |
-
'Unable to decode body: gzip extension not available',
|
620 |
-
HTTP_Request2_Exception::MISCONFIGURATION
|
621 |
-
);
|
622 |
-
}
|
623 |
-
// RFC 2616 defines 'deflate' encoding as zlib format from RFC 1950,
|
624 |
-
// while many applications send raw deflate stream from RFC 1951.
|
625 |
-
// We should check for presence of zlib header and use gzuncompress() or
|
626 |
-
// gzinflate() as needed. See bug #15305
|
627 |
-
$header = unpack('n', substr($data, 0, 2));
|
628 |
-
return (0 == $header[1] % 31)? gzuncompress($data): gzinflate($data);
|
629 |
-
}
|
630 |
-
}
|
631 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class representing a HTTP response
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Exception class for HTTP_Request2 package
|
23 |
+
*/
|
24 |
+
require_once 'HTTP/Request2/Exception.php';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Class representing a HTTP response
|
28 |
+
*
|
29 |
+
* The class is designed to be used in "streaming" scenario, building the
|
30 |
+
* response as it is being received:
|
31 |
+
* <code>
|
32 |
+
* $statusLine = read_status_line();
|
33 |
+
* $response = new HTTP_Request2_Response($statusLine);
|
34 |
+
* do {
|
35 |
+
* $headerLine = read_header_line();
|
36 |
+
* $response->parseHeaderLine($headerLine);
|
37 |
+
* } while ($headerLine != '');
|
38 |
+
*
|
39 |
+
* while ($chunk = read_body()) {
|
40 |
+
* $response->appendBody($chunk);
|
41 |
+
* }
|
42 |
+
*
|
43 |
+
* var_dump($response->getHeader(), $response->getCookies(), $response->getBody());
|
44 |
+
* </code>
|
45 |
+
*
|
46 |
+
* @category HTTP
|
47 |
+
* @package HTTP_Request2
|
48 |
+
* @author Alexey Borzov <avb@php.net>
|
49 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
50 |
+
* @version Release: 2.2.1
|
51 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
52 |
+
* @link http://tools.ietf.org/html/rfc2616#section-6
|
53 |
+
*/
|
54 |
+
class HTTP_Request2_Response
|
55 |
+
{
|
56 |
+
/**
|
57 |
+
* HTTP protocol version (e.g. 1.0, 1.1)
|
58 |
+
* @var string
|
59 |
+
*/
|
60 |
+
protected $version;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Status code
|
64 |
+
* @var integer
|
65 |
+
* @link http://tools.ietf.org/html/rfc2616#section-6.1.1
|
66 |
+
*/
|
67 |
+
protected $code;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Reason phrase
|
71 |
+
* @var string
|
72 |
+
* @link http://tools.ietf.org/html/rfc2616#section-6.1.1
|
73 |
+
*/
|
74 |
+
protected $reasonPhrase;
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Effective URL (may be different from original request URL in case of redirects)
|
78 |
+
* @var string
|
79 |
+
*/
|
80 |
+
protected $effectiveUrl;
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Associative array of response headers
|
84 |
+
* @var array
|
85 |
+
*/
|
86 |
+
protected $headers = array();
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Cookies set in the response
|
90 |
+
* @var array
|
91 |
+
*/
|
92 |
+
protected $cookies = array();
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Name of last header processed by parseHederLine()
|
96 |
+
*
|
97 |
+
* Used to handle the headers that span multiple lines
|
98 |
+
*
|
99 |
+
* @var string
|
100 |
+
*/
|
101 |
+
protected $lastHeader = null;
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Response body
|
105 |
+
* @var string
|
106 |
+
*/
|
107 |
+
protected $body = '';
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Whether the body is still encoded by Content-Encoding
|
111 |
+
*
|
112 |
+
* cURL provides the decoded body to the callback; if we are reading from
|
113 |
+
* socket the body is still gzipped / deflated
|
114 |
+
*
|
115 |
+
* @var bool
|
116 |
+
*/
|
117 |
+
protected $bodyEncoded;
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Associative array of HTTP status code / reason phrase.
|
121 |
+
*
|
122 |
+
* @var array
|
123 |
+
* @link http://tools.ietf.org/html/rfc2616#section-10
|
124 |
+
*/
|
125 |
+
protected static $phrases = array(
|
126 |
+
|
127 |
+
// 1xx: Informational - Request received, continuing process
|
128 |
+
100 => 'Continue',
|
129 |
+
101 => 'Switching Protocols',
|
130 |
+
|
131 |
+
// 2xx: Success - The action was successfully received, understood and
|
132 |
+
// accepted
|
133 |
+
200 => 'OK',
|
134 |
+
201 => 'Created',
|
135 |
+
202 => 'Accepted',
|
136 |
+
203 => 'Non-Authoritative Information',
|
137 |
+
204 => 'No Content',
|
138 |
+
205 => 'Reset Content',
|
139 |
+
206 => 'Partial Content',
|
140 |
+
|
141 |
+
// 3xx: Redirection - Further action must be taken in order to complete
|
142 |
+
// the request
|
143 |
+
300 => 'Multiple Choices',
|
144 |
+
301 => 'Moved Permanently',
|
145 |
+
302 => 'Found', // 1.1
|
146 |
+
303 => 'See Other',
|
147 |
+
304 => 'Not Modified',
|
148 |
+
305 => 'Use Proxy',
|
149 |
+
307 => 'Temporary Redirect',
|
150 |
+
|
151 |
+
// 4xx: Client Error - The request contains bad syntax or cannot be
|
152 |
+
// fulfilled
|
153 |
+
400 => 'Bad Request',
|
154 |
+
401 => 'Unauthorized',
|
155 |
+
402 => 'Payment Required',
|
156 |
+
403 => 'Forbidden',
|
157 |
+
404 => 'Not Found',
|
158 |
+
405 => 'Method Not Allowed',
|
159 |
+
406 => 'Not Acceptable',
|
160 |
+
407 => 'Proxy Authentication Required',
|
161 |
+
408 => 'Request Timeout',
|
162 |
+
409 => 'Conflict',
|
163 |
+
410 => 'Gone',
|
164 |
+
411 => 'Length Required',
|
165 |
+
412 => 'Precondition Failed',
|
166 |
+
413 => 'Request Entity Too Large',
|
167 |
+
414 => 'Request-URI Too Long',
|
168 |
+
415 => 'Unsupported Media Type',
|
169 |
+
416 => 'Requested Range Not Satisfiable',
|
170 |
+
417 => 'Expectation Failed',
|
171 |
+
|
172 |
+
// 5xx: Server Error - The server failed to fulfill an apparently
|
173 |
+
// valid request
|
174 |
+
500 => 'Internal Server Error',
|
175 |
+
501 => 'Not Implemented',
|
176 |
+
502 => 'Bad Gateway',
|
177 |
+
503 => 'Service Unavailable',
|
178 |
+
504 => 'Gateway Timeout',
|
179 |
+
505 => 'HTTP Version Not Supported',
|
180 |
+
509 => 'Bandwidth Limit Exceeded',
|
181 |
+
|
182 |
+
);
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Returns the default reason phrase for the given code or all reason phrases
|
186 |
+
*
|
187 |
+
* @param int $code Response code
|
188 |
+
*
|
189 |
+
* @return string|array|null Default reason phrase for $code if $code is given
|
190 |
+
* (null if no phrase is available), array of all
|
191 |
+
* reason phrases if $code is null
|
192 |
+
* @link http://pear.php.net/bugs/18716
|
193 |
+
*/
|
194 |
+
public static function getDefaultReasonPhrase($code = null)
|
195 |
+
{
|
196 |
+
if (null === $code) {
|
197 |
+
return self::$phrases;
|
198 |
+
} else {
|
199 |
+
return isset(self::$phrases[$code]) ? self::$phrases[$code] : null;
|
200 |
+
}
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Constructor, parses the response status line
|
205 |
+
*
|
206 |
+
* @param string $statusLine Response status line (e.g. "HTTP/1.1 200 OK")
|
207 |
+
* @param bool $bodyEncoded Whether body is still encoded by Content-Encoding
|
208 |
+
* @param string $effectiveUrl Effective URL of the response
|
209 |
+
*
|
210 |
+
* @throws HTTP_Request2_MessageException if status line is invalid according to spec
|
211 |
+
*/
|
212 |
+
public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)
|
213 |
+
{
|
214 |
+
if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {
|
215 |
+
throw new HTTP_Request2_MessageException(
|
216 |
+
"Malformed response: {$statusLine}",
|
217 |
+
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
218 |
+
);
|
219 |
+
}
|
220 |
+
$this->version = $m[1];
|
221 |
+
$this->code = intval($m[2]);
|
222 |
+
$this->reasonPhrase = !empty($m[3]) ? trim($m[3]) : self::getDefaultReasonPhrase($this->code);
|
223 |
+
$this->bodyEncoded = (bool)$bodyEncoded;
|
224 |
+
$this->effectiveUrl = (string)$effectiveUrl;
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Parses the line from HTTP response filling $headers array
|
229 |
+
*
|
230 |
+
* The method should be called after reading the line from socket or receiving
|
231 |
+
* it into cURL callback. Passing an empty string here indicates the end of
|
232 |
+
* response headers and triggers additional processing, so be sure to pass an
|
233 |
+
* empty string in the end.
|
234 |
+
*
|
235 |
+
* @param string $headerLine Line from HTTP response
|
236 |
+
*/
|
237 |
+
public function parseHeaderLine($headerLine)
|
238 |
+
{
|
239 |
+
$headerLine = trim($headerLine, "\r\n");
|
240 |
+
|
241 |
+
if ('' == $headerLine) {
|
242 |
+
// empty string signals the end of headers, process the received ones
|
243 |
+
if (!empty($this->headers['set-cookie'])) {
|
244 |
+
$cookies = is_array($this->headers['set-cookie'])?
|
245 |
+
$this->headers['set-cookie']:
|
246 |
+
array($this->headers['set-cookie']);
|
247 |
+
foreach ($cookies as $cookieString) {
|
248 |
+
$this->parseCookie($cookieString);
|
249 |
+
}
|
250 |
+
unset($this->headers['set-cookie']);
|
251 |
+
}
|
252 |
+
foreach (array_keys($this->headers) as $k) {
|
253 |
+
if (is_array($this->headers[$k])) {
|
254 |
+
$this->headers[$k] = implode(', ', $this->headers[$k]);
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
} elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {
|
259 |
+
// string of the form header-name: header value
|
260 |
+
$name = strtolower($m[1]);
|
261 |
+
$value = trim($m[2]);
|
262 |
+
if (empty($this->headers[$name])) {
|
263 |
+
$this->headers[$name] = $value;
|
264 |
+
} else {
|
265 |
+
if (!is_array($this->headers[$name])) {
|
266 |
+
$this->headers[$name] = array($this->headers[$name]);
|
267 |
+
}
|
268 |
+
$this->headers[$name][] = $value;
|
269 |
+
}
|
270 |
+
$this->lastHeader = $name;
|
271 |
+
|
272 |
+
} elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
|
273 |
+
// continuation of a previous header
|
274 |
+
if (!is_array($this->headers[$this->lastHeader])) {
|
275 |
+
$this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
|
276 |
+
} else {
|
277 |
+
$key = count($this->headers[$this->lastHeader]) - 1;
|
278 |
+
$this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);
|
279 |
+
}
|
280 |
+
}
|
281 |
+
}
|
282 |
+
|
283 |
+
/**
|
284 |
+
* Parses a Set-Cookie header to fill $cookies array
|
285 |
+
*
|
286 |
+
* @param string $cookieString value of Set-Cookie header
|
287 |
+
*
|
288 |
+
* @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
|
289 |
+
*/
|
290 |
+
protected function parseCookie($cookieString)
|
291 |
+
{
|
292 |
+
$cookie = array(
|
293 |
+
'expires' => null,
|
294 |
+
'domain' => null,
|
295 |
+
'path' => null,
|
296 |
+
'secure' => false
|
297 |
+
);
|
298 |
+
|
299 |
+
if (!strpos($cookieString, ';')) {
|
300 |
+
// Only a name=value pair
|
301 |
+
$pos = strpos($cookieString, '=');
|
302 |
+
$cookie['name'] = trim(substr($cookieString, 0, $pos));
|
303 |
+
$cookie['value'] = trim(substr($cookieString, $pos + 1));
|
304 |
+
|
305 |
+
} else {
|
306 |
+
// Some optional parameters are supplied
|
307 |
+
$elements = explode(';', $cookieString);
|
308 |
+
$pos = strpos($elements[0], '=');
|
309 |
+
$cookie['name'] = trim(substr($elements[0], 0, $pos));
|
310 |
+
$cookie['value'] = trim(substr($elements[0], $pos + 1));
|
311 |
+
|
312 |
+
for ($i = 1; $i < count($elements); $i++) {
|
313 |
+
if (false === strpos($elements[$i], '=')) {
|
314 |
+
$elName = trim($elements[$i]);
|
315 |
+
$elValue = null;
|
316 |
+
} else {
|
317 |
+
list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
|
318 |
+
}
|
319 |
+
$elName = strtolower($elName);
|
320 |
+
if ('secure' == $elName) {
|
321 |
+
$cookie['secure'] = true;
|
322 |
+
} elseif ('expires' == $elName) {
|
323 |
+
$cookie['expires'] = str_replace('"', '', $elValue);
|
324 |
+
} elseif ('path' == $elName || 'domain' == $elName) {
|
325 |
+
$cookie[$elName] = urldecode($elValue);
|
326 |
+
} else {
|
327 |
+
$cookie[$elName] = $elValue;
|
328 |
+
}
|
329 |
+
}
|
330 |
+
}
|
331 |
+
$this->cookies[] = $cookie;
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Appends a string to the response body
|
336 |
+
*
|
337 |
+
* @param string $bodyChunk part of response body
|
338 |
+
*/
|
339 |
+
public function appendBody($bodyChunk)
|
340 |
+
{
|
341 |
+
$this->body .= $bodyChunk;
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Returns the effective URL of the response
|
346 |
+
*
|
347 |
+
* This may be different from the request URL if redirects were followed.
|
348 |
+
*
|
349 |
+
* @return string
|
350 |
+
* @link http://pear.php.net/bugs/bug.php?id=18412
|
351 |
+
*/
|
352 |
+
public function getEffectiveUrl()
|
353 |
+
{
|
354 |
+
return $this->effectiveUrl;
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Returns the status code
|
359 |
+
*
|
360 |
+
* @return integer
|
361 |
+
*/
|
362 |
+
public function getStatus()
|
363 |
+
{
|
364 |
+
return $this->code;
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Returns the reason phrase
|
369 |
+
*
|
370 |
+
* @return string
|
371 |
+
*/
|
372 |
+
public function getReasonPhrase()
|
373 |
+
{
|
374 |
+
return $this->reasonPhrase;
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* Whether response is a redirect that can be automatically handled by HTTP_Request2
|
379 |
+
*
|
380 |
+
* @return bool
|
381 |
+
*/
|
382 |
+
public function isRedirect()
|
383 |
+
{
|
384 |
+
return in_array($this->code, array(300, 301, 302, 303, 307))
|
385 |
+
&& isset($this->headers['location']);
|
386 |
+
}
|
387 |
+
|
388 |
+
/**
|
389 |
+
* Returns either the named header or all response headers
|
390 |
+
*
|
391 |
+
* @param string $headerName Name of header to return
|
392 |
+
*
|
393 |
+
* @return string|array Value of $headerName header (null if header is
|
394 |
+
* not present), array of all response headers if
|
395 |
+
* $headerName is null
|
396 |
+
*/
|
397 |
+
public function getHeader($headerName = null)
|
398 |
+
{
|
399 |
+
if (null === $headerName) {
|
400 |
+
return $this->headers;
|
401 |
+
} else {
|
402 |
+
$headerName = strtolower($headerName);
|
403 |
+
return isset($this->headers[$headerName])? $this->headers[$headerName]: null;
|
404 |
+
}
|
405 |
+
}
|
406 |
+
|
407 |
+
/**
|
408 |
+
* Returns cookies set in response
|
409 |
+
*
|
410 |
+
* @return array
|
411 |
+
*/
|
412 |
+
public function getCookies()
|
413 |
+
{
|
414 |
+
return $this->cookies;
|
415 |
+
}
|
416 |
+
|
417 |
+
/**
|
418 |
+
* Returns the body of the response
|
419 |
+
*
|
420 |
+
* @return string
|
421 |
+
* @throws HTTP_Request2_Exception if body cannot be decoded
|
422 |
+
*/
|
423 |
+
public function getBody()
|
424 |
+
{
|
425 |
+
if (0 == strlen($this->body) || !$this->bodyEncoded
|
426 |
+
|| !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))
|
427 |
+
) {
|
428 |
+
return $this->body;
|
429 |
+
|
430 |
+
} else {
|
431 |
+
if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
|
432 |
+
$oldEncoding = mb_internal_encoding();
|
433 |
+
mb_internal_encoding('8bit');
|
434 |
+
}
|
435 |
+
|
436 |
+
try {
|
437 |
+
switch (strtolower($this->getHeader('content-encoding'))) {
|
438 |
+
case 'gzip':
|
439 |
+
$decoded = self::decodeGzip($this->body);
|
440 |
+
break;
|
441 |
+
case 'deflate':
|
442 |
+
$decoded = self::decodeDeflate($this->body);
|
443 |
+
}
|
444 |
+
} catch (Exception $e) {
|
445 |
+
}
|
446 |
+
|
447 |
+
if (!empty($oldEncoding)) {
|
448 |
+
mb_internal_encoding($oldEncoding);
|
449 |
+
}
|
450 |
+
if (!empty($e)) {
|
451 |
+
throw $e;
|
452 |
+
}
|
453 |
+
return $decoded;
|
454 |
+
}
|
455 |
+
}
|
456 |
+
|
457 |
+
/**
|
458 |
+
* Get the HTTP version of the response
|
459 |
+
*
|
460 |
+
* @return string
|
461 |
+
*/
|
462 |
+
public function getVersion()
|
463 |
+
{
|
464 |
+
return $this->version;
|
465 |
+
}
|
466 |
+
|
467 |
+
/**
|
468 |
+
* Decodes the message-body encoded by gzip
|
469 |
+
*
|
470 |
+
* The real decoding work is done by gzinflate() built-in function, this
|
471 |
+
* method only parses the header and checks data for compliance with
|
472 |
+
* RFC 1952
|
473 |
+
*
|
474 |
+
* @param string $data gzip-encoded data
|
475 |
+
*
|
476 |
+
* @return string decoded data
|
477 |
+
* @throws HTTP_Request2_LogicException
|
478 |
+
* @throws HTTP_Request2_MessageException
|
479 |
+
* @link http://tools.ietf.org/html/rfc1952
|
480 |
+
*/
|
481 |
+
public static function decodeGzip($data)
|
482 |
+
{
|
483 |
+
$length = strlen($data);
|
484 |
+
// If it doesn't look like gzip-encoded data, don't bother
|
485 |
+
if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
|
486 |
+
return $data;
|
487 |
+
}
|
488 |
+
if (!function_exists('gzinflate')) {
|
489 |
+
throw new HTTP_Request2_LogicException(
|
490 |
+
'Unable to decode body: gzip extension not available',
|
491 |
+
HTTP_Request2_Exception::MISCONFIGURATION
|
492 |
+
);
|
493 |
+
}
|
494 |
+
$method = ord(substr($data, 2, 1));
|
495 |
+
if (8 != $method) {
|
496 |
+
throw new HTTP_Request2_MessageException(
|
497 |
+
'Error parsing gzip header: unknown compression method',
|
498 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
499 |
+
);
|
500 |
+
}
|
501 |
+
$flags = ord(substr($data, 3, 1));
|
502 |
+
if ($flags & 224) {
|
503 |
+
throw new HTTP_Request2_MessageException(
|
504 |
+
'Error parsing gzip header: reserved bits are set',
|
505 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
506 |
+
);
|
507 |
+
}
|
508 |
+
|
509 |
+
// header is 10 bytes minimum. may be longer, though.
|
510 |
+
$headerLength = 10;
|
511 |
+
// extra fields, need to skip 'em
|
512 |
+
if ($flags & 4) {
|
513 |
+
if ($length - $headerLength - 2 < 8) {
|
514 |
+
throw new HTTP_Request2_MessageException(
|
515 |
+
'Error parsing gzip header: data too short',
|
516 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
517 |
+
);
|
518 |
+
}
|
519 |
+
$extraLength = unpack('v', substr($data, 10, 2));
|
520 |
+
if ($length - $headerLength - 2 - $extraLength[1] < 8) {
|
521 |
+
throw new HTTP_Request2_MessageException(
|
522 |
+
'Error parsing gzip header: data too short',
|
523 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
524 |
+
);
|
525 |
+
}
|
526 |
+
$headerLength += $extraLength[1] + 2;
|
527 |
+
}
|
528 |
+
// file name, need to skip that
|
529 |
+
if ($flags & 8) {
|
530 |
+
if ($length - $headerLength - 1 < 8) {
|
531 |
+
throw new HTTP_Request2_MessageException(
|
532 |
+
'Error parsing gzip header: data too short',
|
533 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
534 |
+
);
|
535 |
+
}
|
536 |
+
$filenameLength = strpos(substr($data, $headerLength), chr(0));
|
537 |
+
if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
|
538 |
+
throw new HTTP_Request2_MessageException(
|
539 |
+
'Error parsing gzip header: data too short',
|
540 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
541 |
+
);
|
542 |
+
}
|
543 |
+
$headerLength += $filenameLength + 1;
|
544 |
+
}
|
545 |
+
// comment, need to skip that also
|
546 |
+
if ($flags & 16) {
|
547 |
+
if ($length - $headerLength - 1 < 8) {
|
548 |
+
throw new HTTP_Request2_MessageException(
|
549 |
+
'Error parsing gzip header: data too short',
|
550 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
551 |
+
);
|
552 |
+
}
|
553 |
+
$commentLength = strpos(substr($data, $headerLength), chr(0));
|
554 |
+
if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
|
555 |
+
throw new HTTP_Request2_MessageException(
|
556 |
+
'Error parsing gzip header: data too short',
|
557 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
558 |
+
);
|
559 |
+
}
|
560 |
+
$headerLength += $commentLength + 1;
|
561 |
+
}
|
562 |
+
// have a CRC for header. let's check
|
563 |
+
if ($flags & 2) {
|
564 |
+
if ($length - $headerLength - 2 < 8) {
|
565 |
+
throw new HTTP_Request2_MessageException(
|
566 |
+
'Error parsing gzip header: data too short',
|
567 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
568 |
+
);
|
569 |
+
}
|
570 |
+
$crcReal = 0xffff & crc32(substr($data, 0, $headerLength));
|
571 |
+
$crcStored = unpack('v', substr($data, $headerLength, 2));
|
572 |
+
if ($crcReal != $crcStored[1]) {
|
573 |
+
throw new HTTP_Request2_MessageException(
|
574 |
+
'Header CRC check failed',
|
575 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
576 |
+
);
|
577 |
+
}
|
578 |
+
$headerLength += 2;
|
579 |
+
}
|
580 |
+
// unpacked data CRC and size at the end of encoded data
|
581 |
+
$tmp = unpack('V2', substr($data, -8));
|
582 |
+
$dataCrc = $tmp[1];
|
583 |
+
$dataSize = $tmp[2];
|
584 |
+
|
585 |
+
// finally, call the gzinflate() function
|
586 |
+
// don't pass $dataSize to gzinflate, see bugs #13135, #14370
|
587 |
+
$unpacked = gzinflate(substr($data, $headerLength, -8));
|
588 |
+
if (false === $unpacked) {
|
589 |
+
throw new HTTP_Request2_MessageException(
|
590 |
+
'gzinflate() call failed',
|
591 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
592 |
+
);
|
593 |
+
} elseif ($dataSize != strlen($unpacked)) {
|
594 |
+
throw new HTTP_Request2_MessageException(
|
595 |
+
'Data size check failed',
|
596 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
597 |
+
);
|
598 |
+
} elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
|
599 |
+
throw new HTTP_Request2_Exception(
|
600 |
+
'Data CRC check failed',
|
601 |
+
HTTP_Request2_Exception::DECODE_ERROR
|
602 |
+
);
|
603 |
+
}
|
604 |
+
return $unpacked;
|
605 |
+
}
|
606 |
+
|
607 |
+
/**
|
608 |
+
* Decodes the message-body encoded by deflate
|
609 |
+
*
|
610 |
+
* @param string $data deflate-encoded data
|
611 |
+
*
|
612 |
+
* @return string decoded data
|
613 |
+
* @throws HTTP_Request2_LogicException
|
614 |
+
*/
|
615 |
+
public static function decodeDeflate($data)
|
616 |
+
{
|
617 |
+
if (!function_exists('gzuncompress')) {
|
618 |
+
throw new HTTP_Request2_LogicException(
|
619 |
+
'Unable to decode body: gzip extension not available',
|
620 |
+
HTTP_Request2_Exception::MISCONFIGURATION
|
621 |
+
);
|
622 |
+
}
|
623 |
+
// RFC 2616 defines 'deflate' encoding as zlib format from RFC 1950,
|
624 |
+
// while many applications send raw deflate stream from RFC 1951.
|
625 |
+
// We should check for presence of zlib header and use gzuncompress() or
|
626 |
+
// gzinflate() as needed. See bug #15305
|
627 |
+
$header = unpack('n', substr($data, 0, 2));
|
628 |
+
return (0 == $header[1] % 31)? gzuncompress($data): gzinflate($data);
|
629 |
+
}
|
630 |
+
}
|
631 |
?>
|
vendor/PEAR/HTTP/Request2/SOCKS5.php
CHANGED
@@ -1,135 +1,135 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* SOCKS5 proxy connection class
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/** Socket wrapper class used by Socket Adapter */
|
22 |
-
require_once 'HTTP/Request2/SocketWrapper.php';
|
23 |
-
|
24 |
-
/**
|
25 |
-
* SOCKS5 proxy connection class (used by Socket Adapter)
|
26 |
-
*
|
27 |
-
* @category HTTP
|
28 |
-
* @package HTTP_Request2
|
29 |
-
* @author Alexey Borzov <avb@php.net>
|
30 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
31 |
-
* @version Release: 2.2.1
|
32 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
33 |
-
* @link http://pear.php.net/bugs/bug.php?id=19332
|
34 |
-
* @link http://tools.ietf.org/html/rfc1928
|
35 |
-
*/
|
36 |
-
class HTTP_Request2_SOCKS5 extends HTTP_Request2_SocketWrapper
|
37 |
-
{
|
38 |
-
/**
|
39 |
-
* Constructor, tries to connect and authenticate to a SOCKS5 proxy
|
40 |
-
*
|
41 |
-
* @param string $address Proxy address, e.g. 'tcp://localhost:1080'
|
42 |
-
* @param int $timeout Connection timeout (seconds)
|
43 |
-
* @param array $contextOptions Stream context options
|
44 |
-
* @param string $username Proxy user name
|
45 |
-
* @param string $password Proxy password
|
46 |
-
*
|
47 |
-
* @throws HTTP_Request2_LogicException
|
48 |
-
* @throws HTTP_Request2_ConnectionException
|
49 |
-
* @throws HTTP_Request2_MessageException
|
50 |
-
*/
|
51 |
-
public function __construct(
|
52 |
-
$address, $timeout = 10, array $contextOptions = array(),
|
53 |
-
$username = null, $password = null
|
54 |
-
) {
|
55 |
-
parent::__construct($address, $timeout, $contextOptions);
|
56 |
-
|
57 |
-
if (strlen($username)) {
|
58 |
-
$request = pack('C4', 5, 2, 0, 2);
|
59 |
-
} else {
|
60 |
-
$request = pack('C3', 5, 1, 0);
|
61 |
-
}
|
62 |
-
$this->write($request);
|
63 |
-
$response = unpack('Cversion/Cmethod', $this->read(3));
|
64 |
-
if (5 != $response['version']) {
|
65 |
-
throw new HTTP_Request2_MessageException(
|
66 |
-
'Invalid version received from SOCKS5 proxy: ' . $response['version'],
|
67 |
-
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
68 |
-
);
|
69 |
-
}
|
70 |
-
switch ($response['method']) {
|
71 |
-
case 2:
|
72 |
-
$this->performAuthentication($username, $password);
|
73 |
-
case 0:
|
74 |
-
break;
|
75 |
-
default:
|
76 |
-
throw new HTTP_Request2_ConnectionException(
|
77 |
-
"Connection rejected by proxy due to unsupported auth method"
|
78 |
-
);
|
79 |
-
}
|
80 |
-
}
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Performs username/password authentication for SOCKS5
|
84 |
-
*
|
85 |
-
* @param string $username Proxy user name
|
86 |
-
* @param string $password Proxy password
|
87 |
-
*
|
88 |
-
* @throws HTTP_Request2_ConnectionException
|
89 |
-
* @throws HTTP_Request2_MessageException
|
90 |
-
* @link http://tools.ietf.org/html/rfc1929
|
91 |
-
*/
|
92 |
-
protected function performAuthentication($username, $password)
|
93 |
-
{
|
94 |
-
$request = pack('C2', 1, strlen($username)) . $username
|
95 |
-
. pack('C', strlen($password)) . $password;
|
96 |
-
|
97 |
-
$this->write($request);
|
98 |
-
$response = unpack('Cvn/Cstatus', $this->read(3));
|
99 |
-
if (1 != $response['vn'] || 0 != $response['status']) {
|
100 |
-
throw new HTTP_Request2_ConnectionException(
|
101 |
-
'Connection rejected by proxy due to invalid username and/or password'
|
102 |
-
);
|
103 |
-
}
|
104 |
-
}
|
105 |
-
|
106 |
-
/**
|
107 |
-
* Connects to a remote host via proxy
|
108 |
-
*
|
109 |
-
* @param string $remoteHost Remote host
|
110 |
-
* @param int $remotePort Remote port
|
111 |
-
*
|
112 |
-
* @throws HTTP_Request2_ConnectionException
|
113 |
-
* @throws HTTP_Request2_MessageException
|
114 |
-
*/
|
115 |
-
public function connect($remoteHost, $remotePort)
|
116 |
-
{
|
117 |
-
$request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))
|
118 |
-
. $remoteHost . pack('n', $remotePort);
|
119 |
-
|
120 |
-
$this->write($request);
|
121 |
-
$response = unpack('Cversion/Creply/Creserved', $this->read(1024));
|
122 |
-
if (5 != $response['version'] || 0 != $response['reserved']) {
|
123 |
-
throw new HTTP_Request2_MessageException(
|
124 |
-
'Invalid response received from SOCKS5 proxy',
|
125 |
-
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
126 |
-
);
|
127 |
-
} elseif (0 != $response['reply']) {
|
128 |
-
throw new HTTP_Request2_ConnectionException(
|
129 |
-
"Unable to connect to {$remoteHost}:{$remotePort} through SOCKS5 proxy",
|
130 |
-
0, $response['reply']
|
131 |
-
);
|
132 |
-
}
|
133 |
-
}
|
134 |
-
}
|
135 |
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* SOCKS5 proxy connection class
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/** Socket wrapper class used by Socket Adapter */
|
22 |
+
require_once 'HTTP/Request2/SocketWrapper.php';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* SOCKS5 proxy connection class (used by Socket Adapter)
|
26 |
+
*
|
27 |
+
* @category HTTP
|
28 |
+
* @package HTTP_Request2
|
29 |
+
* @author Alexey Borzov <avb@php.net>
|
30 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
31 |
+
* @version Release: 2.2.1
|
32 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
33 |
+
* @link http://pear.php.net/bugs/bug.php?id=19332
|
34 |
+
* @link http://tools.ietf.org/html/rfc1928
|
35 |
+
*/
|
36 |
+
class HTTP_Request2_SOCKS5 extends HTTP_Request2_SocketWrapper
|
37 |
+
{
|
38 |
+
/**
|
39 |
+
* Constructor, tries to connect and authenticate to a SOCKS5 proxy
|
40 |
+
*
|
41 |
+
* @param string $address Proxy address, e.g. 'tcp://localhost:1080'
|
42 |
+
* @param int $timeout Connection timeout (seconds)
|
43 |
+
* @param array $contextOptions Stream context options
|
44 |
+
* @param string $username Proxy user name
|
45 |
+
* @param string $password Proxy password
|
46 |
+
*
|
47 |
+
* @throws HTTP_Request2_LogicException
|
48 |
+
* @throws HTTP_Request2_ConnectionException
|
49 |
+
* @throws HTTP_Request2_MessageException
|
50 |
+
*/
|
51 |
+
public function __construct(
|
52 |
+
$address, $timeout = 10, array $contextOptions = array(),
|
53 |
+
$username = null, $password = null
|
54 |
+
) {
|
55 |
+
parent::__construct($address, $timeout, $contextOptions);
|
56 |
+
|
57 |
+
if (strlen($username)) {
|
58 |
+
$request = pack('C4', 5, 2, 0, 2);
|
59 |
+
} else {
|
60 |
+
$request = pack('C3', 5, 1, 0);
|
61 |
+
}
|
62 |
+
$this->write($request);
|
63 |
+
$response = unpack('Cversion/Cmethod', $this->read(3));
|
64 |
+
if (5 != $response['version']) {
|
65 |
+
throw new HTTP_Request2_MessageException(
|
66 |
+
'Invalid version received from SOCKS5 proxy: ' . $response['version'],
|
67 |
+
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
68 |
+
);
|
69 |
+
}
|
70 |
+
switch ($response['method']) {
|
71 |
+
case 2:
|
72 |
+
$this->performAuthentication($username, $password);
|
73 |
+
case 0:
|
74 |
+
break;
|
75 |
+
default:
|
76 |
+
throw new HTTP_Request2_ConnectionException(
|
77 |
+
"Connection rejected by proxy due to unsupported auth method"
|
78 |
+
);
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Performs username/password authentication for SOCKS5
|
84 |
+
*
|
85 |
+
* @param string $username Proxy user name
|
86 |
+
* @param string $password Proxy password
|
87 |
+
*
|
88 |
+
* @throws HTTP_Request2_ConnectionException
|
89 |
+
* @throws HTTP_Request2_MessageException
|
90 |
+
* @link http://tools.ietf.org/html/rfc1929
|
91 |
+
*/
|
92 |
+
protected function performAuthentication($username, $password)
|
93 |
+
{
|
94 |
+
$request = pack('C2', 1, strlen($username)) . $username
|
95 |
+
. pack('C', strlen($password)) . $password;
|
96 |
+
|
97 |
+
$this->write($request);
|
98 |
+
$response = unpack('Cvn/Cstatus', $this->read(3));
|
99 |
+
if (1 != $response['vn'] || 0 != $response['status']) {
|
100 |
+
throw new HTTP_Request2_ConnectionException(
|
101 |
+
'Connection rejected by proxy due to invalid username and/or password'
|
102 |
+
);
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Connects to a remote host via proxy
|
108 |
+
*
|
109 |
+
* @param string $remoteHost Remote host
|
110 |
+
* @param int $remotePort Remote port
|
111 |
+
*
|
112 |
+
* @throws HTTP_Request2_ConnectionException
|
113 |
+
* @throws HTTP_Request2_MessageException
|
114 |
+
*/
|
115 |
+
public function connect($remoteHost, $remotePort)
|
116 |
+
{
|
117 |
+
$request = pack('C5', 0x05, 0x01, 0x00, 0x03, strlen($remoteHost))
|
118 |
+
. $remoteHost . pack('n', $remotePort);
|
119 |
+
|
120 |
+
$this->write($request);
|
121 |
+
$response = unpack('Cversion/Creply/Creserved', $this->read(1024));
|
122 |
+
if (5 != $response['version'] || 0 != $response['reserved']) {
|
123 |
+
throw new HTTP_Request2_MessageException(
|
124 |
+
'Invalid response received from SOCKS5 proxy',
|
125 |
+
HTTP_Request2_Exception::MALFORMED_RESPONSE
|
126 |
+
);
|
127 |
+
} elseif (0 != $response['reply']) {
|
128 |
+
throw new HTTP_Request2_ConnectionException(
|
129 |
+
"Unable to connect to {$remoteHost}:{$remotePort} through SOCKS5 proxy",
|
130 |
+
0, $response['reply']
|
131 |
+
);
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
?>
|
vendor/PEAR/HTTP/Request2/SocketWrapper.php
CHANGED
@@ -1,297 +1,297 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Socket wrapper class used by Socket Adapter
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* LICENSE
|
8 |
-
*
|
9 |
-
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
-
* with this package in the file LICENSE and available at the URL
|
11 |
-
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
-
*
|
13 |
-
* @category HTTP
|
14 |
-
* @package HTTP_Request2
|
15 |
-
* @author Alexey Borzov <avb@php.net>
|
16 |
-
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
-
*/
|
20 |
-
|
21 |
-
/** Exception classes for HTTP_Request2 package */
|
22 |
-
require_once 'HTTP/Request2/Exception.php';
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Socket wrapper class used by Socket Adapter
|
26 |
-
*
|
27 |
-
* Needed to properly handle connection errors, global timeout support and
|
28 |
-
* similar things. Loosely based on Net_Socket used by older HTTP_Request.
|
29 |
-
*
|
30 |
-
* @category HTTP
|
31 |
-
* @package HTTP_Request2
|
32 |
-
* @author Alexey Borzov <avb@php.net>
|
33 |
-
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
34 |
-
* @version Release: 2.2.1
|
35 |
-
* @link http://pear.php.net/package/HTTP_Request2
|
36 |
-
* @link http://pear.php.net/bugs/bug.php?id=19332
|
37 |
-
* @link http://tools.ietf.org/html/rfc1928
|
38 |
-
*/
|
39 |
-
class HTTP_Request2_SocketWrapper
|
40 |
-
{
|
41 |
-
/**
|
42 |
-
* PHP warning messages raised during stream_socket_client() call
|
43 |
-
* @var array
|
44 |
-
*/
|
45 |
-
protected $connectionWarnings = array();
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Connected socket
|
49 |
-
* @var resource
|
50 |
-
*/
|
51 |
-
protected $socket;
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Sum of start time and global timeout, exception will be thrown if request continues past this time
|
55 |
-
* @var integer
|
56 |
-
*/
|
57 |
-
protected $deadline;
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Global timeout value, mostly for exception messages
|
61 |
-
* @var integer
|
62 |
-
*/
|
63 |
-
protected $timeout;
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Class constructor, tries to establish connection
|
67 |
-
*
|
68 |
-
* @param string $address Address for stream_socket_client() call,
|
69 |
-
* e.g. 'tcp://localhost:80'
|
70 |
-
* @param int $timeout Connection timeout (seconds)
|
71 |
-
* @param array $contextOptions Context options
|
72 |
-
*
|
73 |
-
* @throws HTTP_Request2_LogicException
|
74 |
-
* @throws HTTP_Request2_ConnectionException
|
75 |
-
*/
|
76 |
-
public function __construct($address, $timeout, array $contextOptions = array())
|
77 |
-
{
|
78 |
-
if (!empty($contextOptions)
|
79 |
-
&& !isset($contextOptions['socket']) && !isset($contextOptions['ssl'])
|
80 |
-
) {
|
81 |
-
// Backwards compatibility with 2.1.0 and 2.1.1 releases
|
82 |
-
$contextOptions = array('ssl' => $contextOptions);
|
83 |
-
}
|
84 |
-
$context = stream_context_create();
|
85 |
-
foreach ($contextOptions as $wrapper => $options) {
|
86 |
-
foreach ($options as $name => $value) {
|
87 |
-
if (!stream_context_set_option($context, $wrapper, $name, $value)) {
|
88 |
-
throw new HTTP_Request2_LogicException(
|
89 |
-
"Error setting '{$wrapper}' wrapper context option '{$name}'"
|
90 |
-
);
|
91 |
-
}
|
92 |
-
}
|
93 |
-
}
|
94 |
-
set_error_handler(array($this, 'connectionWarningsHandler'));
|
95 |
-
$this->socket = stream_socket_client(
|
96 |
-
$address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context
|
97 |
-
);
|
98 |
-
restore_error_handler();
|
99 |
-
// if we fail to bind to a specified local address (see request #19515),
|
100 |
-
// connection still succeeds, albeit with a warning. Throw an Exception
|
101 |
-
// with the warning text in this case as that connection is unlikely
|
102 |
-
// to be what user wants and as Curl throws an error in similar case.
|
103 |
-
if ($this->connectionWarnings) {
|
104 |
-
if ($this->socket) {
|
105 |
-
fclose($this->socket);
|
106 |
-
}
|
107 |
-
$error = $errstr ? $errstr : implode("\n", $this->connectionWarnings);
|
108 |
-
throw new HTTP_Request2_ConnectionException(
|
109 |
-
"Unable to connect to {$address}. Error: {$error}", 0, $errno
|
110 |
-
);
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
/**
|
115 |
-
* Destructor, disconnects socket
|
116 |
-
*/
|
117 |
-
public function __destruct()
|
118 |
-
{
|
119 |
-
fclose($this->socket);
|
120 |
-
}
|
121 |
-
|
122 |
-
/**
|
123 |
-
* Wrapper around fread(), handles global request timeout
|
124 |
-
*
|
125 |
-
* @param int $length Reads up to this number of bytes
|
126 |
-
*
|
127 |
-
* @return string Data read from socket
|
128 |
-
* @throws HTTP_Request2_MessageException In case of timeout
|
129 |
-
*/
|
130 |
-
public function read($length)
|
131 |
-
{
|
132 |
-
if ($this->deadline) {
|
133 |
-
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
|
134 |
-
}
|
135 |
-
$data = fread($this->socket, $length);
|
136 |
-
$this->checkTimeout();
|
137 |
-
return $data;
|
138 |
-
}
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Reads until either the end of the socket or a newline, whichever comes first
|
142 |
-
*
|
143 |
-
* Strips the trailing newline from the returned data, handles global
|
144 |
-
* request timeout. Method idea borrowed from Net_Socket PEAR package.
|
145 |
-
*
|
146 |
-
* @param int $bufferSize buffer size to use for reading
|
147 |
-
* @param int $localTimeout timeout value to use just for this call
|
148 |
-
* (used when waiting for "100 Continue" response)
|
149 |
-
*
|
150 |
-
* @return string Available data up to the newline (not including newline)
|
151 |
-
* @throws HTTP_Request2_MessageException In case of timeout
|
152 |
-
*/
|
153 |
-
public function readLine($bufferSize, $localTimeout = null)
|
154 |
-
{
|
155 |
-
$line = '';
|
156 |
-
while (!feof($this->socket)) {
|
157 |
-
if (null !== $localTimeout) {
|
158 |
-
stream_set_timeout($this->socket, $localTimeout);
|
159 |
-
} elseif ($this->deadline) {
|
160 |
-
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
|
161 |
-
}
|
162 |
-
|
163 |
-
$line .= @fgets($this->socket, $bufferSize);
|
164 |
-
|
165 |
-
if (null === $localTimeout) {
|
166 |
-
$this->checkTimeout();
|
167 |
-
|
168 |
-
} else {
|
169 |
-
$info = stream_get_meta_data($this->socket);
|
170 |
-
// reset socket timeout if we don't have request timeout specified,
|
171 |
-
// prevents further calls failing with a bogus Exception
|
172 |
-
if (!$this->deadline) {
|
173 |
-
$default = (int)@ini_get('default_socket_timeout');
|
174 |
-
stream_set_timeout($this->socket, $default > 0 ? $default : PHP_INT_MAX);
|
175 |
-
}
|
176 |
-
if ($info['timed_out']) {
|
177 |
-
throw new HTTP_Request2_MessageException(
|
178 |
-
"readLine() call timed out", HTTP_Request2_Exception::TIMEOUT
|
179 |
-
);
|
180 |
-
}
|
181 |
-
}
|
182 |
-
if (substr($line, -1) == "\n") {
|
183 |
-
return rtrim($line, "\r\n");
|
184 |
-
}
|
185 |
-
}
|
186 |
-
return $line;
|
187 |
-
}
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Wrapper around fwrite(), handles global request timeout
|
191 |
-
*
|
192 |
-
* @param string $data String to be written
|
193 |
-
*
|
194 |
-
* @return int
|
195 |
-
* @throws HTTP_Request2_MessageException
|
196 |
-
*/
|
197 |
-
public function write($data)
|
198 |
-
{
|
199 |
-
if ($this->deadline) {
|
200 |
-
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
|
201 |
-
}
|
202 |
-
$written = fwrite($this->socket, $data);
|
203 |
-
$this->checkTimeout();
|
204 |
-
// http://www.php.net/manual/en/function.fwrite.php#96951
|
205 |
-
if ($written < strlen($data)) {
|
206 |
-
throw new HTTP_Request2_MessageException('Error writing request');
|
207 |
-
}
|
208 |
-
return $written;
|
209 |
-
}
|
210 |
-
|
211 |
-
/**
|
212 |
-
* Tests for end-of-file on a socket
|
213 |
-
*
|
214 |
-
* @return bool
|
215 |
-
*/
|
216 |
-
public function eof()
|
217 |
-
{
|
218 |
-
return feof($this->socket);
|
219 |
-
}
|
220 |
-
|
221 |
-
/**
|
222 |
-
* Sets request deadline
|
223 |
-
*
|
224 |
-
* @param int $deadline Exception will be thrown if request continues
|
225 |
-
* past this time
|
226 |
-
* @param int $timeout Original request timeout value, to use in
|
227 |
-
* Exception message
|
228 |
-
*/
|
229 |
-
public function setDeadline($deadline, $timeout)
|
230 |
-
{
|
231 |
-
$this->deadline = $deadline;
|
232 |
-
$this->timeout = $timeout;
|
233 |
-
}
|
234 |
-
|
235 |
-
/**
|
236 |
-
* Turns on encryption on a socket
|
237 |
-
*
|
238 |
-
* @throws HTTP_Request2_ConnectionException
|
239 |
-
*/
|
240 |
-
public function enableCrypto()
|
241 |
-
{
|
242 |
-
$modes = array(
|
243 |
-
STREAM_CRYPTO_METHOD_TLS_CLIENT,
|
244 |
-
STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
|
245 |
-
STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
|
246 |
-
STREAM_CRYPTO_METHOD_SSLv2_CLIENT
|
247 |
-
);
|
248 |
-
|
249 |
-
foreach ($modes as $mode) {
|
250 |
-
if (stream_socket_enable_crypto($this->socket, true, $mode)) {
|
251 |
-
return;
|
252 |
-
}
|
253 |
-
}
|
254 |
-
throw new HTTP_Request2_ConnectionException(
|
255 |
-
'Failed to enable secure connection when connecting through proxy'
|
256 |
-
);
|
257 |
-
}
|
258 |
-
|
259 |
-
/**
|
260 |
-
* Throws an Exception if stream timed out
|
261 |
-
*
|
262 |
-
* @throws HTTP_Request2_MessageException
|
263 |
-
*/
|
264 |
-
protected function checkTimeout()
|
265 |
-
{
|
266 |
-
$info = stream_get_meta_data($this->socket);
|
267 |
-
if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
|
268 |
-
$reason = $this->deadline
|
269 |
-
? "after {$this->timeout} second(s)"
|
270 |
-
: 'due to default_socket_timeout php.ini setting';
|
271 |
-
throw new HTTP_Request2_MessageException(
|
272 |
-
"Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
|
273 |
-
);
|
274 |
-
}
|
275 |
-
}
|
276 |
-
|
277 |
-
/**
|
278 |
-
* Error handler to use during stream_socket_client() call
|
279 |
-
*
|
280 |
-
* One stream_socket_client() call may produce *multiple* PHP warnings
|
281 |
-
* (especially OpenSSL-related), we keep them in an array to later use for
|
282 |
-
* the message of HTTP_Request2_ConnectionException
|
283 |
-
*
|
284 |
-
* @param int $errno error level
|
285 |
-
* @param string $errstr error message
|
286 |
-
*
|
287 |
-
* @return bool
|
288 |
-
*/
|
289 |
-
protected function connectionWarningsHandler($errno, $errstr)
|
290 |
-
{
|
291 |
-
if ($errno & E_WARNING) {
|
292 |
-
array_unshift($this->connectionWarnings, $errstr);
|
293 |
-
}
|
294 |
-
return true;
|
295 |
-
}
|
296 |
-
}
|
297 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Socket wrapper class used by Socket Adapter
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* LICENSE
|
8 |
+
*
|
9 |
+
* This source file is subject to BSD 3-Clause License that is bundled
|
10 |
+
* with this package in the file LICENSE and available at the URL
|
11 |
+
* https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE
|
12 |
+
*
|
13 |
+
* @category HTTP
|
14 |
+
* @package HTTP_Request2
|
15 |
+
* @author Alexey Borzov <avb@php.net>
|
16 |
+
* @copyright 2008-2014 Alexey Borzov <avb@php.net>
|
17 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
18 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
19 |
+
*/
|
20 |
+
|
21 |
+
/** Exception classes for HTTP_Request2 package */
|
22 |
+
require_once 'HTTP/Request2/Exception.php';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Socket wrapper class used by Socket Adapter
|
26 |
+
*
|
27 |
+
* Needed to properly handle connection errors, global timeout support and
|
28 |
+
* similar things. Loosely based on Net_Socket used by older HTTP_Request.
|
29 |
+
*
|
30 |
+
* @category HTTP
|
31 |
+
* @package HTTP_Request2
|
32 |
+
* @author Alexey Borzov <avb@php.net>
|
33 |
+
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
|
34 |
+
* @version Release: 2.2.1
|
35 |
+
* @link http://pear.php.net/package/HTTP_Request2
|
36 |
+
* @link http://pear.php.net/bugs/bug.php?id=19332
|
37 |
+
* @link http://tools.ietf.org/html/rfc1928
|
38 |
+
*/
|
39 |
+
class HTTP_Request2_SocketWrapper
|
40 |
+
{
|
41 |
+
/**
|
42 |
+
* PHP warning messages raised during stream_socket_client() call
|
43 |
+
* @var array
|
44 |
+
*/
|
45 |
+
protected $connectionWarnings = array();
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Connected socket
|
49 |
+
* @var resource
|
50 |
+
*/
|
51 |
+
protected $socket;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Sum of start time and global timeout, exception will be thrown if request continues past this time
|
55 |
+
* @var integer
|
56 |
+
*/
|
57 |
+
protected $deadline;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Global timeout value, mostly for exception messages
|
61 |
+
* @var integer
|
62 |
+
*/
|
63 |
+
protected $timeout;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Class constructor, tries to establish connection
|
67 |
+
*
|
68 |
+
* @param string $address Address for stream_socket_client() call,
|
69 |
+
* e.g. 'tcp://localhost:80'
|
70 |
+
* @param int $timeout Connection timeout (seconds)
|
71 |
+
* @param array $contextOptions Context options
|
72 |
+
*
|
73 |
+
* @throws HTTP_Request2_LogicException
|
74 |
+
* @throws HTTP_Request2_ConnectionException
|
75 |
+
*/
|
76 |
+
public function __construct($address, $timeout, array $contextOptions = array())
|
77 |
+
{
|
78 |
+
if (!empty($contextOptions)
|
79 |
+
&& !isset($contextOptions['socket']) && !isset($contextOptions['ssl'])
|
80 |
+
) {
|
81 |
+
// Backwards compatibility with 2.1.0 and 2.1.1 releases
|
82 |
+
$contextOptions = array('ssl' => $contextOptions);
|
83 |
+
}
|
84 |
+
$context = stream_context_create();
|
85 |
+
foreach ($contextOptions as $wrapper => $options) {
|
86 |
+
foreach ($options as $name => $value) {
|
87 |
+
if (!stream_context_set_option($context, $wrapper, $name, $value)) {
|
88 |
+
throw new HTTP_Request2_LogicException(
|
89 |
+
"Error setting '{$wrapper}' wrapper context option '{$name}'"
|
90 |
+
);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
set_error_handler(array($this, 'connectionWarningsHandler'));
|
95 |
+
$this->socket = stream_socket_client(
|
96 |
+
$address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context
|
97 |
+
);
|
98 |
+
restore_error_handler();
|
99 |
+
// if we fail to bind to a specified local address (see request #19515),
|
100 |
+
// connection still succeeds, albeit with a warning. Throw an Exception
|
101 |
+
// with the warning text in this case as that connection is unlikely
|
102 |
+
// to be what user wants and as Curl throws an error in similar case.
|
103 |
+
if ($this->connectionWarnings) {
|
104 |
+
if ($this->socket) {
|
105 |
+
fclose($this->socket);
|
106 |
+
}
|
107 |
+
$error = $errstr ? $errstr : implode("\n", $this->connectionWarnings);
|
108 |
+
throw new HTTP_Request2_ConnectionException(
|
109 |
+
"Unable to connect to {$address}. Error: {$error}", 0, $errno
|
110 |
+
);
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Destructor, disconnects socket
|
116 |
+
*/
|
117 |
+
public function __destruct()
|
118 |
+
{
|
119 |
+
fclose($this->socket);
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Wrapper around fread(), handles global request timeout
|
124 |
+
*
|
125 |
+
* @param int $length Reads up to this number of bytes
|
126 |
+
*
|
127 |
+
* @return string Data read from socket
|
128 |
+
* @throws HTTP_Request2_MessageException In case of timeout
|
129 |
+
*/
|
130 |
+
public function read($length)
|
131 |
+
{
|
132 |
+
if ($this->deadline) {
|
133 |
+
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
|
134 |
+
}
|
135 |
+
$data = fread($this->socket, $length);
|
136 |
+
$this->checkTimeout();
|
137 |
+
return $data;
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Reads until either the end of the socket or a newline, whichever comes first
|
142 |
+
*
|
143 |
+
* Strips the trailing newline from the returned data, handles global
|
144 |
+
* request timeout. Method idea borrowed from Net_Socket PEAR package.
|
145 |
+
*
|
146 |
+
* @param int $bufferSize buffer size to use for reading
|
147 |
+
* @param int $localTimeout timeout value to use just for this call
|
148 |
+
* (used when waiting for "100 Continue" response)
|
149 |
+
*
|
150 |
+
* @return string Available data up to the newline (not including newline)
|
151 |
+
* @throws HTTP_Request2_MessageException In case of timeout
|
152 |
+
*/
|
153 |
+
public function readLine($bufferSize, $localTimeout = null)
|
154 |
+
{
|
155 |
+
$line = '';
|
156 |
+
while (!feof($this->socket)) {
|
157 |
+
if (null !== $localTimeout) {
|
158 |
+
stream_set_timeout($this->socket, $localTimeout);
|
159 |
+
} elseif ($this->deadline) {
|
160 |
+
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
|
161 |
+
}
|
162 |
+
|
163 |
+
$line .= @fgets($this->socket, $bufferSize);
|
164 |
+
|
165 |
+
if (null === $localTimeout) {
|
166 |
+
$this->checkTimeout();
|
167 |
+
|
168 |
+
} else {
|
169 |
+
$info = stream_get_meta_data($this->socket);
|
170 |
+
// reset socket timeout if we don't have request timeout specified,
|
171 |
+
// prevents further calls failing with a bogus Exception
|
172 |
+
if (!$this->deadline) {
|
173 |
+
$default = (int)@ini_get('default_socket_timeout');
|
174 |
+
stream_set_timeout($this->socket, $default > 0 ? $default : PHP_INT_MAX);
|
175 |
+
}
|
176 |
+
if ($info['timed_out']) {
|
177 |
+
throw new HTTP_Request2_MessageException(
|
178 |
+
"readLine() call timed out", HTTP_Request2_Exception::TIMEOUT
|
179 |
+
);
|
180 |
+
}
|
181 |
+
}
|
182 |
+
if (substr($line, -1) == "\n") {
|
183 |
+
return rtrim($line, "\r\n");
|
184 |
+
}
|
185 |
+
}
|
186 |
+
return $line;
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Wrapper around fwrite(), handles global request timeout
|
191 |
+
*
|
192 |
+
* @param string $data String to be written
|
193 |
+
*
|
194 |
+
* @return int
|
195 |
+
* @throws HTTP_Request2_MessageException
|
196 |
+
*/
|
197 |
+
public function write($data)
|
198 |
+
{
|
199 |
+
if ($this->deadline) {
|
200 |
+
stream_set_timeout($this->socket, max($this->deadline - time(), 1));
|
201 |
+
}
|
202 |
+
$written = fwrite($this->socket, $data);
|
203 |
+
$this->checkTimeout();
|
204 |
+
// http://www.php.net/manual/en/function.fwrite.php#96951
|
205 |
+
if ($written < strlen($data)) {
|
206 |
+
throw new HTTP_Request2_MessageException('Error writing request');
|
207 |
+
}
|
208 |
+
return $written;
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Tests for end-of-file on a socket
|
213 |
+
*
|
214 |
+
* @return bool
|
215 |
+
*/
|
216 |
+
public function eof()
|
217 |
+
{
|
218 |
+
return feof($this->socket);
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Sets request deadline
|
223 |
+
*
|
224 |
+
* @param int $deadline Exception will be thrown if request continues
|
225 |
+
* past this time
|
226 |
+
* @param int $timeout Original request timeout value, to use in
|
227 |
+
* Exception message
|
228 |
+
*/
|
229 |
+
public function setDeadline($deadline, $timeout)
|
230 |
+
{
|
231 |
+
$this->deadline = $deadline;
|
232 |
+
$this->timeout = $timeout;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Turns on encryption on a socket
|
237 |
+
*
|
238 |
+
* @throws HTTP_Request2_ConnectionException
|
239 |
+
*/
|
240 |
+
public function enableCrypto()
|
241 |
+
{
|
242 |
+
$modes = array(
|
243 |
+
STREAM_CRYPTO_METHOD_TLS_CLIENT,
|
244 |
+
STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
|
245 |
+
STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
|
246 |
+
STREAM_CRYPTO_METHOD_SSLv2_CLIENT
|
247 |
+
);
|
248 |
+
|
249 |
+
foreach ($modes as $mode) {
|
250 |
+
if (stream_socket_enable_crypto($this->socket, true, $mode)) {
|
251 |
+
return;
|
252 |
+
}
|
253 |
+
}
|
254 |
+
throw new HTTP_Request2_ConnectionException(
|
255 |
+
'Failed to enable secure connection when connecting through proxy'
|
256 |
+
);
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Throws an Exception if stream timed out
|
261 |
+
*
|
262 |
+
* @throws HTTP_Request2_MessageException
|
263 |
+
*/
|
264 |
+
protected function checkTimeout()
|
265 |
+
{
|
266 |
+
$info = stream_get_meta_data($this->socket);
|
267 |
+
if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
|
268 |
+
$reason = $this->deadline
|
269 |
+
? "after {$this->timeout} second(s)"
|
270 |
+
: 'due to default_socket_timeout php.ini setting';
|
271 |
+
throw new HTTP_Request2_MessageException(
|
272 |
+
"Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
|
273 |
+
);
|
274 |
+
}
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* Error handler to use during stream_socket_client() call
|
279 |
+
*
|
280 |
+
* One stream_socket_client() call may produce *multiple* PHP warnings
|
281 |
+
* (especially OpenSSL-related), we keep them in an array to later use for
|
282 |
+
* the message of HTTP_Request2_ConnectionException
|
283 |
+
*
|
284 |
+
* @param int $errno error level
|
285 |
+
* @param string $errstr error message
|
286 |
+
*
|
287 |
+
* @return bool
|
288 |
+
*/
|
289 |
+
protected function connectionWarningsHandler($errno, $errstr)
|
290 |
+
{
|
291 |
+
if ($errno & E_WARNING) {
|
292 |
+
array_unshift($this->connectionWarnings, $errstr);
|
293 |
+
}
|
294 |
+
return true;
|
295 |
+
}
|
296 |
+
}
|
297 |
+
?>
|