BackUpWordPress - Version 3.3.0

Version Description

= 3.2.5 =

  • Security fixes related to add_query_arg

= 3.2.1 =

  • Important bug fixes. Please upgrade to this version to avoid incomplete or broken backups.

= 3.1.3 =

  • Fixes backwards compatibility for add-ons and avoids a Fatal Error. Please upgrade straight to this version before upgrading your add-ons.

= 3.0.4 =

  • Fixes a few minor bugs. Immediate update is recommended.

= 3.0.2 =

  • Important: we have dropped support for PHP 5.2, you will not be able to activate BackUpWordPress on a server running PHP versions older than PHP 5.3.29

= 3.0.1 =

  • This is a critical update. Fixes a bug in the core backup library. Please update immediately.
Download this release

Release Info

Developer pauldewouters
Plugin Icon 128x128 BackUpWordPress
Version 3.3.0
Comparing to
See all releases

Code changes from version 3.2.7 to 3.3.0

Files changed (131) hide show
  1. admin/actions.php +6 -6
  2. admin/backups.php +0 -12
  3. admin/enable-support.php +2 -2
  4. admin/faq.php +5 -5
  5. admin/menu.php +1 -4
  6. admin/page.php +12 -0
  7. admin/schedule-form-excludes.php +75 -68
  8. admin/schedule-form.php +6 -3
  9. admin/schedule-sentence.php +9 -11
  10. admin/server-info.php +1 -1
  11. assets/hmbkp.css +4 -6
  12. assets/hmbkp.js +160 -159
  13. assets/hmbkp.min.css +1 -1
  14. assets/hmbkp.min.js +1 -1
  15. backdrop/task.php +2 -2
  16. backupwordpress.php +3 -3
  17. changelog.txt +0 -5
  18. classes/class-backup.php +1362 -1475
  19. classes/class-backupwordpress-wp-cli-command.php +1 -1
  20. classes/class-email-service.php +2 -2
  21. classes/class-path.php +4 -2
  22. classes/class-plugin.php +3 -3
  23. classes/class-schedule.php +20 -29
  24. classes/class-service.php +9 -3
  25. classes/deprecated.php +1 -1
  26. composer.json +24 -0
  27. composer.lock +67 -0
  28. functions/core.php +44 -51
  29. functions/interface.php +35 -14
  30. languages/backupwordpress-en_AU.mo +0 -0
  31. languages/backupwordpress-en_AU.po +1211 -0
  32. languages/backupwordpress-en_GB.mo +0 -0
  33. languages/backupwordpress-en_GB.po +1211 -0
  34. languages/backupwordpress.pot +397 -266
  35. phpunit.xml +25 -0
  36. readme.md +52 -0
  37. readme.txt +20 -8
  38. vendor/autoload.php +1 -1
  39. vendor/composer/ClassLoader.php +35 -1
  40. vendor/composer/LICENSE +21 -0
  41. vendor/composer/autoload_namespaces.php +0 -1
  42. vendor/composer/autoload_psr4.php +1 -0
  43. vendor/composer/autoload_real.php +4 -4
  44. vendor/composer/installed.json +17 -15
  45. vendor/symfony/finder/Adapter/AbstractAdapter.php +236 -0
  46. vendor/symfony/finder/Adapter/AbstractFindAdapter.php +327 -0
  47. vendor/symfony/finder/Adapter/AdapterInterface.php +144 -0
  48. vendor/symfony/finder/Adapter/BsdFindAdapter.php +103 -0
  49. vendor/symfony/finder/Adapter/GnuFindAdapter.php +104 -0
  50. vendor/symfony/finder/Adapter/PhpAdapter.php +98 -0
  51. vendor/symfony/finder/CHANGELOG.md +34 -0
  52. vendor/symfony/finder/Comparator/Comparator.php +98 -0
  53. vendor/symfony/finder/Comparator/DateComparator.php +53 -0
  54. vendor/symfony/finder/Comparator/NumberComparator.php +81 -0
  55. vendor/symfony/finder/Exception/AccessDeniedException.php +19 -0
  56. vendor/symfony/finder/Exception/AdapterFailureException.php +46 -0
  57. vendor/symfony/finder/Exception/ExceptionInterface.php +23 -0
  58. vendor/symfony/finder/Exception/OperationNotPermitedException.php +19 -0
  59. vendor/symfony/finder/Exception/ShellCommandFailureException.php +45 -0
  60. vendor/symfony/finder/Expression/Expression.php +146 -0
  61. vendor/symfony/finder/Expression/Glob.php +109 -0
  62. vendor/symfony/finder/Expression/Regex.php +321 -0
  63. vendor/symfony/finder/Expression/ValueInterface.php +60 -0
  64. vendor/symfony/finder/Finder.php +840 -0
  65. vendor/symfony/finder/Glob.php +104 -0
  66. vendor/symfony/finder/Iterator/CustomFilterIterator.php +63 -0
  67. vendor/symfony/finder/Iterator/DateRangeFilterIterator.php +60 -0
  68. vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php +47 -0
  69. vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php +55 -0
  70. vendor/symfony/finder/Iterator/FilePathsIterator.php +131 -0
  71. vendor/symfony/finder/Iterator/FileTypeFilterIterator.php +55 -0
  72. vendor/symfony/finder/Iterator/FilecontentFilterIterator.php +76 -0
  73. vendor/symfony/finder/Iterator/FilenameFilterIterator.php +67 -0
  74. vendor/symfony/finder/Iterator/FilterIterator.php +49 -0
  75. vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php +66 -0
  76. vendor/symfony/finder/Iterator/PathFilterIterator.php +74 -0
  77. vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php +126 -0
  78. vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php +59 -0
  79. vendor/symfony/finder/Iterator/SortableIterator.php +82 -0
  80. vendor/symfony/finder/LICENSE +19 -0
  81. vendor/symfony/finder/Shell/Command.php +294 -0
  82. vendor/symfony/finder/Shell/Shell.php +97 -0
  83. vendor/symfony/finder/SplFileInfo.php +77 -0
  84. vendor/symfony/finder/Tests/Comparator/ComparatorTest.php +64 -0
  85. vendor/symfony/finder/Tests/Comparator/DateComparatorTest.php +63 -0
  86. vendor/symfony/finder/Tests/Comparator/NumberComparatorTest.php +107 -0
  87. vendor/symfony/finder/Tests/Expression/ExpressionTest.php +68 -0
  88. vendor/symfony/finder/Tests/Expression/GlobTest.php +47 -0
  89. vendor/symfony/finder/Tests/Expression/RegexTest.php +143 -0
  90. vendor/symfony/finder/Tests/FakeAdapter/DummyAdapter.php +57 -0
  91. vendor/symfony/finder/Tests/FakeAdapter/FailingAdapter.php +45 -0
  92. vendor/symfony/finder/Tests/FakeAdapter/NamedAdapter.php +57 -0
  93. vendor/symfony/finder/Tests/FakeAdapter/UnsupportedAdapter.php +44 -0
  94. vendor/symfony/finder/Tests/FinderTest.php +866 -0
  95. vendor/symfony/finder/Tests/Fixtures/A/B/C/abc.dat +0 -0
  96. vendor/symfony/finder/Tests/Fixtures/A/B/ab.dat +0 -0
  97. vendor/symfony/finder/Tests/Fixtures/A/a.dat +0 -0
  98. vendor/symfony/finder/Tests/Fixtures/copy/A/B/C/abc.dat.copy +0 -0
  99. vendor/symfony/finder/Tests/Fixtures/copy/A/B/ab.dat.copy +0 -0
  100. vendor/symfony/finder/Tests/Fixtures/copy/A/a.dat.copy +0 -0
  101. vendor/symfony/finder/Tests/Fixtures/dolor.txt +2 -0
  102. vendor/symfony/finder/Tests/Fixtures/ipsum.txt +2 -0
  103. vendor/symfony/finder/Tests/Fixtures/lorem.txt +2 -0
  104. vendor/symfony/finder/Tests/Fixtures/one/a +0 -0
  105. vendor/symfony/finder/Tests/Fixtures/one/b/c.neon +0 -0
  106. vendor/symfony/finder/Tests/Fixtures/one/b/d.neon +0 -0
  107. vendor/symfony/finder/Tests/Fixtures/r+e.gex[c]a(r)s/dir/bar.dat +0 -0
  108. vendor/symfony/finder/Tests/Fixtures/with space/foo.txt +0 -0
  109. vendor/symfony/finder/Tests/GlobTest.php +24 -0
  110. vendor/symfony/finder/Tests/Iterator/CustomFilterIteratorTest.php +46 -0
  111. vendor/symfony/finder/Tests/Iterator/DateRangeFilterIteratorTest.php +72 -0
  112. vendor/symfony/finder/Tests/Iterator/DepthRangeFilterIteratorTest.php +80 -0
  113. vendor/symfony/finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php +64 -0
  114. vendor/symfony/finder/Tests/Iterator/FilePathsIteratorTest.php +69 -0
  115. vendor/symfony/finder/Tests/Iterator/FileTypeFilterIteratorTest.php +72 -0
  116. vendor/symfony/finder/Tests/Iterator/FilecontentFilterIteratorTest.php +86 -0
  117. vendor/symfony/finder/Tests/Iterator/FilenameFilterIteratorTest.php +54 -0
  118. vendor/symfony/finder/Tests/Iterator/FilterIteratorTest.php +50 -0
  119. vendor/symfony/finder/Tests/Iterator/Iterator.php +55 -0
  120. vendor/symfony/finder/Tests/Iterator/IteratorTestCase.php +98 -0
  121. vendor/symfony/finder/Tests/Iterator/MockFileListIterator.php +21 -0
  122. vendor/symfony/finder/Tests/Iterator/MockSplFileInfo.php +134 -0
  123. vendor/symfony/finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php +67 -0
  124. vendor/symfony/finder/Tests/Iterator/PathFilterIteratorTest.php +83 -0
  125. vendor/symfony/finder/Tests/Iterator/RealIteratorTestCase.php +109 -0
  126. vendor/symfony/finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php +83 -0
  127. vendor/symfony/finder/Tests/Iterator/SizeRangeFilterIteratorTest.php +68 -0
  128. vendor/symfony/finder/Tests/Iterator/SortableIteratorTest.php +169 -0
  129. vendor/symfony/finder/Tests/Shell/CommandTest.php +162 -0
  130. vendor/symfony/finder/composer.json +33 -0
  131. vendor/symfony/finder/phpunit.xml.dist +28 -0
admin/actions.php CHANGED
@@ -76,7 +76,7 @@ function hmbkp_request_do_backup() {
76
 
77
  // Fixes an issue on servers which only allow a single session per client
78
  session_write_close();
79
-
80
  $schedule_id = sanitize_text_field( urldecode( $_POST['hmbkp_schedule_id'] ) );
81
  $task = new \HM\Backdrop\Task( 'hmbkp_run_schedule_async', $schedule_id );
82
  $task->schedule();
@@ -114,7 +114,7 @@ function hmbkp_request_download_backup() {
114
  return;
115
  }
116
 
117
- $url = str_replace( HM\BackUpWordPress\Backup::conform_dir( HM\BackUpWordPress\Backup::get_home_path() ), home_url(), trailingslashit( dirname( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ) ) ) ) . urlencode( pathinfo( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ), PATHINFO_BASENAME ) );
118
 
119
  global $is_apache;
120
 
@@ -259,7 +259,7 @@ function hmbkp_edit_schedule_submit() {
259
  $errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Schedule cannot be empty', 'backupwordpress' );
260
  }
261
 
262
- elseif ( ! in_array( $schedule_recurrence_type, array_keys( hmbkp_get_cron_schedules() ) ) && 'manually' !== $schedule_recurrence_type ) {
263
  $errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Invalid schedule', 'backupwordpress' );
264
  }
265
 
@@ -274,7 +274,7 @@ function hmbkp_edit_schedule_submit() {
274
  $day_of_week = sanitize_text_field( $_POST['hmbkp_schedule_recurrence']['hmbkp_schedule_start_day_of_week'] );
275
 
276
  if ( ! in_array( $day_of_week, array( 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' ) ) ) {
277
- $errors['hmbkp_schedule_start_day_of_week'] = __( 'Day of the week must be a valid lowercase day name', 'backupwordpress' );
278
  }
279
 
280
  else {
@@ -283,7 +283,7 @@ function hmbkp_edit_schedule_submit() {
283
 
284
  }
285
 
286
- if ( ( 'hmbkp_monthly' === $schedule_recurrence_type ) && isset( $_POST['hmbkp_schedule_recurrence']['hmbkp_schedule_start_day_of_month'] ) ) {
287
 
288
  $day_of_month = absint( $_POST['hmbkp_schedule_recurrence']['hmbkp_schedule_start_day_of_month'] );
289
 
@@ -711,7 +711,7 @@ function hmbkp_ajax_cron_test() {
711
 
712
  } elseif ( ! in_array( 200, array_map( 'wp_remote_retrieve_response_code', array( $response1, $response2, $response3 ) ) ) ) {
713
 
714
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'backupwordpress' ) . '</strong> ' . sprintf( __( '%1$s is returning a %2$s response which could mean cron jobs aren\'t getting fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. See the %3$s for more details.', 'backupwordpress' ), '<code>wp-cron.php</code>', '<code>' . esc_html( wp_remote_retrieve_response_code( $response1 ) ) . ' ' . esc_html( get_status_header_desc( wp_remote_retrieve_response_code( $response1 ) ) ) . '</code>', '<a href="http://wordpress.org/extend/plugins/backupwordpress/faq/">FAQ</a>' ) . '</p></div>';
715
 
716
  update_option( 'hmbkp_wp_cron_test_failed', true );
717
 
76
 
77
  // Fixes an issue on servers which only allow a single session per client
78
  session_write_close();
79
+
80
  $schedule_id = sanitize_text_field( urldecode( $_POST['hmbkp_schedule_id'] ) );
81
  $task = new \HM\Backdrop\Task( 'hmbkp_run_schedule_async', $schedule_id );
82
  $task->schedule();
114
  return;
115
  }
116
 
117
+ $url = str_replace( wp_normalize_path( HM\BackUpWordPress\Backup::get_home_path() ), home_url(), trailingslashit( dirname( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ) ) ) ) . urlencode( pathinfo( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ), PATHINFO_BASENAME ) );
118
 
119
  global $is_apache;
120
 
259
  $errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Schedule cannot be empty', 'backupwordpress' );
260
  }
261
 
262
+ elseif ( ! in_array( $schedule_recurrence_type, array_keys( hmbkp_cron_schedules() ) ) && 'manually' !== $schedule_recurrence_type ) {
263
  $errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Invalid schedule', 'backupwordpress' );
264
  }
265
 
274
  $day_of_week = sanitize_text_field( $_POST['hmbkp_schedule_recurrence']['hmbkp_schedule_start_day_of_week'] );
275
 
276
  if ( ! in_array( $day_of_week, array( 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' ) ) ) {
277
+ $errors['hmbkp_schedule_start_day_of_week'] = __( 'Day of the week must be a valid, lowercase day name', 'backupwordpress' );
278
  }
279
 
280
  else {
283
 
284
  }
285
 
286
+ if ( ( 'monthly' === $schedule_recurrence_type ) && isset( $_POST['hmbkp_schedule_recurrence']['hmbkp_schedule_start_day_of_month'] ) ) {
287
 
288
  $day_of_month = absint( $_POST['hmbkp_schedule_recurrence']['hmbkp_schedule_start_day_of_month'] );
289
 
711
 
712
  } elseif ( ! in_array( 200, array_map( 'wp_remote_retrieve_response_code', array( $response1, $response2, $response3 ) ) ) ) {
713
 
714
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'backupwordpress' ) . '</strong> ' . sprintf( __( '%1$s is returning a %2$s response which could mean cron jobs aren\'t getting fired properly. BackUpWordPress relies on wp-cron to run scheduled backups, and more generally relies on HTTP loopback connections not being blocked for manual backups. See the %3$s for more details.', 'backupwordpress' ), '<code>wp-cron.php</code>', '<code>' . esc_html( wp_remote_retrieve_response_code( $response1 ) ) . ' ' . esc_html( get_status_header_desc( wp_remote_retrieve_response_code( $response1 ) ) ) . '</code>', '<a href="http://wordpress.org/extend/plugins/backupwordpress/faq/">FAQ</a>' ) . '</p></div>';
715
 
716
  update_option( 'hmbkp_wp_cron_test_failed', true );
717
 
admin/backups.php CHANGED
@@ -21,18 +21,6 @@ if ( ! empty( $_GET['hmbkp_schedule_id'] ) ) {
21
 
22
  <a class="nav-tab<?php if ( ! HM\BackUpWordPress\Schedules::get_instance()->get_schedule( $current_schedule->get_id() ) ) { ?> nav-tab-active<?php } ?>" href="<?php echo esc_url( add_query_arg( array( 'hmbkp_add_schedule' => '1', 'action' => 'hmbkp_edit_schedule', 'hmbkp_schedule_id' => time(), 'hmbkp_panel' => 'hmbkp_edit_schedule_settings' ), HMBKP_ADMIN_URL ) ); ?>"> + <?php _e( 'add schedule', 'backupwordpress' ); ?></a>
23
 
24
- <?php if ( get_option( 'hmbkp_enable_support' ) ) { ?>
25
-
26
- <a id="intercom" class="add-new-h2" href="mailto:backupwordpress@hmn.md"><?php _e( 'Support', 'backupwordpress' ); ?></a>
27
-
28
- <?php } else {
29
-
30
- add_thickbox(); ?>
31
-
32
- <a id="intercom-info" class="thickbox add-new-h2" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'load_enable_support', 'width' => '600', 'height' => '420' ), self_admin_url( 'admin-ajax.php' ) ), 'hmbkp_nonce' ) ); ?>"><span class="dashicons dashicons-admin-users"></span>&nbsp;<?php _e( 'Enable Support', 'backupwordpress' ); ?></a>
33
-
34
- <?php } ?>
35
-
36
  </h2>
37
 
38
  <?php // Don't continue if we don't have a schedule
21
 
22
  <a class="nav-tab<?php if ( ! HM\BackUpWordPress\Schedules::get_instance()->get_schedule( $current_schedule->get_id() ) ) { ?> nav-tab-active<?php } ?>" href="<?php echo esc_url( add_query_arg( array( 'hmbkp_add_schedule' => '1', 'action' => 'hmbkp_edit_schedule', 'hmbkp_schedule_id' => time(), 'hmbkp_panel' => 'hmbkp_edit_schedule_settings' ), HMBKP_ADMIN_URL ) ); ?>"> + <?php _e( 'add schedule', 'backupwordpress' ); ?></a>
23
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  </h2>
25
 
26
  <?php // Don't continue if we don't have a schedule
admin/enable-support.php CHANGED
@@ -57,5 +57,5 @@
57
 
58
  <p class="howto"><?php _e( 'You can disable support in the future by deactivating BackUpWordPress.', 'backupwordpress' ); ?></p>
59
 
60
- <a href="#" class="button-secondary hmbkp-thickbox-close"><?php _e( 'No thanks', 'backupwordpress' ); ?></a>
61
- <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_request_enable_support' ), admin_url( 'admin-post.php' ) ), 'hmbkp_enable_support', 'hmbkp_enable_support_nonce' ) ); ?>" class="button-primary right"><?php _e( 'Yes I want to enable support', 'backupwordpress' ); ?></a>
57
 
58
  <p class="howto"><?php _e( 'You can disable support in the future by deactivating BackUpWordPress.', 'backupwordpress' ); ?></p>
59
 
60
+ <a href="#" class="button-secondary hmbkp-thickbox-close"><?php _e( 'No, thanks', 'backupwordpress' ); ?></a>
61
+ <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_request_enable_support' ), admin_url( 'admin-post.php' ) ), 'hmbkp_enable_support', 'hmbkp_enable_support_nonce' ) ); ?>" class="button-primary right"><?php _e( 'Yes, I want to enable support', 'backupwordpress' ); ?></a>
admin/faq.php CHANGED
@@ -19,7 +19,7 @@ echo '<p><strong>' . __( 'Where does BackUpWordPress store the backup files?', '
19
 
20
  '<p>' . __( 'No.', 'backupwordpress' ) . '</p>' .
21
 
22
- '<p><strong>' . __( 'I\'m not receiving my backups by email?', 'backupwordpress' ) . '</strong></p>' .
23
 
24
  '<p>' . __( 'Most servers have a filesize limit on email attachments, it\'s generally about 10mb. If your backup file is over that limit it won\'t be sent attached to the email, instead you should receive an email with a link to download the backup, if you aren\'t even receiving that then you likely have a mail issue on your server that you\'ll need to contact your host about.', 'backupwordpress' ) . '</p>' .
25
 
@@ -37,15 +37,15 @@ echo '<p><strong>' . __( 'Where does BackUpWordPress store the backup files?', '
37
 
38
  '<p>' . __( 'There are some things you can test to confirm this is the issue.', 'backupwordpress' ) . '</p>' .
39
 
40
- '<ul><li>' . __( 'Are scheduled posts working? (They use wp-cron as well ). ', 'backupwordpress' ) . '</li>' .
41
 
42
- '<li>' . __( 'Are you hosted on Heart Internet? (wp-cron may not be supported by Heart Internet, see below for work-around).', 'backupwordpress' ) . '</li>' .
43
 
44
  '<li>' . __( 'If you click manual backup does it work?', 'backupwordpress' ) . '</li>' .
45
 
46
  '<li>' . __( 'Try adding <code>define( \'ALTERNATE_WP_CRON\', true );</code> to your <code>wp-config.php</code>, do automatic backups work?', 'backupwordpress' ) . '</li>' .
47
 
48
- '<li>' . __( 'Is your site private (I.E. is it behind some kind of authentication, maintenance plugin, .htaccess) if so wp-cron won\'t work until you remove it, if you are and you temporarily remove the authentication, do backups start working?', 'backupwordpress' ) . '</li></ul>' .
49
 
50
  '<p>' . __( 'Report the results to our support team for further help. To do this, either enable suport from your Admin Dashboard (recommended), or email backupwordpress@hmn.md', 'backupwordpress' ) . '</p>' .
51
 
@@ -55,4 +55,4 @@ echo '<p><strong>' . __( 'Where does BackUpWordPress store the backup files?', '
55
 
56
  '<p><strong>' . __( 'My backups seem to be failing?', 'backupwordpress' ) . '</strong></p>' .
57
 
58
- '<p>' . __( 'If your backups are failing - it\'s commonly caused by lack of available resources on your server. The easiest way to establish this to exclude some [of] or your entire uploades folder, running a backup an if that succeeds. If so, we know it\'s probably a server issue. If not, report the results to our support team for further help. To do this, either enable suport from your Admin Dashboard (recommended), or email backupwordpress@hmn.md', 'backupwordpress' ) . '</p>';
19
 
20
  '<p>' . __( 'No.', 'backupwordpress' ) . '</p>' .
21
 
22
+ '<p><strong>' . __( 'I\'m not receiving my backups by email', 'backupwordpress' ) . '</strong></p>' .
23
 
24
  '<p>' . __( 'Most servers have a filesize limit on email attachments, it\'s generally about 10mb. If your backup file is over that limit it won\'t be sent attached to the email, instead you should receive an email with a link to download the backup, if you aren\'t even receiving that then you likely have a mail issue on your server that you\'ll need to contact your host about.', 'backupwordpress' ) . '</p>' .
25
 
37
 
38
  '<p>' . __( 'There are some things you can test to confirm this is the issue.', 'backupwordpress' ) . '</p>' .
39
 
40
+ '<ul><li>' . __( 'Are scheduled posts working? (They use wp-cron as well.)', 'backupwordpress' ) . '</li>' .
41
 
42
+ '<li>' . __( 'Are you hosted on Heart Internet? (wp-cron may not be supported by Heart Internet, see below for work-around.)', 'backupwordpress' ) . '</li>' .
43
 
44
  '<li>' . __( 'If you click manual backup does it work?', 'backupwordpress' ) . '</li>' .
45
 
46
  '<li>' . __( 'Try adding <code>define( \'ALTERNATE_WP_CRON\', true );</code> to your <code>wp-config.php</code>, do automatic backups work?', 'backupwordpress' ) . '</li>' .
47
 
48
+ '<li>' . __( 'Is your site private (i.e. is it behind some kind of authentication, maintenance plugin, .htaccess)? If so wp-cron won\'t work until you remove it. If you are and you temporarily remove the authentication, do backups start working?', 'backupwordpress' ) . '</li></ul>' .
49
 
50
  '<p>' . __( 'Report the results to our support team for further help. To do this, either enable suport from your Admin Dashboard (recommended), or email backupwordpress@hmn.md', 'backupwordpress' ) . '</p>' .
51
 
55
 
56
  '<p><strong>' . __( 'My backups seem to be failing?', 'backupwordpress' ) . '</strong></p>' .
57
 
58
+ '<p>' . __( 'If your backups are failing, it\'s commonly caused by a lack of available resources on your server. The easiest way to establish this is to exclude some of, or the entirety of your uploads folder, running a backup, and if that succeeds, then you\'ll know it\'s probably a server issue. If not, report the results to our support team for further help. To do this, either enable support from your Admin Dashboard (recommended), or email backupwordpress@hmn.md', 'backupwordpress' ) . '</p>';
admin/menu.php CHANGED
@@ -99,10 +99,7 @@ function hmbkp_contextual_help() {
99
  );
100
 
101
  get_current_screen()->set_help_sidebar(
102
- '<p><strong>' . esc_html__( 'For more information:', 'backupwordpress' ) . '</strong></p>' .
103
- '<p><a href="https://github.com/humanmade/backupwordpress" target="_blank">GitHub</a></p>' .
104
- '<p><a href="http://wordpress.org/tags/backupwordpress?forum_id=10" target="_blank">' . esc_html__( 'Support Forums', 'backupwordpress' ) . '</a></p>' .
105
- '<p><a href="http://translate.hmn.md/" target="_blank">' . esc_html__( 'Help with translation', 'backupwordpress' ) . '</a></p>'
106
  );
107
 
108
  }
99
  );
100
 
101
  get_current_screen()->set_help_sidebar(
102
+ '<p><strong>' . esc_html__( 'For more information:', 'backupwordpress' ) . '</strong></p><p><a href="https://github.com/humanmade/backupwordpress" target="_blank">GitHub</a></p><p><a href="http://wordpress.org/tags/backupwordpress?forum_id=10" target="_blank">' . esc_html__( 'Support Forums', 'backupwordpress' ) . '</a></p><p><a href="https://translate.wordpress.org/projects/wp-plugins/backupwordpress/dev/" target="_blank">' . esc_html__( 'Help with translation', 'backupwordpress' ) . '</a></p>'
 
 
 
103
  );
104
 
105
  }
admin/page.php CHANGED
@@ -1,5 +1,17 @@
1
  <div class="wrap">
2
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <?php if ( hmbkp_possible() ) : ?>
4
 
5
  <?php include_once( HMBKP_PLUGIN_PATH . 'admin/backups.php' ); ?>
1
  <div class="wrap">
2
 
3
+ <h1>
4
+ BackUpWordPress
5
+
6
+ <?php if ( get_option( 'hmbkp_enable_support' ) ) { ?>
7
+ <a class="page-title-action" href="mailto:backupwordpress@hmn.md"><?php _e( 'Support', 'backupwordpress' ); ?></a>
8
+ <?php } else {
9
+ add_thickbox(); ?>
10
+ <a id="intercom-info" class="thickbox page-title-action" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'load_enable_support', 'width' => '600', 'height' => '420' ), self_admin_url( 'admin-ajax.php' ) ), 'hmbkp_nonce' ) ); ?>"><span class="dashicons dashicons-admin-users"></span>&nbsp;<?php _e( 'Enable Support', 'backupwordpress' ); ?></a>
11
+ <?php } ?>
12
+
13
+ </h1>
14
+
15
  <?php if ( hmbkp_possible() ) : ?>
16
 
17
  <?php include_once( HMBKP_PLUGIN_PATH . 'admin/backups.php' ); ?>
admin/schedule-form-excludes.php CHANGED
@@ -68,7 +68,7 @@
68
 
69
  <?php endif; ?>
70
 
71
- <h3 id="directory-listing"><?php _e( 'Directory Listing', 'backupwordpress' ); ?></h3>
72
 
73
  <p><?php _e( 'Here\'s a directory listing of all files on your site, you can browse through and exclude files or folders that you don\'t want included in your backup.', 'backupwordpress' ); ?></p>
74
 
@@ -91,121 +91,121 @@
91
  $exclude_string = $schedule->backup->exclude_string( 'regex' );
92
 
93
  // Kick off a recursive filesize scan
94
- $files = $schedule->list_directory_by_total_filesize( $directory );
95
 
96
- if ( $files ) { ?>
97
 
98
- <table class="widefat">
99
 
100
- <thead>
 
 
 
 
 
 
 
101
 
102
- <tr>
103
- <th></th>
104
- <th scope="col"><?php _e( 'Name', 'backupwordpress' ); ?></th>
105
- <th scope="col" class="column-format"><?php _e( 'Size', 'backupwordpress' ); ?></th>
106
- <th scope="col" class="column-format"><?php _e( 'Permissions', 'backupwordpress' ); ?></th>
107
- <th scope="col" class="column-format"><?php _e( 'Type', 'backupwordpress' ); ?></th>
108
- <th scope="col" class="column-format"><?php _e( 'Status', 'backupwordpress' ); ?></th>
109
- </tr>
110
 
111
- <tr>
 
 
112
 
113
- <th scope="row">
114
- <div class="dashicons dashicons-admin-home"></div>
115
- </th>
116
 
117
- <th scope="col">
118
 
119
- <?php if ( $schedule->backup->get_root() !== $directory ) { ?>
 
120
 
121
- <a href="<?php echo esc_url( remove_query_arg( 'hmbkp_directory_browse' ) ); ?>"><?php echo esc_html( $schedule->backup->get_root() ); ?></a>
122
- <code>/</code>
123
 
124
- <?php $parents = array_filter( explode( '/', str_replace( trailingslashit( $schedule->backup->get_root() ), '', trailingslashit( dirname( $directory ) ) ) ) );
125
 
126
- foreach ( $parents as $directory_basename ) { ?>
 
127
 
128
- <a href="<?php echo esc_url( add_query_arg( 'hmbkp_directory_browse', urlencode( substr( $directory, 0, strpos( $directory, $directory_basename ) ) . $directory_basename ) ) ); ?>"><?php echo esc_html( $directory_basename ); ?></a>
129
- <code>/</code>
130
 
131
- <?php } ?>
132
 
133
- <?php echo esc_html( basename( $directory ) ); ?>
134
 
135
- <?php } else { ?>
136
 
137
- <?php echo esc_html( $schedule->backup->get_root() ); ?>
138
 
139
- <?php } ?>
140
 
141
- </th>
142
 
143
- <td class="column-filesize">
144
 
145
- <?php if ( $schedule->is_site_size_being_calculated() ) { ?>
146
 
147
- <span class="spinner"></span>
148
 
149
- <?php } else {
150
 
151
- $root = new SplFileInfo( $schedule->backup->get_root() );
152
 
153
- $size = $schedule->filesize( $root, true );
154
 
155
- if ( false !== $size ) {
156
 
157
- $size = size_format( $size );
 
 
158
 
159
- if ( ! $size ) {
160
- $size = '0 B';
161
- } ?>
162
 
163
- <code>
164
 
165
- <?php echo esc_html( $size ); ?>
 
166
 
167
- <a class="dashicons dashicons-update"
168
- href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'hmbkp_recalculate_directory_filesize', urlencode( $schedule->backup->get_root() ) ), 'hmbkp-recalculate_directory_filesize' ) ); ?>"><span><?php _e( 'Refresh', 'backupwordpress' ); ?></span></a>
169
 
170
- </code>
171
 
 
172
 
173
- <?php } ?>
174
 
175
- <?php } ?>
 
 
176
 
177
- <td>
178
- <?php echo esc_html( substr( sprintf( '%o', fileperms( $schedule->backup->get_root() ) ), - 4 ) ); ?>
179
- </td>
180
 
181
- <td>
182
 
183
- <?php if ( is_link( $schedule->backup->get_root() ) ) {
184
 
185
- _e( 'Symlink', 'backupwordpress' );
186
 
187
- } elseif ( is_dir( $schedule->backup->get_root() ) ) {
188
 
189
- _e( 'Folder', 'backupwordpress' );
190
 
191
- } ?>
192
 
193
- </td>
194
 
195
- <td></td>
196
 
197
- </tr>
198
 
199
- </thead>
200
 
201
- <tbody>
202
 
203
- <?php foreach ( $files as $size => $file ) {
204
 
205
  $is_excluded = $is_unreadable = false;
206
 
207
  // Check if the file is excluded
208
- if ( $exclude_string && preg_match( '(' . $exclude_string . ')', str_ireplace( trailingslashit( $schedule->backup->get_root() ), '', HM\BackUpWordPress\Backup::conform_dir( $file->getPathname() ) ) ) ) {
209
  $is_excluded = true;
210
  }
211
 
@@ -354,11 +354,18 @@
354
 
355
  <?php } ?>
356
 
357
- </tbody>
358
 
359
- </table>
 
 
 
 
 
 
 
 
360
 
361
- <?php } ?>
362
 
363
  <p class="submit">
364
  <a href="<?php echo esc_url( hmbkp_get_settings_url() ) ?>"
68
 
69
  <?php endif; ?>
70
 
71
+ <h3 id="directory-listing"><?php _e( 'Your Site', 'backupwordpress' ); ?></h3>
72
 
73
  <p><?php _e( 'Here\'s a directory listing of all files on your site, you can browse through and exclude files or folders that you don\'t want included in your backup.', 'backupwordpress' ); ?></p>
74
 
91
  $exclude_string = $schedule->backup->exclude_string( 'regex' );
92
 
93
  // Kick off a recursive filesize scan
94
+ $files = $schedule->list_directory_by_total_filesize( $directory ); ?>
95
 
96
+ <table class="widefat">
97
 
98
+ <thead>
99
 
100
+ <tr>
101
+ <th></th>
102
+ <th scope="col"><?php _e( 'Name', 'backupwordpress' ); ?></th>
103
+ <th scope="col" class="column-format"><?php _e( 'Size', 'backupwordpress' ); ?></th>
104
+ <th scope="col" class="column-format"><?php _e( 'Permissions', 'backupwordpress' ); ?></th>
105
+ <th scope="col" class="column-format"><?php _e( 'Type', 'backupwordpress' ); ?></th>
106
+ <th scope="col" class="column-format"><?php _e( 'Status', 'backupwordpress' ); ?></th>
107
+ </tr>
108
 
109
+ <tr>
 
 
 
 
 
 
 
110
 
111
+ <th scope="row">
112
+ <div class="dashicons dashicons-admin-home"></div>
113
+ </th>
114
 
115
+ <th scope="col">
 
 
116
 
117
+ <?php if ( $schedule->backup->get_root() !== $directory ) { ?>
118
 
119
+ <a href="<?php echo esc_url( remove_query_arg( 'hmbkp_directory_browse' ) ); ?>"><?php echo esc_html( $schedule->backup->get_root() ); ?></a>
120
+ <code>/</code>
121
 
122
+ <?php $parents = array_filter( explode( '/', str_replace( trailingslashit( $schedule->backup->get_root() ), '', trailingslashit( dirname( $directory ) ) ) ) );
 
123
 
124
+ foreach ( $parents as $directory_basename ) { ?>
125
 
126
+ <a href="<?php echo esc_url( add_query_arg( 'hmbkp_directory_browse', urlencode( substr( $directory, 0, strpos( $directory, $directory_basename ) ) . $directory_basename ) ) ); ?>"><?php echo esc_html( $directory_basename ); ?></a>
127
+ <code>/</code>
128
 
129
+ <?php } ?>
 
130
 
131
+ <?php echo esc_html( basename( $directory ) ); ?>
132
 
133
+ <?php } else { ?>
134
 
135
+ <?php echo esc_html( $schedule->backup->get_root() ); ?>
136
 
137
+ <?php } ?>
138
 
139
+ </th>
140
 
141
+ <td class="column-filesize">
142
 
143
+ <?php if ( $schedule->is_site_size_being_calculated() ) { ?>
144
 
145
+ <span class="spinner"></span>
146
 
147
+ <?php } else {
148
 
149
+ $root = new SplFileInfo( $schedule->backup->get_root() );
150
 
151
+ $size = $schedule->filesize( $root, true );
152
 
153
+ if ( false !== $size ) {
154
 
155
+ $size = size_format( $size );
156
 
157
+ if ( ! $size ) {
158
+ $size = '0 B';
159
+ } ?>
160
 
161
+ <code>
 
 
162
 
163
+ <?php echo esc_html( $size ); ?>
164
 
165
+ <a class="dashicons dashicons-update"
166
+ href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'hmbkp_recalculate_directory_filesize', urlencode( $schedule->backup->get_root() ) ), 'hmbkp-recalculate_directory_filesize' ) ); ?>"><span><?php _e( 'Refresh', 'backupwordpress' ); ?></span></a>
167
 
168
+ </code>
 
169
 
 
170
 
171
+ <?php } ?>
172
 
173
+ <?php } ?>
174
 
175
+ <td>
176
+ <?php echo esc_html( substr( sprintf( '%o', fileperms( $schedule->backup->get_root() ) ), - 4 ) ); ?>
177
+ </td>
178
 
179
+ <td>
 
 
180
 
181
+ <?php if ( is_link( $schedule->backup->get_root() ) ) {
182
 
183
+ _e( 'Symlink', 'backupwordpress' );
184
 
185
+ } elseif ( is_dir( $schedule->backup->get_root() ) ) {
186
 
187
+ _e( 'Folder', 'backupwordpress' );
188
 
189
+ } ?>
190
 
191
+ </td>
192
 
193
+ <td></td>
194
 
195
+ </tr>
196
 
197
+ </thead>
198
 
199
+ <tbody>
200
 
201
+ <?php if ( $files ) {
202
 
203
+ foreach ( $files as $size => $file ) {
204
 
205
  $is_excluded = $is_unreadable = false;
206
 
207
  // Check if the file is excluded
208
+ if ( $exclude_string && preg_match( '(' . $exclude_string . ')', str_ireplace( trailingslashit( $schedule->backup->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
209
  $is_excluded = true;
210
  }
211
 
354
 
355
  <?php } ?>
356
 
357
+ <?php } else { ?>
358
 
359
+ <tr>
360
+ <td colspan="5"><span class="description"><?php _e( 'This folder is empty', 'backupwordpress' ); ?></span></td>
361
+ </tr>
362
+
363
+ <?php } ?>
364
+
365
+ </tbody>
366
+
367
+ </table>
368
 
 
369
 
370
  <p class="submit">
371
  <a href="<?php echo esc_url( hmbkp_get_settings_url() ) ?>"
admin/schedule-form.php CHANGED
@@ -149,8 +149,11 @@ hmbkp_clear_settings_errors();
149
  <?php _e( 'Minutes', 'backupwordpress' ); ?></label>
150
 
151
  </span>
152
- <p class="descriprion"><strong><?php esc_html_e( 'Please use 24 hour format for hours', 'backupwordpress' ); ?></strong></p>
153
- <p class="twice-js description<?php if ( $schedule->get_reoccurrence() !== 'hmbkp_fortnightly' ) { ?> hidden<?php } ?>"><?php _e( 'The second backup will run 12 hours after the first', 'backupwordpress' ); ?></p>
 
 
 
154
 
155
  </td>
156
 
@@ -193,4 +196,4 @@ hmbkp_clear_settings_errors();
193
  </p>
194
 
195
 
196
- </form>
149
  <?php _e( 'Minutes', 'backupwordpress' ); ?></label>
150
 
151
  </span>
152
+
153
+ <p class="description">
154
+ <?php esc_html_e( '24-hour format.', 'backupwordpress' ); ?>
155
+ <span class="twice-js <?php if ( $schedule->get_reoccurrence() !== 'fortnightly' ) { ?> hidden<?php } ?>"><?php _e( 'The second backup will run 12 hours after the first.', 'backupwordpress' ); ?><span>
156
+ </p>
157
 
158
  </td>
159
 
196
  </p>
197
 
198
 
199
+ </form>
admin/schedule-sentence.php CHANGED
@@ -13,19 +13,19 @@ $next_backup = 'title="' . esc_attr( sprintf( __( 'The next backup will be on %1
13
  // Backup Re-occurrence
14
  switch ( $schedule->get_reoccurrence() ) :
15
 
16
- case 'hmbkp_hourly' :
17
 
18
  $reoccurrence = date_i18n( 'i', $schedule->get_next_occurrence( false ) ) === '00' ? '<span ' . $next_backup . '>' . __( 'hourly on the hour', 'backupwordpress' ) . '</span>' : sprintf( __( 'hourly at %s minutes past the hour', 'backupwordpress' ), '<span ' . $next_backup . '>' . intval( date_i18n( 'i', $schedule->get_next_occurrence( false ) ) ) ) . '</span>';
19
 
20
  break;
21
 
22
- case 'hmbkp_daily' :
23
 
24
  $reoccurrence = sprintf( __( 'daily at %s', 'backupwordpress' ), '<span ' . $next_backup . '>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
25
 
26
  break;
27
 
28
- case 'hmbkp_twicedaily' :
29
 
30
  $times[] = date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) );
31
  $times[] = date_i18n( get_option( 'time_format' ), strtotime( '+ 12 hours', $schedule->get_next_occurrence( false ) ) );
@@ -36,19 +36,19 @@ switch ( $schedule->get_reoccurrence() ) :
36
 
37
  break;
38
 
39
- case 'hmbkp_weekly' :
40
 
41
  $reoccurrence = sprintf( __( 'weekly on %1$s at %2$s', 'backupwordpress' ), '<span ' . $next_backup . '>' .esc_html( $day ) . '</span>', '<span>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
42
 
43
  break;
44
 
45
- case 'hmbkp_fortnightly' :
46
 
47
- $reoccurrence = sprintf( __( 'biweekly on %1$s at %2$s', 'backupwordpress' ), '<span ' . $next_backup . '>' . $day . '</span>', '<span>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
48
 
49
  break;
50
 
51
- case 'hmbkp_monthly' :
52
 
53
  $reoccurrence = sprintf( __( 'on the %1$s of each month at %2$s', 'backupwordpress' ), '<span ' . $next_backup . '>' . esc_html( date_i18n( 'jS', $schedule->get_next_occurrence( false ) ) ) . '</span>', '<span>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
54
 
@@ -99,10 +99,8 @@ foreach ( HM\BackUpWordPress\Services::get_services( $schedule ) as $file => $se
99
  $email_msg = $service->get_error_message();
100
  } elseif ( 'Email' === $service->name ) {
101
  $email_msg = wp_kses_post( $service->display() );
102
-
103
  } elseif ( $service->is_service_active() ) {
104
  $services[] = esc_html( $service->display() );
105
-
106
  }
107
 
108
  }
@@ -155,7 +153,7 @@ function hmbkp_get_site_size_text( HM\BackUpWordPress\Scheduled_Backup $schedule
155
 
156
  } elseif ( ( 'database' === $schedule->get_type() ) || $schedule->is_site_size_cached() ) {
157
 
158
- return sprintf( '(<code title="' . __( 'Backups will be compressed and should be smaller than this.', 'backupwordpress' ) . '">%s</code>)', esc_attr( $schedule->get_formatted_site_size() ) );
159
 
160
  } else {
161
 
@@ -163,4 +161,4 @@ function hmbkp_get_site_size_text( HM\BackUpWordPress\Scheduled_Backup $schedule
163
 
164
  }
165
 
166
- }
13
  // Backup Re-occurrence
14
  switch ( $schedule->get_reoccurrence() ) :
15
 
16
+ case 'hourly' :
17
 
18
  $reoccurrence = date_i18n( 'i', $schedule->get_next_occurrence( false ) ) === '00' ? '<span ' . $next_backup . '>' . __( 'hourly on the hour', 'backupwordpress' ) . '</span>' : sprintf( __( 'hourly at %s minutes past the hour', 'backupwordpress' ), '<span ' . $next_backup . '>' . intval( date_i18n( 'i', $schedule->get_next_occurrence( false ) ) ) ) . '</span>';
19
 
20
  break;
21
 
22
+ case 'daily' :
23
 
24
  $reoccurrence = sprintf( __( 'daily at %s', 'backupwordpress' ), '<span ' . $next_backup . '>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
25
 
26
  break;
27
 
28
+ case 'twicedaily' :
29
 
30
  $times[] = date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) );
31
  $times[] = date_i18n( get_option( 'time_format' ), strtotime( '+ 12 hours', $schedule->get_next_occurrence( false ) ) );
36
 
37
  break;
38
 
39
+ case 'weekly' :
40
 
41
  $reoccurrence = sprintf( __( 'weekly on %1$s at %2$s', 'backupwordpress' ), '<span ' . $next_backup . '>' .esc_html( $day ) . '</span>', '<span>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
42
 
43
  break;
44
 
45
+ case 'fortnightly' :
46
 
47
+ $reoccurrence = sprintf( __( 'every two weeks on %1$s at %2$s', 'backupwordpress' ), '<span ' . $next_backup . '>' . $day . '</span>', '<span>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
48
 
49
  break;
50
 
51
+ case 'monthly' :
52
 
53
  $reoccurrence = sprintf( __( 'on the %1$s of each month at %2$s', 'backupwordpress' ), '<span ' . $next_backup . '>' . esc_html( date_i18n( 'jS', $schedule->get_next_occurrence( false ) ) ) . '</span>', '<span>' . esc_html( date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ) ) . '</span>' );
54
 
99
  $email_msg = $service->get_error_message();
100
  } elseif ( 'Email' === $service->name ) {
101
  $email_msg = wp_kses_post( $service->display() );
 
102
  } elseif ( $service->is_service_active() ) {
103
  $services[] = esc_html( $service->display() );
 
104
  }
105
 
106
  }
153
 
154
  } elseif ( ( 'database' === $schedule->get_type() ) || $schedule->is_site_size_cached() ) {
155
 
156
+ return sprintf( '(<code title="' . __( 'Backups will be compressed and should be smaller than this.', 'backupwordpress' ) . '">%s</code>)', esc_attr( $schedule->get_formatted_site_size( true ) ) );
157
 
158
  } else {
159
 
161
 
162
  }
163
 
164
+ }
admin/server-info.php CHANGED
@@ -60,4 +60,4 @@ foreach ( HM\BackUpWordPress\Requirements::get_requirement_groups() as $group )
60
 
61
  foreach ( HM\BackUpWordPress\Services::get_services() as $file => $service ) {
62
  echo wp_kses_post( call_user_func( array( $service, 'intercom_data_html' ) ) );
63
- }
60
 
61
  foreach ( HM\BackUpWordPress\Services::get_services() as $file => $service ) {
62
  echo wp_kses_post( call_user_func( array( $service, 'intercom_data_html' ) ) );
63
+ }
assets/hmbkp.css CHANGED
@@ -38,12 +38,12 @@ h2 + div[id^="hmbkp"] input { max-width: 100%; }
38
  .hmbkp-ajax-loading, button.hmbkp-ajax-loading { padding-left: 20px; position: relative; }
39
  .hmbkp-ajax-loading::after { content: ""; width: 16px; height: 16px; background-image: url('spinner-2x.gif'); background-size: 16px 16px; background-repeat: no-repeat; background-position: 0 0; position: absolute; right: -30px; top: 5px; }
40
 
41
- .delete-action { color: #a00; -webkit-transition: all 300ms ease; -moz-transition: all 300ms ease; -ms-transition: all 300ms ease; -o-transition: all 300ms ease; transition: all 300ms ease; }
42
- .delete-action:hover .delete-action:focus { color: red; -webkit-transition: all 300ms ease; -moz-transition: all 300ms ease; -ms-transition: all 300ms ease; -o-transition: all 300ms ease; transition: all 300ms ease; }
43
 
44
  .strikethrough { text-decoration: line-through; }
45
 
46
- table.widefat tbody tr:nth-child(even) { background-color: #f9f9f9 }
47
  .hmbkp-exclude-settings td:first-child, .hmbkp-exclude-settings th:first-child { width: 20px; padding-right: 0 }
48
  .hmbkp-exclude-settings thead tr:last-child { background-color: #f9f9f9; }
49
  .hmbkp-exclude-settings table .button-secondary { line-height: 18px; height: 20px; }
@@ -61,9 +61,7 @@ thead td { border-bottom: 1px solid #e1e1e1; }
61
  .server-info { overflow: auto; max-height: 50%; outline: black 1px solid; }
62
  .server-info pre { max-height: 100px; overflow-x:hidden; }
63
 
64
- #intercom-info { background: #0074a2; color:#fff; display: inline-block; margin-bottom: -3px; padding: 3px 8px; }
65
- #intercom-info:hover { background: #2ea2cc; color:#fff;}
66
- #intercom-info span.dashicons-admin-users { position: relative; display:inline-block; vertical-align: middle; top:-2px; }
67
 
68
  pre { background-color: #eee; padding: 10px; white-space: pre; max-height: 320px; overflow: auto; word-wrap: normal !important; }
69
 
38
  .hmbkp-ajax-loading, button.hmbkp-ajax-loading { padding-left: 20px; position: relative; }
39
  .hmbkp-ajax-loading::after { content: ""; width: 16px; height: 16px; background-image: url('spinner-2x.gif'); background-size: 16px 16px; background-repeat: no-repeat; background-position: 0 0; position: absolute; right: -30px; top: 5px; }
40
 
41
+ .delete-action { color: #a00; -webkit-transition: all 300ms ease; transition: all 300ms ease; }
42
+ .delete-action:hover .delete-action:focus { color: red; -webkit-transition: all 300ms ease; transition: all 300ms ease; }
43
 
44
  .strikethrough { text-decoration: line-through; }
45
 
46
+ table.widefat tbody tr:nth-child(odd) { background-color: #f9f9f9 }
47
  .hmbkp-exclude-settings td:first-child, .hmbkp-exclude-settings th:first-child { width: 20px; padding-right: 0 }
48
  .hmbkp-exclude-settings thead tr:last-child { background-color: #f9f9f9; }
49
  .hmbkp-exclude-settings table .button-secondary { line-height: 18px; height: 20px; }
61
  .server-info { overflow: auto; max-height: 50%; outline: black 1px solid; }
62
  .server-info pre { max-height: 100px; overflow-x:hidden; }
63
 
64
+ .page-title-action span.dashicons-admin-users { position: relative; display:inline-block; vertical-align: middle; top:-2px; }
 
 
65
 
66
  pre { background-color: #eee; padding: 10px; white-space: pre; max-height: 320px; overflow: auto; word-wrap: normal !important; }
67
 
assets/hmbkp.js CHANGED
@@ -1,214 +1,215 @@
1
- jQuery(document).ready(function ( $ ) {
 
 
 
 
2
 
3
- // Don't ever cache ajax requests
4
- $.ajaxSetup( {'cache': false} );
5
 
6
- if ( $( 'select#hmbkp_schedule_recurrence_type' ).size() ) {
7
 
8
- hmbkpToggleScheduleFields( $( 'select#hmbkp_schedule_recurrence_type' ).val() );
 
 
9
 
10
- $( document ).on( 'change', 'select#hmbkp_schedule_recurrence_type', function () {
11
- hmbkpToggleScheduleFields( $( this ).val() );
12
- } );
13
 
14
- }
 
15
 
16
- // Show delete confirm message for delete schedule
17
- $( document ).on( 'click', '.hmbkp-schedule-actions .delete-action', function ( e ) {
 
18
 
19
- if ( ! confirm( hmbkp.delete_schedule ) ) {
20
- e.preventDefault();
21
- }
22
 
23
- } );
 
24
 
25
- // Show delete confirm message for delete backup
26
- $( document ).on( 'click', '.hmbkp_manage_backups_row .delete-action', function ( e ) {
 
27
 
28
- if ( ! confirm(hmbkp.delete_backup ) ) {
29
- e.preventDefault();
30
- }
31
 
32
- } );
 
33
 
34
- // Show delete confirm message for remove exclude rule
35
- $( document ).on( 'click', '.hmbkp-edit-schedule-excludes-form .delete-action', function ( e ) {
 
36
 
37
- if ( ! confirm(hmbkp.remove_exclude_rule ) ) {
38
- e.preventDefault();
39
- }
40
 
41
- } );
 
 
 
 
 
 
 
42
 
43
- // Test the cron response using ajax
44
- $.post( ajaxurl, {'nonce': hmbkp.nonce, 'action': 'hmbkp_cron_test'},
45
- function ( data ) {
46
- if ( data !== '1' ) {
47
- $( '.wrap > h2' ).after( data );
48
- }
49
- }
50
- );
51
 
52
- // Run a backup
53
- $( document ).on( 'click', '.hmbkp-run', function ( e ) {
54
 
55
- $( this ).closest( '.hmbkp-schedule-sentence' ).addClass('hmbkp-running' );
56
 
57
- $( '.hmbkp-error' ).removeClass( 'hmbkp-error' );
58
 
59
- var scheduleId = $( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' );
 
 
 
 
 
 
 
60
 
61
- $.post(
62
- ajaxurl,
63
- {
64
- 'hmbkp_run_schedule_nonce': hmbkp.hmbkp_run_schedule_nonce,
65
- 'action': 'hmbkp_run_schedule',
66
- 'hmbkp_schedule_id': scheduleId
67
- }
68
- );
69
 
70
- e.preventDefault();
71
 
72
- } );
 
73
 
74
- // Send the schedule id with the heartbeat
75
- $( document ).on( 'heartbeat-send', function ( e, data ) {
76
 
77
- data.hmbkp_schedule_id = $( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' );
 
 
 
 
78
 
79
- if ( $( '.hmbkp-schedule-sentence.hmbkp-running' ).size() ) {
80
 
81
- data.hmbkp_is_in_progress = true;
82
- } else {
83
- data.hmbkp_client_request = 'site_size';
84
- }
85
 
86
- } );
 
 
 
87
 
88
- // Update schedule status on heartbeat tick
89
- $( document ).on( 'heartbeat-tick', function ( e, data ) {
 
 
90
 
91
- // If the schedule has finished then reload the page
92
- if ( data.hmbkp_schedule_status === 0 && ! $( '.hmbkp-error' ).size() ) {
93
- location.reload(true);
94
- }
 
 
 
95
 
96
- // If the schedule is still running then update the schedule status
97
- if ( ( data.hmbkp_schedule_status !== 0 ) && ( data.hmbkp_schedule_status !== undefined ) ) {
98
- $( '.hmbkp-status' ).replaceWith( data.hmbkp_schedule_status );
99
- }
100
 
101
- if ( ( data.hmbkp_site_size !== undefined ) && ( $( 'code.calculating' ).size() ) ) {
102
- $( 'code.calculating' ).text( data.hmbkp_site_size );
103
 
104
- var excludes = $( '.hmbkp-exclude-settings' );
105
- if ( excludes.size() ) {
106
- excludes.replaceWith( data.hmbkp_dir_sizes );
107
- }
108
- }
109
 
110
- } );
111
-
112
- // Closing ThickBox Modal Window
113
- $( document ).on( 'click', '.hmbkp-thickbox-close', function ( e ) {
114
-
115
- e.preventDefault();
116
- window.parent.tb_remove();
117
-
118
- } );
119
 
120
  } );
121
 
122
  function hmbkpToggleScheduleFields( recurrence ) {
123
 
124
- recurrence = ( typeof recurrence !== 'undefined' ) ? recurrence : 'manually';
125
-
126
- var settingFields = jQuery( '.recurring-setting' );
127
- var scheduleSettingFields = jQuery( '#schedule-start' );
128
- var twiceDailyNote = jQuery( 'p.twice-js' );
129
-
130
- switch ( recurrence ) {
131
-
132
- case 'manually':
133
- settingFields.hide();
134
- break;
135
-
136
- case 'hmbkp_hourly' :
137
- settingFields.hide();
138
- break;
139
-
140
- case 'hmbkp_daily' :
141
- settingFields.hide();
142
- scheduleSettingFields.show();
143
- twiceDailyNote.hide();
144
- break;
145
-
146
- case 'hmbkp_twicedaily' :
147
- settingFields.hide();
148
- scheduleSettingFields.show();
149
- twiceDailyNote.show();
150
- break;
151
-
152
- case 'hmbkp_weekly' : // fall through
153
- case 'hmbkp_fortnightly' :
154
- settingFields.hide();
155
- jQuery('#start-day').show();
156
- scheduleSettingFields.show();
157
- twiceDailyNote.hide();
158
- break;
159
-
160
- case 'hmbkp_monthly' :
161
- settingFields.hide();
162
- scheduleSettingFields.show();
163
- jQuery('#start-date').show();
164
- twiceDailyNote.hide();
165
- break;
166
-
167
- }
 
 
168
 
169
  }
170
 
171
  function hmbkpCatchResponseAndOfferToEmail( data ) {
172
 
173
- // Backup Succeeded
174
- if ( ! data || data === 0 ) {
175
- location.reload( true );
176
- }
177
 
178
- // The backup failed, show the error and offer to have it emailed back
179
- else {
180
 
181
- jQuery( '.hmbkp-schedule-sentence.hmbkp-running' ).removeClass( 'hmbkp-running' ).addClass( 'hmbkp-error' );
182
 
183
- jQuery.post(
184
- ajaxurl,
185
- {'nonce': hmbkp.nonce, 'action': 'hmbkp_backup_error', 'hmbkp_error': data},
186
- function ( data ) {
187
 
188
- if ( ! data || data === 0 ) {
189
- return;
190
- } else {
191
- location.reload( true );
192
- }
193
- }
194
- );
195
 
196
- }
197
 
198
- jQuery( document ).one( 'click', '.hmbkp_send_error_via_email', function ( e ) {
199
 
200
- e.preventDefault();
201
 
202
- jQuery( this ).addClass( 'hmbkp-ajax-loading' ).attr( 'disabled', 'disabled' );
203
 
204
- jQuery.post(
205
- ajaxurl,
206
- {'nonce': hmbkp.nonce, 'action': 'hmbkp_email_error', 'hmbkp_error': data},
207
- function () {
208
- //jQuery.colorbox.close();
209
- }
210
- );
211
 
212
- } );
213
 
214
  }
1
+ jQuery( document ).ready( function ( $ ) {
2
+ 'use strict';
3
+ var recurrenceType = $( 'select#hmbkp_schedule_recurrence_type' );
4
+ // Don't ever cache ajax requests
5
+ $.ajaxSetup( {'cache': false} );
6
 
7
+ if ( recurrenceType.length ) {
 
8
 
9
+ hmbkpToggleScheduleFields( recurrenceType.val() );
10
 
11
+ $( document ).on( 'change', 'select#hmbkp_schedule_recurrence_type', function () {
12
+ hmbkpToggleScheduleFields( $( this ).val() );
13
+ } );
14
 
15
+ }
 
 
16
 
17
+ // Show delete confirm message for delete schedule
18
+ $( document ).on( 'click', '.hmbkp-schedule-actions .delete-action', function ( e ) {
19
 
20
+ if ( ! confirm( hmbkp.delete_schedule ) ) {
21
+ e.preventDefault();
22
+ }
23
 
24
+ } );
 
 
25
 
26
+ // Show delete confirm message for delete backup
27
+ $( document ).on( 'click', '.hmbkp_manage_backups_row .delete-action', function ( e ) {
28
 
29
+ if ( ! confirm( hmbkp.delete_backup ) ) {
30
+ e.preventDefault();
31
+ }
32
 
33
+ } );
 
 
34
 
35
+ // Show delete confirm message for remove exclude rule
36
+ $( document ).on( 'click', '.hmbkp-edit-schedule-excludes-form .delete-action', function ( e ) {
37
 
38
+ if ( ! confirm( hmbkp.remove_exclude_rule ) ) {
39
+ e.preventDefault();
40
+ }
41
 
42
+ } );
 
 
43
 
44
+ // Test the cron response using ajax
45
+ $.post( ajaxurl, {'nonce': hmbkp.nonce, 'action': 'hmbkp_cron_test'},
46
+ function ( data ) {
47
+ if ( data !== '1' ) {
48
+ $( '.wrap > h2' ).after( data );
49
+ }
50
+ }
51
+ );
52
 
53
+ // Run a backup
54
+ $( document ).on( 'click', '.hmbkp-run', function ( e ) {
 
 
 
 
 
 
55
 
56
+ $( this ).closest( '.hmbkp-schedule-sentence' ).addClass( 'hmbkp-running' );
 
57
 
58
+ $( '.hmbkp-error' ).removeClass( 'hmbkp-error' );
59
 
60
+ var scheduleId = $( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' );
61
 
62
+ $.post(
63
+ ajaxurl,
64
+ {
65
+ 'hmbkp_run_schedule_nonce': hmbkp.hmbkp_run_schedule_nonce,
66
+ 'action': 'hmbkp_run_schedule',
67
+ 'hmbkp_schedule_id': scheduleId
68
+ }
69
+ );
70
 
71
+ e.preventDefault();
 
 
 
 
 
 
 
72
 
73
+ } );
74
 
75
+ // Send the schedule id with the heartbeat
76
+ $( document ).on( 'heartbeat-send', function ( e, data ) {
77
 
78
+ data.hmbkp_schedule_id = $( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' );
 
79
 
80
+ if ( $( '.hmbkp-schedule-sentence.hmbkp-running' ).length ) {
81
+ data.hmbkp_is_in_progress = true;
82
+ } else {
83
+ data.hmbkp_client_request = 'site_size';
84
+ }
85
 
86
+ } );
87
 
88
+ // Update schedule status on heartbeat tick
89
+ $( document ).on( 'heartbeat-tick', function ( e, data ) {
 
 
90
 
91
+ // If the schedule has finished then reload the page
92
+ if ( data.hmbkp_schedule_status === 0 && ! $( '.hmbkp-error' ).length ) {
93
+ location.reload( true );
94
+ }
95
 
96
+ // If the schedule is still running then update the schedule status
97
+ if ( ( data.hmbkp_schedule_status !== 0 ) && ( data.hmbkp_schedule_status !== undefined ) ) {
98
+ $( '.hmbkp-status' ).replaceWith( data.hmbkp_schedule_status );
99
+ }
100
 
101
+ if ( (data.hmbkp_site_size !== undefined ) && ( $( 'code.calculating' ).length ) ) {
102
+ $( 'code.calculating' ).text( data.hmbkp_site_size );
103
+ var excludes = $( '.hmbkp-exclude-settings' );
104
+ if ( excludes.length ) {
105
+ excludes.replaceWith( data.hmbkp_dir_sizes );
106
+ }
107
+ }
108
 
109
+ } );
 
 
 
110
 
111
+ // Closing ThickBox Modal Window
112
+ $( document ).on( 'click', '.hmbkp-thickbox-close', function ( e ) {
113
 
114
+ e.preventDefault();
115
+ window.parent.tb_remove();
 
 
 
116
 
117
+ } );
 
 
 
 
 
 
 
 
118
 
119
  } );
120
 
121
  function hmbkpToggleScheduleFields( recurrence ) {
122
 
123
+ recurrence = (
124
+ typeof recurrence !== 'undefined'
125
+ ) ? recurrence : 'manually';
126
+
127
+ var settingFields = jQuery( '.recurring-setting' );
128
+ var scheduleSettingFields = jQuery( '#schedule-start' );
129
+ var twiceDailyNote = jQuery( '.twice-js' );
130
+
131
+ switch ( recurrence ) {
132
+
133
+ case 'manually':
134
+ settingFields.hide();
135
+ break;
136
+
137
+ case 'hourly' :
138
+ settingFields.hide();
139
+ break;
140
+
141
+ case 'daily' :
142
+ settingFields.hide();
143
+ scheduleSettingFields.show();
144
+ twiceDailyNote.hide();
145
+ break;
146
+
147
+ case 'twicedaily' :
148
+ settingFields.hide();
149
+ scheduleSettingFields.show();
150
+ twiceDailyNote.show();
151
+ break;
152
+
153
+ case 'weekly' : // fall through
154
+ case 'fortnightly' :
155
+ settingFields.hide();
156
+ jQuery( '#start-day' ).show();
157
+ scheduleSettingFields.show();
158
+ twiceDailyNote.hide();
159
+ break;
160
+
161
+ case 'monthly' :
162
+ settingFields.hide();
163
+ scheduleSettingFields.show();
164
+ jQuery( '#start-date' ).show();
165
+ twiceDailyNote.hide();
166
+ break;
167
+
168
+ }
169
 
170
  }
171
 
172
  function hmbkpCatchResponseAndOfferToEmail( data ) {
173
 
174
+ // Backup Succeeded
175
+ if ( ! data || data === 0 ) {
176
+ location.reload( true );
177
+ }
178
 
179
+ // The backup failed, show the error and offer to have it emailed back
180
+ else {
181
 
182
+ jQuery( '.hmbkp-schedule-sentence.hmbkp-running' ).removeClass( 'hmbkp-running' ).addClass( 'hmbkp-error' );
183
 
184
+ jQuery.post(
185
+ ajaxurl,
186
+ {'nonce': hmbkp.nonce, 'action': 'hmbkp_backup_error', 'hmbkp_error': data},
187
+ function ( data ) {
188
 
189
+ if ( ! data || data === 0 ) {
190
+ return;
191
+ } else {
192
+ location.reload( true );
193
+ }
194
+ }
195
+ );
196
 
197
+ }
198
 
199
+ jQuery( document ).one( 'click', '.hmbkp_send_error_via_email', function ( e ) {
200
 
201
+ e.preventDefault();
202
 
203
+ jQuery( this ).addClass( 'hmbkp-ajax-loading' ).attr( 'disabled', 'disabled' );
204
 
205
+ jQuery.post(
206
+ ajaxurl,
207
+ {'nonce': hmbkp.nonce, 'action': 'hmbkp_email_error', 'hmbkp_error': data},
208
+ function () {
209
+ //jQuery.colorbox.close();
210
+ }
211
+ );
212
 
213
+ } );
214
 
215
  }
assets/hmbkp.min.css CHANGED
@@ -1 +1 @@
1
- .hmbkp_active td:first-child>code:before{content:"\00a0 \2713 ";font-size:11px}.hmbkp_active{background:#E5F7E8}div#hmbkp-warning,h2.nav-tab-wrapper+div[id^=hmbkp]{margin:20px 0 15px}h2+div[id^=hmbkp] input{max-width:100%}.nav-tab.hmbkp-running:not(.nav-tab-active):before{width:20px;height:20px;margin:0 10px -4px 0;content:"";background:transparent url(spinner-2x.gif) no-repeat 0 0;background-size:20px;display:inline-block}.hmbkp-upsell{margin-top:40px;padding-top:16px;border-top:1px solid #ccc}.hmbkp-upsell a{color:#57792b}.hmbkp-upsell a:hover{color:#98c063}.hmbkp-upsell-sep{color:#bbb}.hmbkp-upsell ul{overflow:hidden}.hmbkp-upsell li{float:left;margin:0 20px 20px 0}.hmbkp-upsell img{display:block;margin:0 auto;max-width:120px;min-height:60px}.hmbkp-upsell ul a{display:block;margin-bottom:0;width:120px}.hmbkp-upsell .howto{font-weight:400;display:inline}.hmbkp-upsell .hmbkp_hide{float:right}.hmbkp-schedule-sentence{font-size:16px;font-weight:lighter;margin:20px 0;background-color:#FBFBFB;padding:20px;border:1px solid #e5e5e5;box-shadow:0 1px 1px rgba(0,0,0,.04)}.hmbkp-schedule-sentence::before{content:"\2714";margin-right:10px;width:16px;height:60px;display:block;float:left}.hmbkp-schedule-sentence.hmbkp-error:before{content:"\2718"}.hmbkp-schedule-sentence.hmbkp-running:before{width:20px;height:80px;margin:-1px 10px 0 0;content:"";background:transparent url(spinner-2x.gif) no-repeat 0 0;background-size:20px;display:inline-block}.hmbkp-schedule-sentence .hmbkp-status{display:none;font-size:12px;color:#666;margin:2px 0 0 30px}.hmbkp-schedule-sentence.hmbkp-running .hmbkp-status{display:block}.hmbkp-schedule-sentence.hmbkp-running .hmbkp-schedule-actions{display:none}.hmbkp-schedule-sentence :not(a)[title]{border-bottom:1px dotted #CCC;cursor:help}.hmbkp-schedule-sentence .hmbkp-status[title]{border-bottom:none}.hmbkp-schedule-sentence .submit{padding:0}.hmbkp-schedule-sentence .hmbkp-schedule-actions{visibility:visible;font-size:12px;font-weight:400;margin:0 0 0 26px}.hmbkp-schedule-actions a{white-space:nowrap}.hmbkp-schedule-settings{border-top:1px solid #e5e5e5;margin:20px -20px -20px;background-color:#f5f5f5;padding:0 20px 20px}.hmbkp-ajax-loading,button.hmbkp-ajax-loading{padding-left:20px;position:relative}.hmbkp-ajax-loading::after{content:"";width:16px;height:16px;background-image:url(spinner-2x.gif);background-size:16px 16px;background-repeat:no-repeat;background-position:0 0;position:absolute;right:-30px;top:5px}.delete-action{color:#a00;-webkit-transition:all 300ms ease;-moz-transition:all 300ms ease;-ms-transition:all 300ms ease;-o-transition:all 300ms ease;transition:all 300ms ease}.delete-action:hover .delete-action:focus{color:red;-webkit-transition:all 300ms ease;-moz-transition:all 300ms ease;-ms-transition:all 300ms ease;-o-transition:all 300ms ease;transition:all 300ms ease}.strikethrough{text-decoration:line-through}table.widefat tbody tr:nth-child(even){background-color:#f9f9f9}.hmbkp-exclude-settings td:first-child,.hmbkp-exclude-settings th:first-child{width:20px;padding-right:0}.hmbkp-exclude-settings thead tr:last-child{background-color:#f9f9f9}.hmbkp-exclude-settings table .button-secondary{line-height:18px;height:20px}thead td{border-bottom:1px solid #e1e1e1}.hmbkp-exclude-settings table .spinner{display:block;float:left;margin:0}.hmbkp-schedule-settings .column-format code{white-space:nowrap}.column-filesize code{position:relative}.column-filesize .dashicons-update{display:none;overflow:hidden;position:absolute;width:100%;left:0;text-align:center;background-color:rgba(255,255,255,.8)}.column-filesize .dashicons-update span{display:none}.column-filesize:hover .dashicons-update{display:inline-block}.hmbkp-exclude-settings td span.reason{color:#CCC}.server-info{overflow:auto;max-height:50%;outline:#000 1px solid}.server-info pre{max-height:100px;overflow-x:hidden}#intercom-info{background:#0074a2;color:#fff;display:inline-block;margin-bottom:-3px;padding:3px 8px}#intercom-info:hover{background:#2ea2cc;color:#fff}#intercom-info span.dashicons-admin-users{position:relative;display:inline-block;vertical-align:middle;top:-2px}pre{background-color:#eee;padding:10px;white-space:pre;max-height:320px;overflow:auto;word-wrap:normal!important}@media screen and (max-width:768px){.wrap h2{padding:10px 0 0}.hmbkp-schedule-sentence::before{height:80px}h2 .nav-tab{display:block;padding:10px;margin:0}.hmbkp-schedule-sentence{margin:10px 0;padding:10px}#intercom-info{display:none}.hmbkp-schedule-settings{padding:0 10px 10px}.hmbkp-exclude-settings table{margin:0 -10px;border-left:none;border-right:none;width:calc(100% + 20px)}.hmbkp-exclude-settings tr>:first-child,.hmbkp-schedule-settings thead tr:nth-child(2),.hmbkp-schedule-settings tr :nth-child(4),.hmbkp-schedule-settings tr :nth-child(5){display:none}.hmbkp-schedule-settings{margin-left:-10px;margin-right:-10px;margin-bottom:-10px}table.widefat tbody tr:nth-child(even){background-color:#fff}table.widefat tbody tr:nth-child(odd){background-color:#f9f9f9}}
1
+ .hmbkp-schedule-actions a,.hmbkp-schedule-settings .column-format code{white-space:nowrap}.hmbkp_active td:first-child>code:before{content:"\00a0 \2713 ";font-size:11px}.hmbkp_active{background:#E5F7E8}div#hmbkp-warning,h2.nav-tab-wrapper+div[id^=hmbkp]{margin:20px 0 15px}h2+div[id^=hmbkp] input{max-width:100%}.nav-tab.hmbkp-running:not(.nav-tab-active):before{width:20px;height:20px;margin:0 10px -4px 0;content:"";background:url(spinner-2x.gif) no-repeat;background-size:20px;display:inline-block}.hmbkp-upsell{margin-top:40px;padding-top:16px;border-top:1px solid #ccc}.hmbkp-upsell a{color:#57792b}.hmbkp-upsell a:hover{color:#98c063}.hmbkp-upsell-sep{color:#bbb}.hmbkp-upsell ul{overflow:hidden}.hmbkp-upsell li{float:left;margin:0 20px 20px 0}.hmbkp-upsell img{display:block;margin:0 auto;max-width:120px;min-height:60px}.hmbkp-upsell ul a{display:block;margin-bottom:0;width:120px}.hmbkp-upsell .howto{font-weight:400;display:inline}.hmbkp-upsell .hmbkp_hide{float:right}.hmbkp-schedule-sentence{font-size:16px;font-weight:lighter;margin:20px 0;background-color:#FBFBFB;padding:20px;border:1px solid #e5e5e5;box-shadow:0 1px 1px rgba(0,0,0,.04)}.hmbkp-schedule-sentence::before{content:"\2714";margin-right:10px;width:16px;height:60px;display:block;float:left}.hmbkp-schedule-sentence.hmbkp-error:before{content:"\2718"}.hmbkp-schedule-sentence.hmbkp-running:before{width:20px;height:80px;margin:-1px 10px 0 0;content:"";background:url(spinner-2x.gif) no-repeat;background-size:20px;display:inline-block}.hmbkp-schedule-sentence .hmbkp-status{display:none;font-size:12px;color:#666;margin:2px 0 0 30px}.hmbkp-schedule-sentence.hmbkp-running .hmbkp-status{display:block}.hmbkp-schedule-sentence.hmbkp-running .hmbkp-schedule-actions{display:none}.hmbkp-schedule-sentence :not(a)[title]{border-bottom:1px dotted #CCC;cursor:help}.hmbkp-schedule-sentence .hmbkp-status[title]{border-bottom:none}.hmbkp-schedule-sentence .submit{padding:0}.hmbkp-schedule-sentence .hmbkp-schedule-actions{visibility:visible;font-size:12px;font-weight:400;margin:0 0 0 26px}.hmbkp-schedule-settings{border-top:1px solid #e5e5e5;margin:20px -20px -20px;background-color:#f5f5f5;padding:0 20px 20px}.hmbkp-exclude-settings thead tr:last-child,table.widefat tbody tr:nth-child(odd){background-color:#f9f9f9}.hmbkp-ajax-loading,button.hmbkp-ajax-loading{padding-left:20px;position:relative}.hmbkp-ajax-loading::after{content:"";width:16px;height:16px;background-image:url(spinner-2x.gif);background-size:16px 16px;background-repeat:no-repeat;background-position:0 0;position:absolute;right:-30px;top:5px}.delete-action{color:#a00;-webkit-transition:all .3s ease;transition:all .3s ease}.delete-action:hover .delete-action:focus{color:red;-webkit-transition:all .3s ease;transition:all .3s ease}.strikethrough{text-decoration:line-through}.hmbkp-exclude-settings td:first-child,.hmbkp-exclude-settings th:first-child{width:20px;padding-right:0}.hmbkp-exclude-settings table .button-secondary{line-height:18px;height:20px}thead td{border-bottom:1px solid #e1e1e1}.hmbkp-exclude-settings table .spinner{display:block;float:left;margin:0}.column-filesize code{position:relative}.column-filesize .dashicons-update{display:none;overflow:hidden;position:absolute;width:100%;left:0;text-align:center;background-color:rgba(255,255,255,.8)}.column-filesize .dashicons-update span{display:none}.column-filesize:hover .dashicons-update{display:inline-block}.hmbkp-exclude-settings td span.reason{color:#CCC}.server-info{overflow:auto;max-height:50%;outline:#000 solid 1px}.server-info pre{max-height:100px;overflow-x:hidden}.page-title-action span.dashicons-admin-users{position:relative;display:inline-block;vertical-align:middle;top:-2px}pre{background-color:#eee;padding:10px;white-space:pre;max-height:320px;overflow:auto;word-wrap:normal!important}@media screen and (max-width:768px){.wrap h2{padding:10px 0 0}.hmbkp-schedule-sentence::before{height:80px}h2 .nav-tab{display:block;padding:10px;margin:0}#intercom-info,.hmbkp-exclude-settings tr>:first-child,.hmbkp-schedule-settings thead tr:nth-child(2),.hmbkp-schedule-settings tr :nth-child(4),.hmbkp-schedule-settings tr :nth-child(5){display:none}.hmbkp-schedule-sentence{margin:10px 0;padding:10px}.hmbkp-exclude-settings table{margin:0 -10px;border-left:none;border-right:none;width:calc(100% + 20px)}.hmbkp-schedule-settings{padding:0 10px 10px;margin-left:-10px;margin-right:-10px;margin-bottom:-10px}table.widefat tbody tr:nth-child(even){background-color:#fff}table.widefat tbody tr:nth-child(odd){background-color:#f9f9f9}}
assets/hmbkp.min.js CHANGED
@@ -1 +1 @@
1
- function hmbkpToggleScheduleFields(a){a="undefined"!=typeof a?a:"manually";var b=jQuery(".recurring-setting"),c=jQuery("#schedule-start"),d=jQuery("p.twice-js");switch(a){case"manually":b.hide();break;case"hmbkp_hourly":b.hide();break;case"hmbkp_daily":b.hide(),c.show(),d.hide();break;case"hmbkp_twicedaily":b.hide(),c.show(),d.show();break;case"hmbkp_weekly":case"hmbkp_fortnightly":b.hide(),jQuery("#start-day").show(),c.show(),d.hide();break;case"hmbkp_monthly":b.hide(),c.show(),jQuery("#start-date").show(),d.hide()}}function hmbkpCatchResponseAndOfferToEmail(a){a&&0!==a?(jQuery(".hmbkp-schedule-sentence.hmbkp-running").removeClass("hmbkp-running").addClass("hmbkp-error"),jQuery.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_backup_error",hmbkp_error:a},function(a){a&&0!==a&&location.reload(!0)})):location.reload(!0),jQuery(document).one("click",".hmbkp_send_error_via_email",function(b){b.preventDefault(),jQuery(this).addClass("hmbkp-ajax-loading").attr("disabled","disabled"),jQuery.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_email_error",hmbkp_error:a},function(){})})}jQuery(document).ready(function(a){a.ajaxSetup({cache:!1}),a("select#hmbkp_schedule_recurrence_type").size()&&(hmbkpToggleScheduleFields(a("select#hmbkp_schedule_recurrence_type").val()),a(document).on("change","select#hmbkp_schedule_recurrence_type",function(){hmbkpToggleScheduleFields(a(this).val())})),a(document).on("click",".hmbkp-schedule-actions .delete-action",function(a){confirm(hmbkp.delete_schedule)||a.preventDefault()}),a(document).on("click",".hmbkp_manage_backups_row .delete-action",function(a){confirm(hmbkp.delete_backup)||a.preventDefault()}),a(document).on("click",".hmbkp-edit-schedule-excludes-form .delete-action",function(a){confirm(hmbkp.remove_exclude_rule)||a.preventDefault()}),a.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_cron_test"},function(b){"1"!==b&&a(".wrap > h2").after(b)}),a(document).on("click",".hmbkp-run",function(b){a(this).closest(".hmbkp-schedule-sentence").addClass("hmbkp-running"),a(".hmbkp-error").removeClass("hmbkp-error");var c=a("[data-hmbkp-schedule-id]").attr("data-hmbkp-schedule-id");a.post(ajaxurl,{hmbkp_run_schedule_nonce:hmbkp.hmbkp_run_schedule_nonce,action:"hmbkp_run_schedule",hmbkp_schedule_id:c}),b.preventDefault()}),a(document).on("heartbeat-send",function(b,c){c.hmbkp_schedule_id=a("[data-hmbkp-schedule-id]").attr("data-hmbkp-schedule-id"),a(".hmbkp-schedule-sentence.hmbkp-running").size()?c.hmbkp_is_in_progress=!0:c.hmbkp_client_request="site_size"}),a(document).on("heartbeat-tick",function(b,c){if(0!==c.hmbkp_schedule_status||a(".hmbkp-error").size()||location.reload(!0),0!==c.hmbkp_schedule_status&&void 0!==c.hmbkp_schedule_status&&a(".hmbkp-status").replaceWith(c.hmbkp_schedule_status),void 0!==c.hmbkp_site_size&&a("code.calculating").size()){a("code.calculating").text(c.hmbkp_site_size);var d=a(".hmbkp-exclude-settings");d.size()&&d.replaceWith(c.hmbkp_dir_sizes)}}),a(document).on("click",".hmbkp-thickbox-close",function(a){a.preventDefault(),window.parent.tb_remove()})});
1
+ function hmbkpToggleScheduleFields(a){a="undefined"!=typeof a?a:"manually";var b=jQuery(".recurring-setting"),c=jQuery("#schedule-start"),d=jQuery(".twice-js");switch(a){case"manually":b.hide();break;case"hourly":b.hide();break;case"daily":b.hide(),c.show(),d.hide();break;case"twicedaily":b.hide(),c.show(),d.show();break;case"weekly":case"fortnightly":b.hide(),jQuery("#start-day").show(),c.show(),d.hide();break;case"monthly":b.hide(),c.show(),jQuery("#start-date").show(),d.hide()}}function hmbkpCatchResponseAndOfferToEmail(a){a&&0!==a?(jQuery(".hmbkp-schedule-sentence.hmbkp-running").removeClass("hmbkp-running").addClass("hmbkp-error"),jQuery.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_backup_error",hmbkp_error:a},function(a){a&&0!==a&&location.reload(!0)})):location.reload(!0),jQuery(document).one("click",".hmbkp_send_error_via_email",function(b){b.preventDefault(),jQuery(this).addClass("hmbkp-ajax-loading").attr("disabled","disabled"),jQuery.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_email_error",hmbkp_error:a},function(){})})}jQuery(document).ready(function(a){"use strict";var b=a("select#hmbkp_schedule_recurrence_type");a.ajaxSetup({cache:!1}),b.length&&(hmbkpToggleScheduleFields(b.val()),a(document).on("change","select#hmbkp_schedule_recurrence_type",function(){hmbkpToggleScheduleFields(a(this).val())})),a(document).on("click",".hmbkp-schedule-actions .delete-action",function(a){confirm(hmbkp.delete_schedule)||a.preventDefault()}),a(document).on("click",".hmbkp_manage_backups_row .delete-action",function(a){confirm(hmbkp.delete_backup)||a.preventDefault()}),a(document).on("click",".hmbkp-edit-schedule-excludes-form .delete-action",function(a){confirm(hmbkp.remove_exclude_rule)||a.preventDefault()}),a.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_cron_test"},function(b){"1"!==b&&a(".wrap > h2").after(b)}),a(document).on("click",".hmbkp-run",function(b){a(this).closest(".hmbkp-schedule-sentence").addClass("hmbkp-running"),a(".hmbkp-error").removeClass("hmbkp-error");var c=a("[data-hmbkp-schedule-id]").attr("data-hmbkp-schedule-id");a.post(ajaxurl,{hmbkp_run_schedule_nonce:hmbkp.hmbkp_run_schedule_nonce,action:"hmbkp_run_schedule",hmbkp_schedule_id:c}),b.preventDefault()}),a(document).on("heartbeat-send",function(b,c){c.hmbkp_schedule_id=a("[data-hmbkp-schedule-id]").attr("data-hmbkp-schedule-id"),a(".hmbkp-schedule-sentence.hmbkp-running").length?c.hmbkp_is_in_progress=!0:c.hmbkp_client_request="site_size"}),a(document).on("heartbeat-tick",function(b,c){if(0!==c.hmbkp_schedule_status||a(".hmbkp-error").length||location.reload(!0),0!==c.hmbkp_schedule_status&&void 0!==c.hmbkp_schedule_status&&a(".hmbkp-status").replaceWith(c.hmbkp_schedule_status),void 0!==c.hmbkp_site_size&&a("code.calculating").length){a("code.calculating").text(c.hmbkp_site_size);var d=a(".hmbkp-exclude-settings");d.length&&d.replaceWith(c.hmbkp_dir_sizes)}}),a(document).on("click",".hmbkp-thickbox-close",function(a){a.preventDefault(),window.parent.tb_remove()})});
backdrop/task.php CHANGED
@@ -55,7 +55,7 @@ class HM_Backdrop_Task {
55
  'body' => $data,
56
  'timeout' => 0.01,
57
  'blocking' => false,
58
- 'sslverify' => apply_filters( 'https_local_ssl_verify', true ),
59
  );
60
  wp_remote_post( $server_url, $args );
61
  return true;
@@ -68,4 +68,4 @@ class HM_Backdrop_Task {
68
  protected function get_unique_id() {
69
  return substr( sha1( serialize( $this->callback ) . serialize( $this->params ) ), -28 );
70
  }
71
- }
55
  'body' => $data,
56
  'timeout' => 0.01,
57
  'blocking' => false,
58
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
59
  );
60
  wp_remote_post( $server_url, $args );
61
  return true;
68
  protected function get_unique_id() {
69
  return substr( sha1( serialize( $this->callback ) . serialize( $this->params ) ), -28 );
70
  }
71
+ }
backupwordpress.php CHANGED
@@ -3,10 +3,10 @@
3
  Plugin Name: BackUpWordPress
4
  Plugin URI: http://bwp.hmn.md/
5
  Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools &rarr; Backups</strong>. On multisite, you'll find me under the Network Settings menu.
6
- Version: 3.2.7
7
  Author: Human Made Limited
8
  Author URI: http://hmn.md/
9
- License: GPL-2.0+
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.txt
11
  Text Domain: backupwordpress
12
  Domain Path: /languages
@@ -50,5 +50,5 @@ if ( version_compare( phpversion(), '5.3', '>=' ) ) {
50
  require_once( HMBKP_PLUGIN_PATH . 'classes/class-plugin.php' );
51
 
52
  } else {
53
- wp_die( sprintf( __( 'BackUpWordPress will not work on this site. ( PHP Version %s is unsupported )', 'backupwordpress' ), phpversion() ), __( 'BackUpWordPress Error', 'backupwordpress' ), array( 'back_link' => true ) );
54
  }
3
  Plugin Name: BackUpWordPress
4
  Plugin URI: http://bwp.hmn.md/
5
  Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools &rarr; Backups</strong>. On multisite, you'll find me under the Network Settings menu.
6
+ Version: 3.3.0
7
  Author: Human Made Limited
8
  Author URI: http://hmn.md/
9
+ License: GPL-2+
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.txt
11
  Text Domain: backupwordpress
12
  Domain Path: /languages
50
  require_once( HMBKP_PLUGIN_PATH . 'classes/class-plugin.php' );
51
 
52
  } else {
53
+ wp_die( sprintf( __( 'BackUpWordPress will not work on this site: PHP Version %s is unsupported.', 'backupwordpress' ), phpversion() ), __( 'BackUpWordPress Error', 'backupwordpress' ), array( 'back_link' => true ) );
54
  }
changelog.txt DELETED
@@ -1,5 +0,0 @@
1
- 5c88eed (HEAD -> master, origin/master, origin/HEAD) Merge pull request #813 from humanmade/mu-settings-page
2
- d924e1e (origin/mu-settings-page, mu-settings-page) Fix settings URL
3
- 297ab9c Merge pull request #820 from herrherrmann/master
4
- 63d1ad0 Updated and extended German translation.
5
- 29710f0 Fixes admin page slug for multisite
 
 
 
 
 
classes/class-backup.php CHANGED
@@ -1,1968 +1,1855 @@
1
  <?php
2
 
3
- namespace HM\BackUpWordPress {
4
- use Symfony\Component\Finder\Finder;
5
-
6
- /**
7
- * Generic file and database backup class
8
- *
9
- * @version 2.3
10
- */
11
- class Backup {
12
-
13
- /**
14
- * The backup type, must be either complete, file or database
15
- *
16
- * @string
17
- */
18
- private $type = '';
19
-
20
- /**
21
- * The filename of the backup file
22
- *
23
- * @string
24
- */
25
- private $archive_filename = '';
26
-
27
- /**
28
- * The filename of the database dump
29
- *
30
- * @string
31
- */
32
- private $database_dump_filename = '';
33
-
34
- /**
35
- * The path to the zip command
36
- *
37
- * @string
38
- */
39
- private $zip_command_path;
40
-
41
- /**
42
- * The path to the mysqldump command
43
- *
44
- * @string
45
- */
46
- private $mysqldump_command_path;
47
-
48
- /**
49
- * The filename of the existing backup file
50
- *
51
- * @string
52
- */
53
- private $existing_archive_filepath = '';
54
-
55
- /**
56
- * An array of exclude rules
57
- *
58
- * @array
59
- */
60
- private $excludes = array();
61
-
62
- /**
63
- * The path that should be backed up
64
- *
65
- * @var string
66
- */
67
- private $root = '';
68
-
69
- /**
70
- * Holds the current db connection
71
- *
72
- * @var resource
73
- */
74
- private $db;
75
-
76
- /**
77
- * An array of all the files in root
78
- * excluding excludes and unreadable files
79
- *
80
- * @var array
81
- */
82
- private $files = array();
83
-
84
- /**
85
- * An array of all the files in root
86
- * that match the exclude rules
87
- *
88
- * @var array
89
- */
90
- private $excluded_files = array();
91
-
92
- /**
93
- * An array of all the files in root
94
- * that are unreadable
95
- *
96
- * @var array
97
- */
98
- private $unreadable_files = array();
99
-
100
- /**
101
- * An array of all the files in root
102
- * that will be included in the backup
103
- *
104
- * @var array
105
- */
106
- protected $included_files = array();
107
-
108
- /**
109
- * Contains an array of errors
110
- *
111
- * @var mixed
112
- */
113
- private $errors = array();
114
-
115
- /**
116
- * Contains an array of warnings
117
- *
118
- * @var mixed
119
- */
120
- private $warnings = array();
121
-
122
- /**
123
- * The archive method used
124
- *
125
- * @var string
126
- */
127
- private $archive_method = '';
128
-
129
- /**
130
- * The mysqldump method used
131
- *
132
- * @var string
133
- */
134
- private $mysqldump_method = '';
135
-
136
- /**
137
- * @var bool
138
- */
139
- protected $mysqldump_verified = false;
140
-
141
- /**
142
- * @var bool
143
- */
144
- protected $archive_verified = false;
145
-
146
- /**
147
- * Hacky way to force a fallback to PclZip
148
- *
149
- * @todo re-factor out of this mess
150
- * @var bool
151
- */
152
- public $skip_zip_archive = false;
153
-
154
- /**
155
- * @var string
156
- */
157
- protected $action_callback = '';
158
-
159
- /**
160
- * List of patterns we want to exclude by default.
161
- * @var array
162
- */
163
- protected $default_excludes = array(
164
- '.git/',
165
- '.svn/',
166
- '.DS_Store',
167
- '.idea/',
168
- 'backwpup-*',
169
- 'updraft',
170
- 'wp-snapshots',
171
- 'backupbuddy_backups',
172
- 'pb_backupbuddy',
173
- 'backup-db',
174
- 'Envato-backups',
175
- 'managewp',
176
- 'backupwordpress-*-backups'
177
- );
178
 
179
- /**
180
- * Returns a filterable array of excluded directories and files.
181
- *
182
- * @return mixed|void
183
- */
184
- public function default_excludes() {
185
- return apply_filters( 'hmbkp_default_excludes', $this->default_excludes );
186
- }
187
 
188
- /**
189
- * Check whether safe mode is active or not
190
- *
191
- * @param string $ini_get_callback
192
- *
193
- * @return bool
194
- */
195
- public static function is_safe_mode_active( $ini_get_callback = 'ini_get' ) {
196
 
197
- $safe_mode = @call_user_func( $ini_get_callback, 'safe_mode' );
 
 
 
 
 
198
 
199
- if ( $safe_mode && strtolower( $safe_mode ) != 'off' ) {
200
- return true;
201
- }
 
 
 
202
 
203
- return false;
 
 
 
 
 
204
 
205
- }
 
 
 
 
 
206
 
207
- /**
208
- * Check whether shell_exec has been disabled.
209
- *
210
- * @return bool
211
- */
212
- public static function is_shell_exec_available() {
213
 
214
- // Are we in Safe Mode
215
- if ( self::is_safe_mode_active() ) {
216
- return false;
217
- }
 
 
218
 
219
- // Is shell_exec or escapeshellcmd or escapeshellarg disabled?
220
- if ( self::is_function_disabled( 'suhosin.executor.func.blacklist' ) ) {
221
- return false;
222
- }
 
 
223
 
224
- // Functions can also be disabled via suhosin
225
- if ( self::is_function_disabled( 'disable_functions' ) ) {
226
- return false;
227
- }
 
 
228
 
229
- // Can we issue a simple echo command?
230
- if ( ! @shell_exec( 'echo backupwordpress' ) ) {
231
- return false;
232
- }
 
 
 
233
 
234
- return true;
 
 
 
 
 
 
235
 
236
- }
 
 
 
 
 
 
237
 
238
- protected static function is_function_disabled( $ini_setting ) {
 
 
 
 
 
 
239
 
240
- if ( array_intersect( array(
241
- 'shell_exec',
242
- 'escapeshellarg',
243
- 'escapeshellcmd'
244
- ), array_map( 'trim', explode( ',', @ini_get( $ini_setting ) ) ) ) ) {
245
- return false;
246
- }
247
 
248
- }
 
 
 
 
 
249
 
 
 
 
 
 
 
250
 
251
- /**
252
- * Attempt to work out the root directory of the site, that
253
- * is, the path equivelant of home_url().
254
- *
255
- * @return string $home_path
256
- */
257
- public static function get_home_path() {
258
 
259
- if ( defined( 'HMBKP_ROOT' ) && HMBKP_ROOT ) {
260
- return self::conform_dir( HMBKP_ROOT );
261
- }
 
262
 
263
- $home_url = home_url();
264
- $site_url = site_url();
 
 
265
 
266
- $home_path = ABSPATH;
 
 
 
267
 
268
- // If site_url contains home_url and they differ then assume WordPress is installed in a sub directory
269
- if ( $home_url !== $site_url && strpos( $site_url, $home_url ) === 0 ) {
270
- $home_path = trailingslashit( substr( self::conform_dir( ABSPATH ), 0, strrpos( self::conform_dir( ABSPATH ), str_replace( $home_url, '', $site_url ) ) ) );
271
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
- return self::conform_dir( $home_path );
 
 
 
 
 
 
 
 
 
274
 
 
 
275
  }
276
 
 
277
 
278
- /**
279
- * Sanitize a directory path
280
- *
281
- * @param string $dir
282
- * @param bool $recursive
283
- *
284
- * @return string
285
- */
286
- public static function conform_dir( $dir = '/', $recursive = false ) {
287
 
288
- // Replace single forward slash (looks like double slash because we have to escape it)
289
- $dir = str_replace( '\\', '/', $dir );
290
- $dir = str_replace( '//', '/', $dir );
 
 
 
291
 
292
- // Remove the trailing slash
293
- if ( $dir !== '/' ) {
294
- $dir = untrailingslashit( $dir );
295
- }
296
 
297
- // Carry on until completely normalized
298
- if ( ! $recursive && self::conform_dir( $dir, true ) != $dir ) {
299
- return self::conform_dir( $dir );
300
- }
301
 
302
- return (string) $dir;
 
 
 
303
 
 
 
 
304
  }
305
 
306
- /**
307
- * Sets up the default properties
308
- */
309
- public function __construct() {
310
 
311
- // Raise the memory limit and max_execution time
312
- @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
313
- @set_time_limit( 0 );
314
 
315
- // Set a custom error handler so we can track errors
316
- set_error_handler( array( $this, 'error_handler' ) );
317
 
318
- // Some properties can be overridden with defines
319
- if ( defined( 'HMBKP_EXCLUDE' ) && HMBKP_EXCLUDE ) {
320
- $this->set_excludes( HMBKP_EXCLUDE, true );
321
- }
 
 
 
322
 
323
- if ( defined( 'HMBKP_MYSQLDUMP_PATH' ) ) {
324
- $this->set_mysqldump_command_path( HMBKP_MYSQLDUMP_PATH );
325
- }
326
 
327
- if ( defined( 'HMBKP_ZIP_PATH' ) ) {
328
- $this->set_zip_command_path( HMBKP_ZIP_PATH );
329
- }
330
 
331
- if ( defined( 'HMBKP_ZIP_PATH' ) && HMBKP_ZIP_PATH === 'PclZip' && $this->skip_zip_archive = true ) {
332
- $this->set_zip_command_path( false );
333
- }
 
 
 
 
334
 
 
 
335
  }
336
 
337
- /**
338
- * Simple class wrapper for Path::get_path()
339
- *
340
- * @return string
341
- */
342
- private function get_path() {
343
- return Path::get_instance()->get_path();
344
- }
345
-
346
- /**
347
- * Get the full filepath to the archive file
348
- *
349
- * @return string
350
- */
351
- public function get_archive_filepath() {
352
- return trailingslashit( $this->get_path() ) . $this->get_archive_filename();
353
- }
354
-
355
- /**
356
- * Get the filename of the archive file
357
- *
358
- * @return string
359
- */
360
- public function get_archive_filename() {
361
-
362
- if ( empty( $this->archive_filename ) ) {
363
- $this->set_archive_filename( implode( '-', array(
364
- sanitize_title( str_ireplace( array(
365
- 'http://',
366
- 'https://',
367
- 'www'
368
- ), '', home_url() ) ),
369
- 'backup',
370
- current_time( 'Y-m-d-H-i-s' )
371
- ) ) . '.zip' );
372
- }
373
 
374
- return $this->archive_filename;
375
 
 
 
 
376
  }
377
 
378
- /**
379
- * Set the filename of the archive file
380
- *
381
- * @param string $filename
382
- *
383
- * @return \WP_Error|null
384
- */
385
- public function set_archive_filename( $filename ) {
386
 
387
- if ( empty( $filename ) || ! is_string( $filename ) ) {
388
- return new \WP_Error( 'invalid_file_name', __( 'archive filename must be a non empty string', 'backupwordpress' ) );
389
- }
390
 
391
- if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'zip' ) {
392
- return new \WP_Error( 'invalid_file_extension', sprintf( __( 'invalid file extension for archive filename <code>%s</code>', 'backupwordpress' ), $filename ) );
393
- }
 
394
 
395
- $this->archive_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
 
 
396
 
 
 
 
 
 
 
397
  }
398
 
399
- /**
400
- * Get the full filepath to the database dump file.
401
- *
402
- * @return string
403
- */
404
- public function get_database_dump_filepath() {
405
- return trailingslashit( $this->get_path() ) . $this->get_database_dump_filename();
406
  }
407
 
408
- /**
409
- * Get the filename of the database dump file
410
- *
411
- * @return string
412
- */
413
- public function get_database_dump_filename() {
414
 
415
- if ( empty( $this->database_dump_filename ) ) {
416
- $this->set_database_dump_filename( 'database_' . DB_NAME . '.sql' );
417
- }
418
 
419
- return $this->database_dump_filename;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  }
422
 
423
- /**
424
- * Set the filename of the database dump file
425
- *
426
- * @param string $filename
427
- *
428
- * @return \WP_Error|null
429
- */
430
- public function set_database_dump_filename( $filename ) {
431
 
432
- if ( empty( $filename ) || ! is_string( $filename ) ) {
433
- return new \WP_Error( 'invalid_file_name', __( 'database dump filename must be a non empty string', 'backupwordpress' ) );
434
- }
435
 
436
- if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'sql' ) {
437
- return new \WP_Error( 'invalid_file_extension', sprintf( __( 'invalid file extension for database dump filename <code>%s</code>', 'backupwordpress' ), $filename ) );
438
- }
 
 
 
 
 
439
 
440
- $this->database_dump_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
 
 
441
 
 
 
442
  }
443
 
444
- /**
445
- * Get the root directory to backup from
446
- *
447
- * Defaults to the root of the path equivalent of your home_url
448
- *
449
- * @return string
450
- */
451
- public function get_root() {
452
 
453
- if ( empty( $this->root ) ) {
454
- $this->set_root( self::conform_dir( self::get_home_path() ) );
455
- }
456
 
457
- return $this->root;
 
 
 
 
 
 
 
458
 
 
 
 
 
 
 
 
 
 
459
  }
460
 
461
- /**
462
- * Set the root directory to backup from
463
- *
464
- * @param string $path
465
- *
466
- * @return \WP_Error|null
467
- */
468
- public function set_root( $path ) {
469
 
470
- if ( empty( $path ) || ! is_string( $path ) || ! is_dir( $path ) ) {
471
- return new \WP_Error( 'invalid_directory_path', sprintf( __( 'Invalid root path <code>%s</code> must be a valid directory path', 'backupwordpress' ), $path ) );
472
- }
473
 
474
- $this->root = self::conform_dir( $path );
 
 
 
 
 
 
 
475
 
 
 
476
  }
477
 
478
- /**
479
- * Get the filepath for the existing archive
480
- *
481
- * @return string
482
- */
483
- public function get_existing_archive_filepath() {
484
- return $this->existing_archive_filepath;
485
  }
486
 
487
- /**
488
- * Set the filepath for the existing archive
489
- *
490
- * @param string $existing_archive_filepath
491
- *
492
- * @return null
493
- */
494
- public function set_existing_archive_filepath( $existing_archive_filepath ) {
495
 
496
- if ( empty( $existing_archive_filepath ) || ! is_string( $existing_archive_filepath ) ) {
497
- return new \WP_Error( 'invalid_existing_archive_filepath', sprintf( __( 'Invalid existing archive filepath <code>%s</code> must be a non empty (string)', 'backupwordpress' ), $existing_archive_filepath ) );
498
- }
499
 
500
- $this->existing_archive_filepath = self::conform_dir( $existing_archive_filepath );
 
 
 
 
 
 
 
501
 
 
 
502
  }
503
 
504
- /**
505
- * Get the archive method that was used for the backup
506
- *
507
- * Will be either zip, ZipArchive or PclZip
508
- *
509
- */
510
- public function get_archive_method() {
511
- return $this->archive_method;
512
- }
 
 
 
513
 
514
- /**
515
- * Get the database dump method that was used for the backup
516
- *
517
- * Will be either mysqldump or mysqldump_fallback
518
- *
519
- */
520
- public function get_mysqldump_method() {
521
- return $this->mysqldump_method;
522
  }
523
 
524
- /**
525
- * Get the backup type
526
- *
527
- * Defaults to complete
528
- *
529
- */
530
- public function get_type() {
531
 
532
- if ( empty( $this->type ) ) {
533
- $this->set_type( 'complete' );
534
- }
535
 
536
- return $this->type;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
 
 
 
538
  }
539
 
540
- /**
541
- * Set the backup type
542
- *
543
- * $type must be one of complete, database or file
544
- *
545
- * @param string $type
546
- *
547
- * @return \WP_Error|null
548
- */
549
- public function set_type( $type ) {
550
 
551
- if ( ! is_string( $type ) || ! in_array( $type, array( 'file', 'database', 'complete' ) ) ) {
552
- return new \WP_Error( 'invalid_backup_type', sprintf( __( 'Invalid backup type <code>%s</code> must be one of (string) file, database or complete', 'backupwordpress' ), $type ) );
553
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
 
555
- $this->type = $type;
 
 
 
 
 
 
556
 
 
 
557
  }
558
 
559
- /**
560
- * Get the path to the mysqldump bin
561
- *
562
- * If not explicitly set will attempt to work
563
- * it out by checking common locations
564
- *
565
- * @return string
566
- */
567
- public function get_mysqldump_command_path() {
568
 
569
- // Check shell_exec is available
570
- if ( ! self::is_shell_exec_available() ) {
571
- return '';
572
- }
573
 
574
- // Return now if it's already been set
575
- if ( isset( $this->mysqldump_command_path ) ) {
576
- return $this->mysqldump_command_path;
577
- }
 
 
 
 
 
 
578
 
579
- $this->mysqldump_command_path = '';
 
 
580
 
581
- // Does mysqldump work
582
- if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) {
583
 
584
- // If so store it for later
585
- $this->set_mysqldump_command_path( 'mysqldump' );
586
 
587
- // And return now
588
- return $this->mysqldump_command_path;
 
 
 
 
 
 
 
589
 
590
- }
 
 
 
591
 
592
- // List of possible mysqldump locations
593
- $mysqldump_locations = array(
594
- '/usr/local/bin/mysqldump',
595
- '/usr/local/mysql/bin/mysqldump',
596
- '/usr/mysql/bin/mysqldump',
597
- '/usr/bin/mysqldump',
598
- '/opt/local/lib/mysql6/bin/mysqldump',
599
- '/opt/local/lib/mysql5/bin/mysqldump',
600
- '/opt/local/lib/mysql4/bin/mysqldump',
601
- '/xampp/mysql/bin/mysqldump',
602
- '/Program Files/xampp/mysql/bin/mysqldump',
603
- '/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
604
- '/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump',
605
- '/Program Files/MySQL/MySQL Server 5.6/bin/mysqldump',
606
- '/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
607
- '/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
608
- '/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
609
- '/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
610
- '/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump',
611
- '/opt/local/bin/mysqldump'
612
- );
613
-
614
- // Find the first one which works
615
- foreach ( $mysqldump_locations as $location ) {
616
- if ( (is_null( shell_exec( 'hash ' . self::conform_dir( $location ) . ' 2>&1' ) ) ) && @is_executable( self::conform_dir( $location ) ) ) {
617
- $this->set_mysqldump_command_path( $location );
618
- break; // Found one
619
- }
620
- }
621
 
 
 
 
 
622
  return $this->mysqldump_command_path;
623
 
624
  }
625
 
626
- /**
627
- * Set the path to the mysqldump bin
628
- *
629
- * Setting the path to false will cause the database
630
- * dump to use the php fallback
631
- *
632
- * @param mixed $path
633
- */
634
- public function set_mysqldump_command_path( $path ) {
635
- $this->mysqldump_command_path = $path;
636
- }
637
-
638
- /**
639
- * Get the path to the zip bin
640
- *
641
- * If not explicitly set will attempt to work
642
- * it out by checking common locations
643
- *
644
- * @return string
645
- */
646
- public function get_zip_command_path() {
647
-
648
- // Check shell_exec is available
649
- if ( ! self::is_shell_exec_available() ) {
650
- return '';
651
- }
652
 
653
- // Return now if it's already been set
654
- if ( isset( $this->zip_command_path ) ) {
655
- return $this->zip_command_path;
 
 
656
  }
 
657
 
658
- $this->zip_command_path = '';
659
 
660
- // Does zip work
661
- if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) {
662
 
663
- // If so store it for later
664
- $this->set_zip_command_path( 'zip' );
 
 
 
 
 
 
 
 
 
665
 
666
- // And return now
667
- return $this->zip_command_path;
 
 
 
 
 
 
 
668
 
669
- }
 
 
 
670
 
671
- // List of possible zip locations
672
- $zip_locations = array(
673
- '/usr/bin/zip',
674
- '/opt/local/bin/zip'
675
- );
676
-
677
- // Find the first one which works
678
- foreach ( $zip_locations as $location ) {
679
- if ( @is_executable( self::conform_dir( $location ) ) ) {
680
- $this->set_zip_command_path( $location );
681
- break; // Found one
682
- }
683
- }
684
 
 
 
 
 
 
 
 
 
 
685
  return $this->zip_command_path;
686
 
687
  }
688
 
689
- /**
690
- * Set the path to the zip bin
691
- *
692
- * Setting the path to false will cause the database
693
- * dump to use the php fallback
694
- *
695
- * @param mixed $path
696
- */
697
- public function set_zip_command_path( $path ) {
698
- $this->zip_command_path = $path;
699
- }
700
-
701
- /**
702
- * Fire actions for the various backup stages
703
- *
704
- * Callers can register callbacks to be called using `set_action_callback`
705
- * Both the action and the instance on Backup are then passed to the callback function
706
- *
707
- * @see set_action_callback
708
- *
709
- * @param string $action The event to fire
710
- */
711
- protected function do_action( $action ) {
712
-
713
- // If we have any callbacks then let's fire them
714
- if ( ! empty( $this->action_callback ) ) {
715
-
716
- // Order them by priority, lowest priority first
717
- ksort( $this->action_callback );
718
-
719
- foreach ( $this->action_callback as $priority ) {
720
- foreach ( $priority as $callback ) {
721
- call_user_func( $callback, $action, $this );
722
- }
723
- }
724
 
 
 
 
 
 
725
  }
 
726
 
727
- // Also fire a global WordPress action
728
- do_action( $action, $this );
729
 
730
- }
731
 
732
- /**
733
- * Allow the caller to set a callback function that will be invoked whenever
734
- * an action fires
735
- *
736
- * @see do_action
737
- * @see /do_action
738
- *
739
- * @param callable $callback The function or method to be called
740
- * @param int $priority The priority of the callback
741
- */
742
- public function set_action_callback( $callback, $priority = 10 ) {
743
- $this->action_callback[ $priority ][] = $callback;
744
- }
745
 
746
- /**
747
- * Kick off a backup
748
- *
749
- * @todo should be renamed so it's not same as class
750
- * @return null
751
- */
752
- public function backup() {
 
 
 
 
 
 
 
753
 
754
- $this->do_action( 'hmbkp_backup_started' );
 
755
 
756
- // Backup database
757
- if ( $this->get_type() !== 'file' ) {
758
- $this->dump_database();
 
759
  }
760
 
761
- // Zip everything up
762
- $this->archive();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
 
764
- $this->do_action( 'hmbkp_backup_complete' );
765
 
 
 
 
766
  }
767
 
768
- /**
769
- * Create the mysql backup
770
- *
771
- * Uses mysqldump if available, falls back to PHP
772
- * if not.
773
- *
774
- */
775
- public function dump_database() {
776
 
777
- // If we cannot run mysqldump via CLI, fallback to PHP
778
- if ( ! ( self::is_shell_exec_available() ) || is_wp_error( $this->user_can_connect() ) ) {
779
- $this->mysqldump_fallback();
780
- } else {
781
- // Attempt mysqldump command
782
- if ( $this->get_mysqldump_command_path() ) {
783
- $this->mysqldump();
784
- }
785
 
786
- if ( empty( $this->mysqldump_verified ) ) {
787
- $this->mysqldump_fallback();
788
- }
789
- }
790
 
791
- $this->do_action( 'hmbkp_mysqldump_finished' );
 
 
 
 
 
 
 
792
 
 
 
 
793
  }
794
 
795
- /**
796
- * Export the database to an .sql file via the command line with mysqldump
797
- */
798
- public function mysqldump() {
799
 
800
- $this->mysqldump_method = 'mysqldump';
801
 
802
- $this->do_action( 'hmbkp_mysqldump_started' );
803
 
804
- // Guess port or socket connection type
805
- $port_or_socket = strstr( DB_HOST, ':' );
 
 
806
 
807
- $host = DB_HOST;
808
 
809
- if ( ! empty( $port_or_socket ) ) {
810
 
811
- $host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
 
812
 
813
- $port_or_socket = substr( $port_or_socket, 1 );
814
 
815
- if ( 0 !== strpos( $port_or_socket, '/' ) ) {
816
 
817
- $port = intval( $port_or_socket );
818
 
819
- $maybe_socket = strstr( $port_or_socket, ':' );
820
 
821
- if ( ! empty( $maybe_socket ) ) {
822
 
823
- $socket = substr( $maybe_socket, 1 );
824
 
825
- }
826
 
827
- } else {
828
 
829
- $socket = $port_or_socket;
830
 
831
  }
832
- }
833
 
834
- // Path to the mysqldump executable
835
- $cmd = escapeshellarg( $this->get_mysqldump_command_path() );
836
 
837
- // We don't want to create a new DB
838
- $cmd .= ' --no-create-db';
839
 
840
- // Allow lock-tables to be overridden
841
- if ( ! defined( 'HMBKP_MYSQLDUMP_SINGLE_TRANSACTION' ) || false !== HMBKP_MYSQLDUMP_SINGLE_TRANSACTION ) {
842
- $cmd .= ' --single-transaction';
843
  }
 
844
 
845
- // Make sure binary data is exported properly
846
- $cmd .= ' --hex-blob';
847
 
848
- // Username
849
- $cmd .= ' -u ' . escapeshellarg( DB_USER );
850
 
851
- // Don't pass the password if it's blank
852
- if ( DB_PASSWORD ) {
853
- $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
854
- }
855
 
856
- // Set the host
857
- $cmd .= ' -h ' . escapeshellarg( $host );
858
 
859
- // Set the port if it was set
860
- if ( ! empty( $port ) && is_numeric( $port ) ) {
861
- $cmd .= ' -P ' . $port;
862
- }
863
 
864
- // Set the socket path
865
- if ( ! empty( $socket ) && ! is_numeric( $socket ) ) {
866
- $cmd .= ' --protocol=socket -S ' . $socket;
867
- }
868
 
869
- // The file we're saving too
870
- $cmd .= ' -r ' . escapeshellarg( $this->get_database_dump_filepath() );
871
 
872
- // The database we're dumping
873
- $cmd .= ' ' . escapeshellarg( DB_NAME );
 
 
874
 
875
- // Pipe STDERR to STDOUT
876
- $cmd .= ' 2>&1';
 
 
877
 
878
- // Store any returned data in an error
879
- $stderr = shell_exec( $cmd );
880
 
881
- // Skip the new password warning that is output in mysql > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
882
- if ( 'Warning: Using a password on the command line interface can be insecure.' === trim( $stderr ) ) {
883
- $stderr = '';
884
- }
885
 
886
- if ( $stderr ) {
887
- $this->error( $this->get_mysqldump_method(), $stderr );
888
- }
889
 
890
- $this->verify_mysqldump();
 
891
 
 
 
 
892
  }
893
 
894
- /**
895
- * PHP mysqldump fallback functions, exports the database to a .sql file
896
- *
897
- */
898
- public function mysqldump_fallback() {
899
 
900
- $this->errors_to_warnings( $this->get_mysqldump_method() );
901
 
902
- $this->mysqldump_method = 'mysqldump_fallback';
903
 
904
- $this->do_action( 'hmbkp_mysqldump_started' );
 
 
 
 
905
 
906
- $this->db = @mysql_pconnect( DB_HOST, DB_USER, DB_PASSWORD );
907
 
908
- if ( ! $this->db ) {
909
- $this->db = mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
910
- }
911
 
912
- if ( ! $this->db ) {
913
- return;
914
- }
915
 
916
- mysql_select_db( DB_NAME, $this->db );
917
 
918
- if ( function_exists( 'mysql_set_charset' ) ) {
919
- mysql_set_charset( DB_CHARSET, $this->db );
920
- }
921
 
922
- // Begin new backup of MySql
923
- $tables = mysql_query( 'SHOW TABLES' );
 
924
 
925
- $sql_file = "# WordPress : " . get_bloginfo( 'url' ) . " MySQL database backup\n";
926
- $sql_file .= "#\n";
927
- $sql_file .= "# Generated: " . date( 'l j. F Y H:i T' ) . "\n";
928
- $sql_file .= "# Hostname: " . DB_HOST . "\n";
929
- $sql_file .= "# Database: " . $this->sql_backquote( DB_NAME ) . "\n";
930
- $sql_file .= "# --------------------------------------------------------\n";
931
 
932
- for ( $i = 0; $i < mysql_num_rows( $tables ); $i ++ ) {
 
 
933
 
934
- $curr_table = mysql_tablename( $tables, $i );
 
935
 
936
- // Create the SQL statements
937
- $sql_file .= "# --------------------------------------------------------\n";
938
- $sql_file .= "# Table: " . $this->sql_backquote( $curr_table ) . "\n";
939
- $sql_file .= "# --------------------------------------------------------\n";
 
 
940
 
941
- $this->make_sql( $sql_file, $curr_table );
942
 
943
- }
 
 
 
 
 
 
 
944
 
945
  }
946
 
947
- /**
948
- * Zip up all the files.
949
- *
950
- * Attempts to use the shell zip command, if
951
- * thats not available then it falls back to
952
- * PHP ZipArchive and finally PclZip.
953
- *
954
- */
955
- public function archive() {
 
 
956
 
957
- // Do we have the path to the zip command
958
- if ( ( defined( 'HMBKP_FORCE_ZIP_METHOD' ) && ( 'zip' === HMBKP_FORCE_ZIP_METHOD ) ) || $this->get_zip_command_path() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959
  $this->zip();
960
  }
961
 
962
- // If not or if the shell zip failed then use ZipArchive
963
- if ( ( defined( 'HMBKP_FORCE_ZIP_METHOD' ) && ( 'ziparchive' === HMBKP_FORCE_ZIP_METHOD ) ) || ( empty( $this->archive_verified ) && class_exists( 'ZipArchive' ) && empty( $this->skip_zip_archive ) ) ) {
964
  $this->zip_archive();
 
 
965
  }
 
966
 
967
- // If ZipArchive is unavailable or one of the above failed
968
- if ( ( defined( 'HMBKP_FORCE_ZIP_METHOD' ) && ( 'pclzip' === HMBKP_FORCE_ZIP_METHOD ) ) || empty( $this->archive_verified ) ) {
969
- $this->pcl_zip();
970
- }
971
-
972
- // Delete the database dump file
973
- if ( file_exists( $this->get_database_dump_filepath() ) ) {
974
- unlink( $this->get_database_dump_filepath() );
975
- }
976
 
977
- $this->do_action( 'hmbkp_archive_finished' );
978
 
979
- }
980
 
981
- /**
982
- * Zip using the native zip command
983
- */
984
- public function zip() {
985
 
986
- $this->archive_method = 'zip';
987
 
988
- $this->do_action( 'hmbkp_archive_started' );
989
 
990
- // Add the database dump to the archive
991
- if ( 'file' !== $this->get_type() && file_exists( $this->get_database_dump_filepath() ) ) {
992
- $stderr = shell_exec( 'cd ' . escapeshellarg( $this->get_path() ) . ' && ' . escapeshellcmd( $this->get_zip_command_path() ) . ' -q ' . escapeshellarg( $this->get_archive_filepath() ) . ' ' . escapeshellarg( $this->get_database_dump_filename() ) . ' 2>&1' );
993
 
994
- if ( ! empty ( $stderr ) ) {
995
  $this->warning( $this->get_archive_method(), $stderr );
996
- }
997
  }
 
998
 
999
- // Zip up $this->root
1000
- if ( 'database' !== $this->get_type() ) {
1001
 
1002
- // cd to the site root
1003
- $command = 'cd ' . escapeshellarg( $this->get_root() );
1004
 
1005
- // Run the zip command with the recursive and quiet flags
1006
- $command .= ' && ' . escapeshellcmd( $this->get_zip_command_path() ) . ' -rq ';
1007
 
1008
- if ( defined( 'HMBKP_ENABLE_SYNC' ) && HMBKP_ENABLE_SYNC ) {
1009
-
1010
- // If the destination zip file already exists then let's just add changed files to save time
1011
- if ( file_exists( $this->get_archive_filepath() ) && $this->get_existing_archive_filepath() ) {
1012
- $command .= ' -FS ';
1013
- }
1014
 
 
 
 
1015
  }
1016
 
1017
- // Save the zip file to the correct path
1018
- $command .= escapeshellarg( $this->get_archive_filepath() ) . ' ./';
1019
-
1020
- // Pass exclude rules in if we have them
1021
- if ( $this->exclude_string( 'zip' ) ) {
1022
- $command .= ' -x ' . $this->exclude_string( 'zip' );
1023
- }
1024
 
1025
- // Push all output to STDERR
1026
- $command .= ' 2>&1';
1027
 
1028
- $stderr = shell_exec( $command );
 
 
 
1029
 
1030
- if ( ! empty ( $stderr ) ) {
1031
- $this->warning( $this->get_archive_method(), $stderr );
1032
- }
1033
 
1034
- }
1035
 
1036
- $this->verify_archive();
1037
 
 
 
1038
  }
1039
 
1040
- /**
1041
- * Fallback for creating zip archives if zip command is
1042
- * unavailable.
1043
- */
1044
- public function zip_archive() {
1045
 
1046
- $this->errors_to_warnings( $this->get_archive_method() );
1047
- $this->archive_method = 'ziparchive';
1048
 
1049
- $this->do_action( 'hmbkp_archive_started' );
 
 
 
 
1050
 
1051
- $zip = new \ZipArchive();
 
1052
 
1053
- if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->get_archive_filepath(), \ZIPARCHIVE::CREATE ) ) {
1054
- return;
1055
- }
1056
 
1057
- $excludes = $this->exclude_string( 'regex' );
1058
 
1059
- // Add the database
1060
- if ( $this->get_type() !== 'file' && file_exists( $this->get_database_dump_filepath() ) ) {
1061
- $zip->addFile( $this->get_database_dump_filepath(), $this->get_database_dump_filename() );
1062
- }
1063
 
1064
- if ( $this->get_type() !== 'database' ) {
1065
 
1066
- $files_added = 0;
 
 
 
1067
 
1068
- foreach ( $this->get_files() as $file ) {
1069
 
1070
- // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1071
- if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1072
- continue;
1073
- }
1074
 
1075
- // Skip unreadable files
1076
- if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1077
- continue;
1078
- }
1079
 
1080
- // Excludes
1081
- if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', self::conform_dir( $file->getPathname() ) ) ) ) {
1082
- continue;
1083
- }
1084
 
1085
- if ( $file->isDir() ) {
1086
- $zip->addEmptyDir( trailingslashit( str_ireplace( trailingslashit( $this->get_root() ), '', self::conform_dir( $file->getPathname() ) ) ) );
1087
- } elseif ( $file->isFile() ) {
1088
- $zip->addFile( $file->getPathname(), str_ireplace( trailingslashit( $this->get_root() ), '', self::conform_dir( $file->getPathname() ) ) );
1089
- }
1090
 
1091
- if ( ++ $files_added % 500 === 0 ) {
1092
- if ( ! $zip->close() || ! $zip->open( $this->get_archive_filepath(), \ZIPARCHIVE::CREATE ) ) {
1093
- return;
1094
- }
1095
- }
1096
 
 
 
 
 
1097
  }
1098
 
1099
- }
 
 
 
 
1100
 
1101
- if ( $zip->status ) {
1102
- $this->warning( $this->get_archive_method(), $zip->status );
1103
  }
1104
 
1105
- if ( $zip->statusSys ) {
1106
- $this->warning( $this->get_archive_method(), $zip->statusSys );
1107
- }
 
 
 
 
 
 
 
 
 
 
 
 
1108
 
1109
- $zip->close();
1110
 
1111
- $this->verify_archive();
1112
 
 
 
 
1113
  }
1114
 
1115
- /**
1116
- * Fallback for creating zip archives if zip command and ZipArchive are
1117
- * unavailable.
1118
- *
1119
- * Uses the PclZip library that ships with WordPress
1120
- */
1121
- public function pcl_zip() {
1122
 
1123
- $this->errors_to_warnings( $this->get_archive_method() );
1124
- $this->archive_method = 'pclzip';
 
 
1125
 
1126
- $this->do_action( 'hmbkp_archive_started' );
 
 
 
1127
 
1128
- global $_hmbkp_exclude_string;
1129
 
1130
- $_hmbkp_exclude_string = $this->exclude_string( 'regex' );
1131
 
1132
- $this->load_pclzip();
 
 
 
 
 
1133
 
1134
- $archive = new \PclZip( $this->get_archive_filepath() );
1135
 
1136
- // Add the database
1137
- if ( $this->get_type() !== 'file' && file_exists( $this->get_database_dump_filepath() ) ) {
1138
- if ( ! $archive->add( $this->get_database_dump_filepath(), \PCLZIP_OPT_REMOVE_PATH, $this->get_path() ) ) {
1139
- $this->warning( $this->get_archive_method(), $archive->errorInfo( true ) );
1140
- }
1141
- }
1142
 
1143
- // Zip up everything
1144
- if ( $this->get_type() !== 'database' ) {
1145
- if ( ! $archive->add( $this->get_root(), \PCLZIP_OPT_REMOVE_PATH, $this->get_root(), \PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) ) {
1146
- $this->warning( $this->get_archive_method(), $archive->errorInfo( true ) );
1147
- }
1148
- }
1149
 
1150
- unset( $GLOBALS['_hmbkp_exclude_string'] );
 
 
 
 
 
1151
 
1152
- $this->verify_archive();
1153
 
 
 
 
 
 
 
 
 
 
 
 
1154
  }
1155
 
1156
- public function verify_mysqldump() {
 
 
 
1157
 
1158
- $this->do_action( 'hmbkp_mysqldump_verify_started' );
1159
-
1160
- // If we've already passed then no need to check again
1161
- if ( ! empty( $this->mysqldump_verified ) ) {
1162
- return true;
1163
  }
 
1164
 
1165
- // If there are mysqldump errors delete the database dump file as mysqldump will still have written one
1166
- if ( $this->get_errors( $this->get_mysqldump_method() ) && file_exists( $this->get_database_dump_filepath() ) ) {
1167
- unlink( $this->get_database_dump_filepath() );
1168
- }
1169
 
1170
- // If we have an empty file delete it
1171
- if ( @filesize( $this->get_database_dump_filepath() ) === 0 ) {
1172
- unlink( $this->get_database_dump_filepath() );
1173
- }
1174
 
1175
- // If the file still exists then it must be good
1176
- if ( file_exists( $this->get_database_dump_filepath() ) ) {
1177
- return $this->mysqldump_verified = true;
1178
- }
1179
 
1180
- return false;
 
 
 
 
 
1181
 
 
 
1182
  }
1183
 
1184
- /**
1185
- * Verify that the archive is valid and contains all the files it should contain.
1186
- *
1187
- * @return bool
1188
- */
1189
- public function verify_archive() {
1190
 
1191
- $this->do_action( 'hmbkp_archive_verify_started' );
1192
 
1193
- // If we've already passed then no need to check again
1194
- if ( ! empty( $this->archive_verified ) ) {
1195
- return true;
 
 
1196
  }
1197
 
1198
- // If there are errors delete the backup file.
1199
- if ( $this->get_errors( $this->get_archive_method() ) && file_exists( $this->get_archive_filepath() ) ) {
1200
- unlink( $this->get_archive_filepath() );
1201
  }
1202
 
1203
- // If the archive file still exists assume it's good
1204
- if ( file_exists( $this->get_archive_filepath() ) ) {
1205
- return $this->archive_verified = true;
1206
  }
1207
 
1208
- return false;
1209
 
1210
  }
1211
 
1212
- /**
1213
- * Return an array of all files in the filesystem.
1214
- *
1215
- * @param bool $ignore_default_exclude_rules If true then will return all files under root. Otherwise returns all files except those matching default exclude rules.
1216
- *
1217
- * @return array
1218
- */
1219
- public function get_files( $ignore_default_exclude_rules = false ) {
1220
 
1221
- $found = array();
1222
 
1223
- if ( ! empty( $this->files ) ) {
1224
- return $this->files;
1225
- }
 
 
 
1226
 
1227
- $finder = new Finder();
1228
- $finder->followLinks();
1229
- $finder->ignoreDotFiles( false );
1230
- $finder->ignoreUnreadableDirs();
1231
 
1232
- if ( ! $ignore_default_exclude_rules ) {
1233
- // Skips folders/files that match default exclude patterns
1234
- foreach ( $this->default_excludes() as $exclude ) {
1235
- $finder->notPath( $exclude );
1236
- }
1237
- }
1238
 
1239
- foreach ( $finder->in( $this->get_root() ) as $entry ) {
1240
- $this->files[] = $entry;
1241
- }
1242
 
1243
- return $this->files;
1244
 
1245
- }
 
 
 
1246
 
1247
- /**
1248
- * Returns an array of files that will be included in the backup.
1249
- *
1250
- * @return array
1251
- */
1252
- public function get_included_files() {
1253
 
1254
- if ( ! empty( $this->included_files ) ) {
1255
- return $this->included_files;
 
1256
  }
1257
 
1258
- $this->included_files = array();
1259
 
1260
- $excludes = $this->exclude_string( 'regex' );
1261
 
1262
- foreach ( $this->get_files( true ) as $file ) {
1263
 
1264
- // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1265
- if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1266
- continue;
1267
- }
 
 
1268
 
1269
- // Skip unreadable files
1270
- if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1271
- continue;
1272
- }
1273
 
1274
- // Excludes
1275
- if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', self::conform_dir( $file->getPathname() ) ) ) ) {
1276
- continue;
1277
- }
1278
 
1279
- $this->included_files[] = $file;
1280
 
 
 
 
1281
  }
1282
 
1283
- return $this->included_files;
 
 
1284
 
1285
  }
1286
 
1287
- /**
1288
- * Returns an array of files that match the exclude rules.
1289
- *
1290
- * @return array
1291
- */
1292
- public function get_excluded_files() {
1293
 
1294
- if ( ! empty( $this->excluded_files ) ) {
1295
- return $this->excluded_files;
1296
- }
1297
-
1298
- $this->excluded_files = array();
1299
 
1300
- $excludes = $this->exclude_string( 'regex' );
 
 
 
 
 
 
 
1301
 
1302
- foreach ( $this->get_files( true ) as $file ) {
1303
 
1304
- // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1305
- if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1306
- continue;
1307
- }
1308
 
1309
- // Skip unreadable files
1310
- if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1311
- continue;
1312
- }
1313
 
1314
- // Excludes
1315
- if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', self::conform_dir( $file->getPathname() ) ) ) ) {
1316
- $this->excluded_files[] = $file;
1317
- }
1318
 
1319
- }
1320
 
1321
- return $this->excluded_files;
 
 
 
 
 
 
1322
 
 
 
1323
  }
1324
 
1325
- /**
1326
- * Returns an array of unreadable files.
1327
- *
1328
- * @return array
1329
- */
1330
- public function get_unreadable_files() {
1331
-
1332
- if ( ! empty( $this->unreadable_files ) ) {
1333
- return $this->unreadable_files;
1334
- }
1335
-
1336
- $this->unreadable_files = array();
1337
 
1338
- foreach ( $this->get_files( true ) as $file ) {
1339
 
1340
- // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1341
- if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1342
- continue;
1343
- }
1344
 
1345
- if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1346
- $this->unreadable_files[] = $file;
1347
- }
 
 
 
 
 
 
 
 
1348
 
1349
- }
 
 
1350
 
1351
- return $this->unreadable_files;
 
 
 
1352
 
 
 
 
 
1353
  }
1354
 
1355
- private function load_pclzip() {
1356
-
1357
- // Load PclZip
1358
- if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) ) {
1359
- define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->get_path() ) );
1360
- }
1361
 
1362
- require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
1363
 
1364
- }
1365
 
1366
- /**
1367
- * Get an array of exclude rules
1368
- *
1369
- * The backup path is automatically excluded
1370
- *
1371
- * @return array
1372
- */
1373
- public function get_excludes() {
 
 
1374
 
1375
- $excludes = array();
 
1376
 
1377
- if ( isset( $this->excludes ) ) {
1378
- $excludes = $this->excludes;
 
1379
  }
1380
 
1381
- // If path() is inside root(), exclude it
1382
- if ( strpos( $this->get_path(), $this->get_root() ) !== false ) {
1383
- array_unshift( $excludes, trailingslashit( $this->get_path() ) );
1384
  }
1385
 
1386
- return array_unique( $excludes );
 
 
 
1387
 
1388
- }
 
 
 
1389
 
1390
- /**
1391
- * Set the excludes, expects and array
1392
- *
1393
- * @param Array $excludes
1394
- * @param Bool $append
1395
- */
1396
- public function set_excludes( $excludes, $append = false ) {
1397
 
1398
- if ( is_string( $excludes ) ) {
1399
- $excludes = explode( ',', $excludes );
 
1400
  }
1401
 
1402
- if ( $append ) {
1403
- $excludes = array_merge( $this->excludes, $excludes );
 
1404
  }
1405
 
1406
- $this->excludes = array_filter( array_unique( array_map( 'trim', $excludes ) ) );
1407
 
 
 
 
1408
  }
1409
 
1410
- /**
1411
- * Generate the exclude param string for the zip backup
1412
- *
1413
- * Takes the exclude rules and formats them for use with either
1414
- * the shell zip command or pclzip
1415
- *
1416
- * @param string $context . (default: 'zip')
1417
- *
1418
- * @return string
1419
- */
1420
- public function exclude_string( $context = 'zip' ) {
1421
 
1422
- // Return a comma separated list by default
1423
- $separator = ', ';
1424
- $wildcard = '';
1425
 
1426
- // The zip command
1427
- if ( $context === 'zip' ) {
1428
- $wildcard = '*';
1429
- $separator = ' -x ';
 
 
 
 
1430
 
1431
- // The PclZip fallback library
1432
- } elseif ( $context === 'regex' ) {
1433
- $wildcard = '([\s\S]*?)';
1434
- $separator = '|';
1435
- }
1436
 
1437
- $excludes = $this->get_excludes();
1438
 
1439
- foreach ( $excludes as $key => &$rule ) {
1440
 
1441
- $file = $absolute = $fragment = false;
1442
 
1443
- // Files don't end with /
1444
- if ( ! in_array( substr( $rule, - 1 ), array( '\\', '/' ) ) ) {
1445
- $file = true;
1446
- } // If rule starts with a / then treat as absolute path
1447
- elseif ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
1448
- $absolute = true;
1449
- } // Otherwise treat as dir fragment
1450
- else {
1451
- $fragment = true;
1452
  }
1453
 
1454
- // Strip $this->root and conform
1455
- $rule = str_ireplace( $this->get_root(), '', untrailingslashit( self::conform_dir( $rule ) ) );
1456
 
1457
- // Strip the preceeding slash
1458
- if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
1459
- $rule = substr( $rule, 1 );
1460
- }
1461
 
1462
- // Escape string for regex
1463
- if ( $context === 'regex' ) {
1464
- $rule = str_replace( '.', '\.', $rule );
1465
- }
1466
 
1467
- // Convert any existing wildcards
1468
- if ( $wildcard !== '*' && false !== strpos( $rule, '*' ) ) {
1469
- $rule = str_replace( '*', $wildcard, $rule );
1470
- }
1471
 
1472
- // Wrap directory fragments and files in wildcards for zip
1473
- if ( 'zip' === $context && ( $fragment || $file ) ) {
1474
- $rule = $wildcard . $rule . $wildcard;
1475
- }
 
 
 
 
 
 
 
1476
 
1477
- // Add a wildcard to the end of absolute url for zips
1478
- if ( 'zip' === $context && $absolute ) {
1479
- $rule .= $wildcard;
1480
- }
 
 
 
 
1481
 
1482
- // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
1483
- if ( $file && 'regex' === $context ) {
1484
- $rule .= '$';
1485
- }
1486
 
1487
- // Add a start carrot to absolute urls for pclzip
1488
- if ( $absolute && 'regex' === $context ) {
1489
- $rule = '^' . $rule;
1490
- }
 
 
 
1491
 
1492
- }
 
 
 
 
1493
 
1494
- // Escape shell args for zip command
1495
- if ( $context === 'zip' ) {
1496
- $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
1497
  }
1498
 
1499
- return implode( $separator, $excludes );
 
1500
 
1501
  }
1502
 
1503
- /**
1504
- * Add backquotes to tables and db-names in SQL queries. Taken from phpMyAdmin.
1505
- *
1506
- * @param mixed $a_name
1507
- *
1508
- * @return array|string
1509
- */
1510
- private function sql_backquote( $a_name ) {
1511
 
1512
- if ( ! empty( $a_name ) && $a_name !== '*' ) {
 
 
1513
 
1514
- if ( is_array( $a_name ) ) {
 
1515
 
1516
- $result = array();
 
 
 
1517
 
1518
- reset( $a_name );
 
 
 
 
 
1519
 
1520
- while ( list( $key, $val ) = each( $a_name ) ) {
1521
- $result[ $key ] = '`' . $val . '`';
1522
- }
1523
 
1524
- return $result;
 
1525
 
1526
- } else {
1527
- return '`' . $a_name . '`';
1528
- }
1529
 
 
 
1530
  } else {
1531
- return $a_name;
1532
  }
1533
 
1534
  }
1535
 
1536
- /**
1537
- * Reads the Database table in $table and creates
1538
- * SQL Statements for recreating structure and data
1539
- * Taken partially from phpMyAdmin and partially from
1540
- * Alain Wolf, Zurich - Switzerland
1541
- * Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
1542
- *
1543
- * @param string $sql_file
1544
- * @param string $table
1545
- */
1546
- private function make_sql( $sql_file, $table ) {
1547
-
1548
- // Add SQL statement to drop existing table
1549
- $sql_file .= "\n";
1550
- $sql_file .= "\n";
1551
- $sql_file .= "#\n";
1552
- $sql_file .= "# Delete any existing table " . $this->sql_backquote( $table ) . "\n";
1553
- $sql_file .= "#\n";
1554
- $sql_file .= "\n";
1555
- $sql_file .= "DROP TABLE IF EXISTS " . $this->sql_backquote( $table ) . ";\n";
1556
-
1557
- /* Table Structure */
1558
-
1559
- // Comment in SQL-file
1560
- $sql_file .= "\n";
1561
- $sql_file .= "\n";
1562
- $sql_file .= "#\n";
1563
- $sql_file .= "# Table structure of table " . $this->sql_backquote( $table ) . "\n";
1564
- $sql_file .= "#\n";
1565
- $sql_file .= "\n";
1566
-
1567
- // Get table structure
1568
- $query = 'SHOW CREATE TABLE ' . $this->sql_backquote( $table );
1569
- $result = mysql_query( $query, $this->db );
1570
-
1571
- if ( $result ) {
1572
-
1573
- if ( mysql_num_rows( $result ) > 0 ) {
1574
- $sql_create_arr = mysql_fetch_array( $result );
1575
- $sql_file .= $sql_create_arr[1];
1576
- }
1577
-
1578
- mysql_free_result( $result );
1579
- $sql_file .= ' ;';
1580
-
1581
- }
1582
-
1583
- /* Table Contents */
1584
 
1585
- // Get table contents
1586
- $query = 'SELECT * FROM ' . $this->sql_backquote( $table );
1587
- $result = mysql_query( $query, $this->db );
1588
 
1589
- $fields_cnt = 0;
1590
- $rows_cnt = 0;
1591
 
1592
- if ( $result ) {
1593
- $fields_cnt = mysql_num_fields( $result );
1594
- $rows_cnt = mysql_num_rows( $result );
1595
- }
1596
 
1597
- // Comment in SQL-file
1598
- $sql_file .= "\n";
1599
- $sql_file .= "\n";
1600
- $sql_file .= "#\n";
1601
- $sql_file .= "# Data contents of table " . $table . " (" . $rows_cnt . " records)\n";
1602
- $sql_file .= "#\n";
1603
 
1604
- $field_set = $field_num = array();
 
1605
 
1606
- // Checks whether the field is an integer or not
1607
- for ( $j = 0; $j < $fields_cnt; $j ++ ) {
1608
 
1609
- $field_set[ $j ] = $this->sql_backquote( mysql_field_name( $result, $j ) );
1610
- $type = mysql_field_type( $result, $j );
 
 
 
 
1611
 
1612
- if ( $type === 'tinyint' || $type === 'smallint' || $type === 'mediumint' || $type === 'int' || $type === 'bigint' ) {
1613
- $field_num[ $j ] = true;
1614
  } else {
1615
- $field_num[ $j ] = false;
1616
  }
1617
 
1618
  }
1619
 
1620
- // Sets the scheme
1621
- $entries = 'INSERT INTO ' . $this->sql_backquote( $table ) . ' VALUES (';
1622
- $search = array( '\x00', '\x0a', '\x0d', '\x1a' ); //\x08\\x09, not required
1623
- $replace = array( '\0', '\n', '\r', '\Z' );
1624
- $current_row = 0;
1625
- $batch_write = 0;
1626
-
1627
- $values = array();
1628
-
1629
- while ( $row = mysql_fetch_row( $result ) ) {
1630
-
1631
- $current_row ++;
1632
-
1633
- // build the statement
1634
- for ( $j = 0; $j < $fields_cnt; $j ++ ) {
1635
-
1636
- if ( ! isset( $row[ $j ] ) ) {
1637
- $values[] = 'NULL';
1638
-
1639
- } elseif ( $row[ $j ] === '0' || $row[ $j ] !== '' ) {
1640
-
1641
- // a number
1642
- if ( $field_num[ $j ] ) {
1643
- $values[] = $row[ $j ];
1644
- } else {
1645
- $values[] = "'" . str_replace( $search, $replace, $this->sql_addslashes( $row[ $j ] ) ) . "'";
1646
- }
1647
 
1648
- } else {
1649
- $values[] = "''";
1650
- }
1651
-
1652
- }
 
1653
 
1654
- $sql_file .= " \n" . $entries . implode( ', ', $values ) . ") ;";
1655
 
1656
- // write the rows in batches of 100
1657
- if ( $batch_write === 100 ) {
1658
- $batch_write = 0;
1659
- $this->write_sql( $sql_file );
1660
- $sql_file = '';
1661
- }
1662
 
1663
- $batch_write ++;
1664
 
1665
- unset( $values );
1666
 
1667
- }
 
 
 
 
 
1668
 
1669
- mysql_free_result( $result );
1670
 
1671
- // Create footer/closing comment in SQL-file
1672
- $sql_file .= "\n";
1673
- $sql_file .= "#\n";
1674
- $sql_file .= "# End of data contents of table " . $table . "\n";
1675
- $sql_file .= "# --------------------------------------------------------\n";
1676
- $sql_file .= "\n";
1677
 
1678
- $this->write_sql( $sql_file );
 
 
 
 
 
 
 
 
 
1679
 
 
 
 
 
1680
  }
1681
 
1682
- /**
1683
- * Better addslashes for SQL queries.
1684
- * Taken from phpMyAdmin.
1685
- *
1686
- * @param string $a_string (default: '')
1687
- * @param bool $is_like (default: false)
1688
- *
1689
- * @return mixed
1690
- */
1691
- private function sql_addslashes( $a_string = '', $is_like = false ) {
1692
 
1693
- if ( $is_like ) {
1694
- $a_string = str_replace( '\\', '\\\\\\\\', $a_string );
1695
- } else {
1696
- $a_string = str_replace( '\\', '\\\\', $a_string );
1697
- }
1698
 
1699
- $a_string = str_replace( '\'', '\\\'', $a_string );
 
 
 
 
 
 
 
1700
 
1701
- return $a_string;
1702
- }
1703
 
1704
- /**
1705
- * Write the SQL file
1706
- *
1707
- * @param string $sql
1708
- *
1709
- * @return null|boolean
1710
- */
1711
- private function write_sql( $sql ) {
1712
 
1713
- $sqlname = $this->get_database_dump_filepath();
 
 
1714
 
1715
- // Actually write the sql file
1716
- if ( is_writable( $sqlname ) || ! file_exists( $sqlname ) ) {
 
1717
 
1718
- if ( ! $handle = @fopen( $sqlname, 'a' ) ) {
1719
- return;
1720
- }
1721
 
1722
- if ( ! fwrite( $handle, $sql ) ) {
1723
- return;
1724
- }
1725
 
1726
- fclose( $handle );
1727
 
1728
- return true;
1729
 
1730
- }
 
 
 
 
1731
 
 
 
1732
  }
1733
 
1734
- /**
1735
- * Get the errors
1736
- *
1737
- */
1738
- public function get_errors( $context = null ) {
1739
 
1740
- if ( ! empty( $context ) ) {
1741
- return isset( $this->errors[ $context ] ) ? $this->errors[ $context ] : array();
1742
- }
1743
 
1744
- return $this->errors;
 
 
 
 
 
 
1745
 
 
 
1746
  }
1747
 
1748
- /**
1749
- * Add an error to the errors stack
1750
- *
1751
- * @param string $context
1752
- * @param mixed $error
1753
- */
1754
- public function error( $context, $error ) {
1755
-
1756
- if ( empty( $context ) || empty( $error ) ) {
1757
- return;
1758
- }
1759
-
1760
- $this->do_action( 'hmbkp_error' );
1761
-
1762
- $this->errors[ $context ][ $_key = md5( implode( ':', (array) $error ) ) ] = $error;
1763
 
1764
- }
1765
 
1766
- /**
1767
- * Migrate errors to warnings
1768
- *
1769
- * @param null $context
1770
- */
1771
- private function errors_to_warnings( $context = null ) {
1772
 
1773
- $errors = empty( $context ) ? $this->get_errors() : array( $context => $this->get_errors( $context ) );
 
 
 
 
 
1774
 
1775
- if ( empty( $errors ) ) {
1776
- return;
1777
- }
1778
 
1779
- foreach ( $errors as $error_context => $context_errors ) {
1780
- foreach ( $context_errors as $error ) {
1781
- $this->warning( $error_context, $error );
1782
- }
1783
- }
1784
 
1785
- if ( $context ) {
1786
- unset( $this->errors[ $context ] );
1787
- } else {
1788
- $this->errors = array();
1789
  }
1790
-
1791
  }
1792
 
1793
- /**
1794
- * Get the warnings
1795
- *
1796
- */
1797
- public function get_warnings( $context = null ) {
1798
 
1799
- if ( ! empty( $context ) ) {
1800
- return isset( $this->warnings[ $context ] ) ? $this->warnings[ $context ] : array();
1801
- }
1802
 
1803
- return $this->warnings;
 
 
 
 
1804
 
 
 
1805
  }
1806
 
1807
- /**
1808
- * Add an warning to the warnings stack
1809
- *
1810
- * @param string $context
1811
- * @param mixed $warning
1812
- */
1813
- private function warning( $context, $warning ) {
1814
 
1815
- if ( empty( $context ) || empty( $warning ) ) {
1816
- return;
1817
- }
1818
-
1819
- $this->do_action( 'hmbkp_warning' );
1820
 
1821
- $this->warnings[ $context ][ $_key = md5( implode( ':', (array) $warning ) ) ] = $warning;
 
 
 
 
 
 
1822
 
 
 
1823
  }
1824
 
1825
- /**
1826
- * Custom error handler for catching php errors
1827
- *
1828
- * @param $type
1829
- *
1830
- * @return bool
1831
- */
1832
- public function error_handler( $type ) {
1833
-
1834
- // Skip strict & deprecated warnings
1835
- if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 ) {
1836
- return false;
1837
- }
1838
 
1839
- $args = func_get_args();
1840
 
1841
- array_shift( $args );
1842
 
1843
- $this->warning( 'php', implode( ', ', array_splice( $args, 0, 3 ) ) );
 
 
 
 
 
 
 
1844
 
 
 
1845
  return false;
1846
-
1847
  }
1848
 
1849
- /**
1850
- * Determine if user can connect via the CLI
1851
- *
1852
- * @return \WP_Error
1853
- */
1854
- public function user_can_connect() {
1855
 
1856
- // mysql --host=localhost --user=myname --password=mypass mydb
1857
 
1858
- // Guess port or socket connection type
1859
- $port_or_socket = strstr( DB_HOST, ':' );
1860
 
1861
- $host = DB_HOST;
1862
 
1863
- if ( ! empty( $port_or_socket ) ) {
1864
-
1865
- $host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
1866
 
1867
- $port_or_socket = substr( $port_or_socket, 1 );
 
 
 
 
 
1868
 
1869
- if ( 0 !== strpos( $port_or_socket, '/' ) ) {
1870
 
1871
- $port = intval( $port_or_socket );
 
1872
 
1873
- $maybe_socket = strstr( $port_or_socket, ':' );
1874
 
1875
- if ( ! empty( $maybe_socket ) ) {
1876
 
1877
- $socket = substr( $maybe_socket, 1 );
1878
 
1879
- }
1880
 
1881
- } else {
1882
 
1883
- $socket = $port_or_socket;
1884
 
1885
- }
1886
- }
1887
 
1888
- // Path to the mysqldump executable
1889
- $cmd = 'mysql ';
1890
 
1891
- // Username
1892
- $cmd .= ' -u ' . escapeshellarg( DB_USER );
1893
 
1894
- // Don't pass the password if it's blank
1895
- if ( DB_PASSWORD ) {
1896
- $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
1897
- }
1898
 
1899
- // Set the host
1900
- $cmd .= ' -h ' . escapeshellarg( $host );
1901
 
1902
- // Set the port if it was set
1903
- if ( ! empty( $port ) && is_numeric( $port ) ) {
1904
- $cmd .= ' -P ' . $port;
1905
- }
1906
 
1907
- // Set the socket path
1908
- if ( ! empty( $socket ) && ! is_numeric( $socket ) ) {
1909
- $cmd .= ' --protocol=socket -S ' . $socket;
1910
  }
 
1911
 
1912
- // The database we're dumping
1913
- $cmd .= ' ' . escapeshellarg( DB_NAME );
1914
-
1915
- // Quit immediately
1916
- $cmd .= ' --execute="quit"';
1917
 
1918
- // Pipe STDERR to STDOUT
1919
- $cmd .= ' 2>&1';
1920
 
1921
- // Store any returned data in an error
1922
- $stderr = shell_exec( $cmd );
 
 
1923
 
1924
- // Skip the new password warning that is output in mysql > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
1925
- if ( 'Warning: Using a password on the command line interface can be insecure.' === trim( $stderr ) ) {
1926
- $stderr = '';
1927
- }
1928
 
1929
- if ( $stderr ) {
1930
- return new \WP_Error( 'mysql-cli-connect-error', __( 'Could not connect to mysql', 'backupwordpress' ) );
1931
- }
1932
  }
1933
 
1934
- }
 
 
 
1935
 
1936
- }
 
1937
 
1938
- // We need this function to exist in the global namespace
1939
- // TODO obviously this should be fixed at some point
1940
- namespace {
1941
 
1942
- /**
1943
- * Add file callback for PclZip, excludes files
1944
- * and sets the database dump to be stored in the root
1945
- * of the zip
1946
- *
1947
- * @param string $event
1948
- * @param array $file
1949
- *
1950
- * @return bool
1951
- */
1952
- function hmbkp_pclzip_callback( $event, $file ) {
1953
 
1954
- global $_hmbkp_exclude_string;
 
1955
 
1956
- // Don't try to add unreadable files.
1957
- if ( ! is_readable( $file['filename'] ) || ! file_exists( $file['filename'] ) ) {
1958
- return false;
1959
- } // Match everything else past the exclude list
1960
- elseif ( $_hmbkp_exclude_string && preg_match( '(' . $_hmbkp_exclude_string . ')', $file['stored_filename'] ) ) {
1961
- return false;
1962
  }
1963
 
1964
- return true;
1965
-
 
1966
  }
1967
 
1968
  }
 
1
  <?php
2
 
3
+ namespace HM\BackUpWordPress;
4
+ use Symfony\Component\Finder\Finder;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ /**
7
+ * Generic file and database backup class
8
+ *
9
+ * @version 2.3
10
+ */
11
+ class Backup {
 
 
12
 
13
+ /**
14
+ * The backup type, must be either complete, file or database
15
+ *
16
+ * @string
17
+ */
18
+ private $type = '';
 
 
19
 
20
+ /**
21
+ * The filename of the backup file
22
+ *
23
+ * @string
24
+ */
25
+ private $archive_filename = '';
26
 
27
+ /**
28
+ * The filename of the database dump
29
+ *
30
+ * @string
31
+ */
32
+ private $database_dump_filename = '';
33
 
34
+ /**
35
+ * The path to the zip command
36
+ *
37
+ * @string
38
+ */
39
+ private $zip_command_path;
40
 
41
+ /**
42
+ * The path to the mysqldump command
43
+ *
44
+ * @string
45
+ */
46
+ private $mysqldump_command_path;
47
 
48
+ /**
49
+ * The filename of the existing backup file
50
+ *
51
+ * @string
52
+ */
53
+ private $existing_archive_filepath = '';
54
 
55
+ /**
56
+ * An array of exclude rules
57
+ *
58
+ * @array
59
+ */
60
+ private $excludes = array();
61
 
62
+ /**
63
+ * The path that should be backed up
64
+ *
65
+ * @var string
66
+ */
67
+ private $root = '';
68
 
69
+ /**
70
+ * Holds the current db connection
71
+ *
72
+ * @var resource
73
+ */
74
+ private $db;
75
 
76
+ /**
77
+ * An array of all the files in root
78
+ * excluding excludes and unreadable files
79
+ *
80
+ * @var array
81
+ */
82
+ private $files = array();
83
 
84
+ /**
85
+ * An array of all the files in root
86
+ * that match the exclude rules
87
+ *
88
+ * @var array
89
+ */
90
+ private $excluded_files = array();
91
 
92
+ /**
93
+ * An array of all the files in root
94
+ * that are unreadable
95
+ *
96
+ * @var array
97
+ */
98
+ private $unreadable_files = array();
99
 
100
+ /**
101
+ * An array of all the files in root
102
+ * that will be included in the backup
103
+ *
104
+ * @var array
105
+ */
106
+ protected $included_files = array();
107
 
108
+ /**
109
+ * Contains an array of errors
110
+ *
111
+ * @var mixed
112
+ */
113
+ private $errors = array();
 
114
 
115
+ /**
116
+ * Contains an array of warnings
117
+ *
118
+ * @var mixed
119
+ */
120
+ private $warnings = array();
121
 
122
+ /**
123
+ * The archive method used
124
+ *
125
+ * @var string
126
+ */
127
+ private $archive_method = '';
128
 
129
+ /**
130
+ * The mysqldump method used
131
+ *
132
+ * @var string
133
+ */
134
+ private $mysqldump_method = '';
 
135
 
136
+ /**
137
+ * @var bool
138
+ */
139
+ protected $mysqldump_verified = false;
140
 
141
+ /**
142
+ * @var bool
143
+ */
144
+ protected $archive_verified = false;
145
 
146
+ /**
147
+ * @var string
148
+ */
149
+ protected $action_callback = '';
150
 
151
+ /**
152
+ * List of patterns we want to exclude by default.
153
+ * @var array
154
+ */
155
+ protected $default_excludes = array(
156
+ '.git/',
157
+ '.svn/',
158
+ '.DS_Store',
159
+ '.idea/',
160
+ 'backwpup-*',
161
+ 'updraft',
162
+ 'wp-snapshots',
163
+ 'backupbuddy_backups',
164
+ 'pb_backupbuddy',
165
+ 'backup-db',
166
+ 'Envato-backups',
167
+ 'managewp',
168
+ 'backupwordpress-*-backups',
169
+ );
170
+
171
+ /**
172
+ * Returns a filterable array of excluded directories and files.
173
+ *
174
+ * @return mixed|void
175
+ */
176
+ public function default_excludes() {
177
+ return apply_filters( 'hmbkp_default_excludes', $this->default_excludes );
178
+ }
179
 
180
+ /**
181
+ * Check whether safe mode is active or not
182
+ *
183
+ * @param string $ini_get_callback
184
+ *
185
+ * @return bool
186
+ */
187
+ public static function is_safe_mode_active( $ini_get_callback = 'ini_get' ) {
188
+
189
+ $safe_mode = @call_user_func( $ini_get_callback, 'safe_mode' );
190
 
191
+ if ( $safe_mode && strtolower( $safe_mode ) != 'off' ) {
192
+ return true;
193
  }
194
 
195
+ return false;
196
 
197
+ }
 
 
 
 
 
 
 
 
198
 
199
+ /**
200
+ * Check whether shell_exec has been disabled.
201
+ *
202
+ * @return bool
203
+ */
204
+ public static function is_shell_exec_available() {
205
 
206
+ // Are we in Safe Mode
207
+ if ( self::is_safe_mode_active() ) {
208
+ return false;
209
+ }
210
 
211
+ // Is shell_exec or escapeshellcmd or escapeshellarg disabled?
212
+ if ( self::is_function_disabled( 'suhosin.executor.func.blacklist' ) ) {
213
+ return false;
214
+ }
215
 
216
+ // Functions can also be disabled via suhosin
217
+ if ( self::is_function_disabled( 'disable_functions' ) ) {
218
+ return false;
219
+ }
220
 
221
+ // Can we issue a simple echo command?
222
+ if ( ! @shell_exec( 'echo backupwordpress' ) ) {
223
+ return false;
224
  }
225
 
226
+ return true;
 
 
 
227
 
228
+ }
 
 
229
 
230
+ protected static function is_function_disabled( $ini_setting ) {
 
231
 
232
+ if ( array_intersect( array(
233
+ 'shell_exec',
234
+ 'escapeshellarg',
235
+ 'escapeshellcmd'
236
+ ), array_map( 'trim', explode( ',', @ini_get( $ini_setting ) ) ) ) ) {
237
+ return false;
238
+ }
239
 
240
+ }
 
 
241
 
 
 
 
242
 
243
+ /**
244
+ * Attempt to work out the root directory of the site, that
245
+ * is, the path equivelant of home_url().
246
+ *
247
+ * @return string $home_path
248
+ */
249
+ public static function get_home_path() {
250
 
251
+ if ( defined( 'HMBKP_ROOT' ) && HMBKP_ROOT ) {
252
+ return wp_normalize_path( HMBKP_ROOT );
253
  }
254
 
255
+ $home_url = home_url();
256
+ $site_url = site_url();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
+ $home_path = ABSPATH;
259
 
260
+ // If site_url contains home_url and they differ then assume WordPress is installed in a sub directory
261
+ if ( $home_url !== $site_url && strpos( $site_url, $home_url ) === 0 ) {
262
+ $home_path = trailingslashit( substr( wp_normalize_path( ABSPATH ), 0, strrpos( wp_normalize_path( ABSPATH ), str_replace( $home_url, '', $site_url ) ) ) );
263
  }
264
 
265
+ return wp_normalize_path( $home_path );
 
 
 
 
 
 
 
266
 
267
+ }
 
 
268
 
269
+ /**
270
+ * Sets up the default properties
271
+ */
272
+ public function __construct() {
273
 
274
+ // Raise the memory limit and max_execution time
275
+ @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
276
+ @set_time_limit( 0 );
277
 
278
+ // Set a custom error handler so we can track errors
279
+ set_error_handler( array( $this, 'error_handler' ) );
280
+
281
+ // Some properties can be overridden with defines
282
+ if ( defined( 'HMBKP_EXCLUDE' ) && HMBKP_EXCLUDE ) {
283
+ $this->set_excludes( HMBKP_EXCLUDE, true );
284
  }
285
 
286
+ if ( defined( 'HMBKP_MYSQLDUMP_PATH' ) ) {
287
+ $this->set_mysqldump_command_path( HMBKP_MYSQLDUMP_PATH );
 
 
 
 
 
288
  }
289
 
290
+ if ( defined( 'HMBKP_ZIP_PATH' ) ) {
291
+ $this->set_zip_command_path( HMBKP_ZIP_PATH );
292
+ }
 
 
 
293
 
294
+ }
 
 
295
 
296
+ /**
297
+ * Simple class wrapper for Path::get_path()
298
+ *
299
+ * @return string
300
+ */
301
+ private function get_path() {
302
+ return Path::get_instance()->get_path();
303
+ }
304
+
305
+ /**
306
+ * Get the full filepath to the archive file
307
+ *
308
+ * @return string
309
+ */
310
+ public function get_archive_filepath() {
311
+ return trailingslashit( $this->get_path() ) . $this->get_archive_filename();
312
+ }
313
 
314
+ /**
315
+ * Get the filename of the archive file
316
+ *
317
+ * @return string
318
+ */
319
+ public function get_archive_filename() {
320
+
321
+ if ( empty( $this->archive_filename ) ) {
322
+ $this->set_archive_filename( implode( '-', array(
323
+ sanitize_title( str_ireplace( array(
324
+ 'http://',
325
+ 'https://',
326
+ 'www'
327
+ ), '', home_url() ) ),
328
+ 'backup',
329
+ current_time( 'Y-m-d-H-i-s' )
330
+ ) ) . '.zip' );
331
  }
332
 
333
+ return $this->archive_filename;
 
 
 
 
 
 
 
334
 
335
+ }
 
 
336
 
337
+ /**
338
+ * Set the filename of the archive file
339
+ *
340
+ * @param string $filename
341
+ *
342
+ * @return \WP_Error|null
343
+ */
344
+ public function set_archive_filename( $filename ) {
345
 
346
+ if ( empty( $filename ) || ! is_string( $filename ) ) {
347
+ return new \WP_Error( 'invalid_file_name', __( 'archive filename must be a non-empty string', 'backupwordpress' ) );
348
+ }
349
 
350
+ if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'zip' ) {
351
+ return new \WP_Error( 'invalid_file_extension', sprintf( __( 'invalid file extension for archive filename <code>%s</code>', 'backupwordpress' ), $filename ) );
352
  }
353
 
354
+ $this->archive_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
 
 
 
 
 
 
 
355
 
356
+ }
 
 
357
 
358
+ /**
359
+ * Get the full filepath to the database dump file.
360
+ *
361
+ * @return string
362
+ */
363
+ public function get_database_dump_filepath() {
364
+ return trailingslashit( $this->get_path() ) . $this->get_database_dump_filename();
365
+ }
366
 
367
+ /**
368
+ * Get the filename of the database dump file
369
+ *
370
+ * @return string
371
+ */
372
+ public function get_database_dump_filename() {
373
+
374
+ if ( empty( $this->database_dump_filename ) ) {
375
+ $this->set_database_dump_filename( 'database_' . DB_NAME . '.sql' );
376
  }
377
 
378
+ return $this->database_dump_filename;
 
 
 
 
 
 
 
379
 
380
+ }
 
 
381
 
382
+ /**
383
+ * Set the filename of the database dump file
384
+ *
385
+ * @param string $filename
386
+ *
387
+ * @return \WP_Error|null
388
+ */
389
+ public function set_database_dump_filename( $filename ) {
390
 
391
+ if ( empty( $filename ) || ! is_string( $filename ) ) {
392
+ return new \WP_Error( 'invalid_file_name', __( 'database dump filename must be a non-empty string', 'backupwordpress' ) );
393
  }
394
 
395
+ if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'sql' ) {
396
+ return new \WP_Error( 'invalid_file_extension', sprintf( __( 'invalid file extension for database dump filename <code>%s</code>', 'backupwordpress' ), $filename ) );
 
 
 
 
 
397
  }
398
 
399
+ $this->database_dump_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
 
 
 
 
 
 
 
400
 
401
+ }
 
 
402
 
403
+ /**
404
+ * Get the root directory to backup from
405
+ *
406
+ * Defaults to the root of the path equivalent of your home_url
407
+ *
408
+ * @return string
409
+ */
410
+ public function get_root() {
411
 
412
+ if ( empty( $this->root ) ) {
413
+ $this->set_root( wp_normalize_path( self::get_home_path() ) );
414
  }
415
 
416
+ return $this->root;
417
+
418
+ }
419
+
420
+ /**
421
+ * Set the root directory to backup from
422
+ *
423
+ * @param string $path
424
+ *
425
+ * @return \WP_Error|null
426
+ */
427
+ public function set_root( $path ) {
428
 
429
+ if ( empty( $path ) || ! is_string( $path ) || ! is_dir( $path ) ) {
430
+ return new \WP_Error( 'invalid_directory_path', sprintf( __( 'Invalid root path <code>%s</code> must be a valid directory path', 'backupwordpress' ), $path ) );
 
 
 
 
 
 
431
  }
432
 
433
+ $this->root = wp_normalize_path( $path );
 
 
 
 
 
 
434
 
435
+ }
 
 
436
 
437
+ /**
438
+ * Get the filepath for the existing archive
439
+ *
440
+ * @return string
441
+ */
442
+ public function get_existing_archive_filepath() {
443
+ return $this->existing_archive_filepath;
444
+ }
445
+
446
+ /**
447
+ * Set the filepath for the existing archive
448
+ *
449
+ * @param string $existing_archive_filepath
450
+ *
451
+ * @return null
452
+ */
453
+ public function set_existing_archive_filepath( $existing_archive_filepath ) {
454
 
455
+ if ( empty( $existing_archive_filepath ) || ! is_string( $existing_archive_filepath ) ) {
456
+ return new \WP_Error( 'invalid_existing_archive_filepath', sprintf( __( 'Invalid existing archive filepath <code>%s</code> must be a non-empty (string)', 'backupwordpress' ), $existing_archive_filepath ) );
457
  }
458
 
459
+ $this->existing_archive_filepath = wp_normalize_path( $existing_archive_filepath );
 
 
 
 
 
 
 
 
 
460
 
461
+ }
462
+
463
+ /**
464
+ * Get the archive method that was used for the backup
465
+ *
466
+ * Will be either zip, ZipArchive or PclZip
467
+ *
468
+ */
469
+ public function get_archive_method() {
470
+ return $this->archive_method;
471
+ }
472
+
473
+ /**
474
+ * Get the database dump method that was used for the backup
475
+ *
476
+ * Will be either mysqldump or mysqldump_fallback
477
+ *
478
+ */
479
+ public function get_mysqldump_method() {
480
+ return $this->mysqldump_method;
481
+ }
482
 
483
+ /**
484
+ * Get the backup type
485
+ *
486
+ * Defaults to complete
487
+ *
488
+ */
489
+ public function get_type() {
490
 
491
+ if ( empty( $this->type ) ) {
492
+ $this->set_type( 'complete' );
493
  }
494
 
495
+ return $this->type;
 
 
 
 
 
 
 
 
496
 
497
+ }
 
 
 
498
 
499
+ /**
500
+ * Set the backup type
501
+ *
502
+ * $type must be one of complete, database or file
503
+ *
504
+ * @param string $type
505
+ *
506
+ * @return \WP_Error|null
507
+ */
508
+ public function set_type( $type ) {
509
 
510
+ if ( ! is_string( $type ) || ! in_array( $type, array( 'file', 'database', 'complete' ) ) ) {
511
+ return new \WP_Error( 'invalid_backup_type', sprintf( __( 'Invalid backup type <code>%s</code> must be one of (string) file, database or complete', 'backupwordpress' ), $type ) );
512
+ }
513
 
514
+ $this->type = $type;
 
515
 
516
+ }
 
517
 
518
+ /**
519
+ * Get the path to the mysqldump bin
520
+ *
521
+ * If not explicitly set will attempt to work
522
+ * it out by checking common locations
523
+ *
524
+ * @return string
525
+ */
526
+ public function get_mysqldump_command_path() {
527
 
528
+ // Check shell_exec is available
529
+ if ( ! self::is_shell_exec_available() ) {
530
+ return '';
531
+ }
532
 
533
+ // Return now if it's already been set
534
+ if ( isset( $this->mysqldump_command_path ) ) {
535
+ return $this->mysqldump_command_path;
536
+ }
537
+
538
+ $this->mysqldump_command_path = '';
539
+
540
+ // Does mysqldump work
541
+ if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
 
543
+ // If so store it for later
544
+ $this->set_mysqldump_command_path( 'mysqldump' );
545
+
546
+ // And return now
547
  return $this->mysqldump_command_path;
548
 
549
  }
550
 
551
+ // List of possible mysqldump locations
552
+ $mysqldump_locations = array(
553
+ '/usr/local/bin/mysqldump',
554
+ '/usr/local/mysql/bin/mysqldump',
555
+ '/usr/mysql/bin/mysqldump',
556
+ '/usr/bin/mysqldump',
557
+ '/opt/local/lib/mysql6/bin/mysqldump',
558
+ '/opt/local/lib/mysql5/bin/mysqldump',
559
+ '/opt/local/lib/mysql4/bin/mysqldump',
560
+ '/xampp/mysql/bin/mysqldump',
561
+ '/Program Files/xampp/mysql/bin/mysqldump',
562
+ '/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
563
+ '/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump',
564
+ '/Program Files/MySQL/MySQL Server 5.6/bin/mysqldump',
565
+ '/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
566
+ '/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
567
+ '/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
568
+ '/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
569
+ '/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump',
570
+ '/opt/local/bin/mysqldump'
571
+ );
 
 
 
 
 
572
 
573
+ // Find the first one which works
574
+ foreach ( $mysqldump_locations as $location ) {
575
+ if ( (is_null( shell_exec( 'hash ' . wp_normalize_path( $location ) . ' 2>&1' ) ) ) && @is_executable( wp_normalize_path( $location ) ) ) {
576
+ $this->set_mysqldump_command_path( $location );
577
+ break; // Found one
578
  }
579
+ }
580
 
581
+ return $this->mysqldump_command_path;
582
 
583
+ }
 
584
 
585
+ /**
586
+ * Set the path to the mysqldump bin
587
+ *
588
+ * Setting the path to false will cause the database
589
+ * dump to use the php fallback
590
+ *
591
+ * @param mixed $path
592
+ */
593
+ public function set_mysqldump_command_path( $path ) {
594
+ $this->mysqldump_command_path = $path;
595
+ }
596
 
597
+ /**
598
+ * Get the path to the zip bin
599
+ *
600
+ * If not explicitly set will attempt to work
601
+ * it out by checking common locations
602
+ *
603
+ * @return string
604
+ */
605
+ public function get_zip_command_path() {
606
 
607
+ // Check shell_exec is available
608
+ if ( ! self::is_shell_exec_available() ) {
609
+ return '';
610
+ }
611
 
612
+ // Return now if it's already been set
613
+ if ( isset( $this->zip_command_path ) ) {
614
+ return $this->zip_command_path;
615
+ }
 
 
 
 
 
 
 
 
 
616
 
617
+ $this->zip_command_path = '';
618
+
619
+ // Does zip work
620
+ if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) {
621
+
622
+ // If so store it for later
623
+ $this->set_zip_command_path( 'zip' );
624
+
625
+ // And return now
626
  return $this->zip_command_path;
627
 
628
  }
629
 
630
+ // List of possible zip locations
631
+ $zip_locations = array(
632
+ '/usr/bin/zip',
633
+ '/opt/local/bin/zip'
634
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
635
 
636
+ // Find the first one which works
637
+ foreach ( $zip_locations as $location ) {
638
+ if ( @is_executable( wp_normalize_path( $location ) ) ) {
639
+ $this->set_zip_command_path( $location );
640
+ break; // Found one
641
  }
642
+ }
643
 
644
+ return $this->zip_command_path;
 
645
 
646
+ }
647
 
648
+ /**
649
+ * Set the path to the zip bin
650
+ *
651
+ * Setting the path to false will cause the database
652
+ * dump to use the php fallback
653
+ *
654
+ * @param mixed $path
655
+ */
656
+ public function set_zip_command_path( $path ) {
657
+ $this->zip_command_path = $path;
658
+ }
 
 
659
 
660
+ /**
661
+ * Fire actions for the various backup stages
662
+ *
663
+ * Callers can register callbacks to be called using `set_action_callback`
664
+ * Both the action and the instance on Backup are then passed to the callback function
665
+ *
666
+ * @see set_action_callback
667
+ *
668
+ * @param string $action The event to fire
669
+ */
670
+ protected function do_action( $action ) {
671
+
672
+ // If we have any callbacks then let's fire them
673
+ if ( ! empty( $this->action_callback ) ) {
674
 
675
+ // Order them by priority, lowest priority first
676
+ ksort( $this->action_callback );
677
 
678
+ foreach ( $this->action_callback as $priority ) {
679
+ foreach ( $priority as $callback ) {
680
+ call_user_func( $callback, $action, $this );
681
+ }
682
  }
683
 
684
+ }
685
+
686
+ // Also fire a global WordPress action
687
+ do_action( $action, $this );
688
+
689
+ }
690
+
691
+ /**
692
+ * Allow the caller to set a callback function that will be invoked whenever
693
+ * an action fires
694
+ *
695
+ * @see do_action
696
+ * @see /do_action
697
+ *
698
+ * @param callable $callback The function or method to be called
699
+ * @param int $priority The priority of the callback
700
+ */
701
+ public function set_action_callback( $callback, $priority = 10 ) {
702
+ $this->action_callback[ $priority ][] = $callback;
703
+ }
704
+
705
+ /**
706
+ * Kick off a backup
707
+ *
708
+ * @todo should be renamed so it's not same as class
709
+ * @return null
710
+ */
711
+ public function backup() {
712
 
713
+ $this->do_action( 'hmbkp_backup_started' );
714
 
715
+ // Backup database
716
+ if ( $this->get_type() !== 'file' ) {
717
+ $this->dump_database();
718
  }
719
 
720
+ // Zip everything up
721
+ $this->archive();
 
 
 
 
 
 
722
 
723
+ $this->do_action( 'hmbkp_backup_complete' );
 
 
 
 
 
 
 
724
 
725
+ }
 
 
 
726
 
727
+ /**
728
+ * Create the mysql backup
729
+ *
730
+ * Uses mysqldump if available, falls back to PHP
731
+ * if not.
732
+ *
733
+ */
734
+ public function dump_database() {
735
 
736
+ // Attempt to use native mysqldump
737
+ if ( self::is_shell_exec_available() && $this->get_mysqldump_command_path() && ! is_wp_error( $this->user_can_connect() ) ) {
738
+ $this->mysqldump();
739
  }
740
 
741
+ // If we cannot run mysqldump via CLI, fallback to PHP
742
+ if ( empty( $this->mysqldump_verified ) ) {
743
+ $this->mysqldump_fallback();
744
+ }
745
 
746
+ $this->do_action( 'hmbkp_mysqldump_finished' );
747
 
748
+ }
749
 
750
+ /**
751
+ * Export the database to an .sql file via the command line with mysqldump
752
+ */
753
+ public function mysqldump() {
754
 
755
+ $this->mysqldump_method = 'mysqldump';
756
 
757
+ $this->do_action( 'hmbkp_mysqldump_started' );
758
 
759
+ // Guess port or socket connection type
760
+ $port_or_socket = strstr( DB_HOST, ':' );
761
 
762
+ $host = DB_HOST;
763
 
764
+ if ( ! empty( $port_or_socket ) ) {
765
 
766
+ $host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
767
 
768
+ $port_or_socket = substr( $port_or_socket, 1 );
769
 
770
+ if ( 0 !== strpos( $port_or_socket, '/' ) ) {
771
 
772
+ $port = intval( $port_or_socket );
773
 
774
+ $maybe_socket = strstr( $port_or_socket, ':' );
775
 
776
+ if ( ! empty( $maybe_socket ) ) {
777
 
778
+ $socket = substr( $maybe_socket, 1 );
779
 
780
  }
 
781
 
782
+ } else {
 
783
 
784
+ $socket = $port_or_socket;
 
785
 
 
 
 
786
  }
787
+ }
788
 
789
+ // Path to the mysqldump executable
790
+ $cmd = escapeshellarg( $this->get_mysqldump_command_path() );
791
 
792
+ // We don't want to create a new DB
793
+ $cmd .= ' --no-create-db';
794
 
795
+ // Allow lock-tables to be overridden
796
+ if ( ! defined( 'HMBKP_MYSQLDUMP_SINGLE_TRANSACTION' ) || false !== HMBKP_MYSQLDUMP_SINGLE_TRANSACTION ) {
797
+ $cmd .= ' --single-transaction';
798
+ }
799
 
800
+ // Make sure binary data is exported properly
801
+ $cmd .= ' --hex-blob';
802
 
803
+ // Username
804
+ $cmd .= ' -u ' . escapeshellarg( DB_USER );
 
 
805
 
806
+ // Don't pass the password if it's blank
807
+ if ( DB_PASSWORD ) {
808
+ $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
809
+ }
810
 
811
+ // Set the host
812
+ $cmd .= ' -h ' . escapeshellarg( $host );
813
 
814
+ // Set the port if it was set
815
+ if ( ! empty( $port ) && is_numeric( $port ) ) {
816
+ $cmd .= ' -P ' . $port;
817
+ }
818
 
819
+ // Set the socket path
820
+ if ( ! empty( $socket ) && ! is_numeric( $socket ) ) {
821
+ $cmd .= ' --protocol=socket -S ' . $socket;
822
+ }
823
 
824
+ // The file we're saving too
825
+ $cmd .= ' -r ' . escapeshellarg( $this->get_database_dump_filepath() );
826
 
827
+ // The database we're dumping
828
+ $cmd .= ' ' . escapeshellarg( DB_NAME );
 
 
829
 
830
+ // Pipe STDERR to STDOUT
831
+ $cmd .= ' 2>&1';
 
832
 
833
+ // Store any returned data in an error
834
+ $stderr = shell_exec( $cmd );
835
 
836
+ // Skip the new password warning that is output in mysql > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
837
+ if ( 'Warning: Using a password on the command line interface can be insecure.' === trim( $stderr ) ) {
838
+ $stderr = '';
839
  }
840
 
841
+ if ( $stderr ) {
842
+ $this->error( $this->get_mysqldump_method(), $stderr );
843
+ }
 
 
844
 
845
+ $this->verify_mysqldump();
846
 
847
+ }
848
 
849
+ /**
850
+ * PHP mysqldump fallback functions, exports the database to a .sql file
851
+ *
852
+ */
853
+ public function mysqldump_fallback() {
854
 
855
+ $this->errors_to_warnings( $this->get_mysqldump_method() );
856
 
857
+ $this->mysqldump_method = 'mysqldump_fallback';
 
 
858
 
859
+ $this->do_action( 'hmbkp_mysqldump_started' );
 
 
860
 
861
+ $this->db = @mysql_pconnect( DB_HOST, DB_USER, DB_PASSWORD );
862
 
863
+ if ( ! $this->db ) {
864
+ $this->db = mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
865
+ }
866
 
867
+ if ( ! $this->db ) {
868
+ return;
869
+ }
870
 
871
+ mysql_select_db( DB_NAME, $this->db );
 
 
 
 
 
872
 
873
+ if ( function_exists( 'mysql_set_charset' ) ) {
874
+ mysql_set_charset( DB_CHARSET, $this->db );
875
+ }
876
 
877
+ // Begin new backup of MySql
878
+ $tables = mysql_query( 'SHOW TABLES' );
879
 
880
+ $sql_file = "# WordPress : " . get_bloginfo( 'url' ) . " MySQL database backup\n";
881
+ $sql_file .= "#\n";
882
+ $sql_file .= "# Generated: " . date( 'l j. F Y H:i T' ) . "\n";
883
+ $sql_file .= "# Hostname: " . DB_HOST . "\n";
884
+ $sql_file .= "# Database: " . $this->sql_backquote( DB_NAME ) . "\n";
885
+ $sql_file .= "# --------------------------------------------------------\n";
886
 
887
+ for ( $i = 0; $i < mysql_num_rows( $tables ); $i ++ ) {
888
 
889
+ $curr_table = mysql_tablename( $tables, $i );
890
+
891
+ // Create the SQL statements
892
+ $sql_file .= "# --------------------------------------------------------\n";
893
+ $sql_file .= "# Table: " . $this->sql_backquote( $curr_table ) . "\n";
894
+ $sql_file .= "# --------------------------------------------------------\n";
895
+
896
+ $this->make_sql( $sql_file, $curr_table );
897
 
898
  }
899
 
900
+ }
901
+
902
+ /**
903
+ * Zip up all the files.
904
+ *
905
+ * Attempts to use the shell zip command, if
906
+ * thats not available then it falls back to
907
+ * PHP ZipArchive.
908
+ *
909
+ */
910
+ public function archive() {
911
 
912
+ if ( defined( 'HMBKP_FORCE_ZIP_METHOD' ) ) {
913
+ switch ( HMBKP_FORCE_ZIP_METHOD ) {
914
+ case 'zip':
915
+ if ( $this->get_zip_command_path() ) {
916
+ $this->zip();
917
+ } else {
918
+ $this->warning( $this->get_archive_method(), __( 'Zip command is not available.', 'backupwordpress' ) );
919
+ }
920
+ break;
921
+ case 'ziparchive':
922
+ if ( class_exists( 'ZipArchive' ) ) {
923
+ $this->zip_archive();
924
+ } else {
925
+ $this->warning( $this->get_archive_method(), __( 'ZipArchive method is not available.', 'backupwordpress' ) );
926
+ }
927
+ break;
928
+ default:
929
+ $this->warning( $this->get_archive_method(), __( 'No valid archive method found.', 'backupwordpress' ) );
930
+ break;
931
+ }
932
+ } else {
933
+ // Is zip available
934
+ if ( $this->get_zip_command_path() ) {
935
  $this->zip();
936
  }
937
 
938
+ // If the shell zip failed then use ZipArchive
939
+ if ( ! $this->get_zip_command_path() || empty( $this->archive_verified ) && class_exists( 'ZipArchive' ) ) {
940
  $this->zip_archive();
941
+ } else {
942
+ $this->warning( $this->get_archive_method(), __( 'No valid archive method found.', 'backupwordpress' ) );
943
  }
944
+ }
945
 
946
+ // Delete the database dump file
947
+ if ( file_exists( $this->get_database_dump_filepath() ) ) {
948
+ unlink( $this->get_database_dump_filepath() );
949
+ }
 
 
 
 
 
950
 
951
+ $this->do_action( 'hmbkp_archive_finished' );
952
 
953
+ }
954
 
955
+ /**
956
+ * Zip using the native zip command
957
+ */
958
+ public function zip() {
959
 
960
+ $this->archive_method = 'zip';
961
 
962
+ $this->do_action( 'hmbkp_archive_started' );
963
 
964
+ // Add the database dump to the archive
965
+ if ( 'file' !== $this->get_type() && file_exists( $this->get_database_dump_filepath() ) ) {
966
+ $stderr = shell_exec( 'cd ' . escapeshellarg( $this->get_path() ) . ' && ' . escapeshellcmd( $this->get_zip_command_path() ) . ' -q ' . escapeshellarg( $this->get_archive_filepath() ) . ' ' . escapeshellarg( $this->get_database_dump_filename() ) . ' 2>&1' );
967
 
968
+ if ( ! empty ( $stderr ) ) {
969
  $this->warning( $this->get_archive_method(), $stderr );
 
970
  }
971
+ }
972
 
973
+ // Zip up $this->root
974
+ if ( 'database' !== $this->get_type() ) {
975
 
976
+ // cd to the site root
977
+ $command = 'cd ' . escapeshellarg( $this->get_root() );
978
 
979
+ // Run the zip command with the recursive and quiet flags
980
+ $command .= ' && ' . escapeshellcmd( $this->get_zip_command_path() ) . ' -rq ';
981
 
982
+ if ( defined( 'HMBKP_ENABLE_SYNC' ) && HMBKP_ENABLE_SYNC ) {
 
 
 
 
 
983
 
984
+ // If the destination zip file already exists then let's just add changed files to save time
985
+ if ( file_exists( $this->get_archive_filepath() ) && $this->get_existing_archive_filepath() ) {
986
+ $command .= ' -FS ';
987
  }
988
 
989
+ }
 
 
 
 
 
 
990
 
991
+ // Save the zip file to the correct path
992
+ $command .= escapeshellarg( $this->get_archive_filepath() ) . ' ./';
993
 
994
+ // Pass exclude rules in if we have them
995
+ if ( $this->exclude_string( 'zip' ) ) {
996
+ $command .= ' -x ' . $this->exclude_string( 'zip' );
997
+ }
998
 
999
+ // Push all output to STDERR
1000
+ $command .= ' 2>&1';
 
1001
 
1002
+ $stderr = shell_exec( $command );
1003
 
1004
+ }
1005
 
1006
+ if ( ! empty( $stderr ) ) {
1007
+ $this->warning( $this->get_archive_method(), $stderr );
1008
  }
1009
 
1010
+ $this->verify_archive();
 
 
 
 
1011
 
1012
+ }
 
1013
 
1014
+ /**
1015
+ * Fallback for creating zip archives if zip command is
1016
+ * unavailable.
1017
+ */
1018
+ public function zip_archive() {
1019
 
1020
+ $this->errors_to_warnings( $this->get_archive_method() );
1021
+ $this->archive_method = 'ziparchive';
1022
 
1023
+ $this->do_action( 'hmbkp_archive_started' );
 
 
1024
 
1025
+ $zip = new \ZipArchive();
1026
 
1027
+ if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->get_archive_filepath(), \ZIPARCHIVE::CREATE ) ) {
1028
+ return;
1029
+ }
 
1030
 
1031
+ $excludes = $this->exclude_string( 'regex' );
1032
 
1033
+ // Add the database
1034
+ if ( $this->get_type() !== 'file' && file_exists( $this->get_database_dump_filepath() ) ) {
1035
+ $zip->addFile( $this->get_database_dump_filepath(), $this->get_database_dump_filename() );
1036
+ }
1037
 
1038
+ if ( $this->get_type() !== 'database' ) {
1039
 
1040
+ $files_added = 0;
 
 
 
1041
 
1042
+ foreach ( $this->get_files() as $file ) {
 
 
 
1043
 
1044
+ // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1045
+ if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1046
+ continue;
1047
+ }
1048
 
1049
+ // Skip unreadable files
1050
+ if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1051
+ continue;
1052
+ }
 
1053
 
1054
+ // Excludes
1055
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
1056
+ continue;
1057
+ }
 
1058
 
1059
+ if ( $file->isDir() ) {
1060
+ $zip->addEmptyDir( trailingslashit( str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) );
1061
+ } elseif ( $file->isFile() ) {
1062
+ $zip->addFile( $file->getPathname(), str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) );
1063
  }
1064
 
1065
+ if ( ++ $files_added % 500 === 0 ) {
1066
+ if ( ! $zip->close() || ! $zip->open( $this->get_archive_filepath(), \ZIPARCHIVE::CREATE ) ) {
1067
+ return;
1068
+ }
1069
+ }
1070
 
 
 
1071
  }
1072
 
1073
+ }
1074
+
1075
+ if ( $zip->status ) {
1076
+ $this->warning( $this->get_archive_method(), $zip->status );
1077
+ }
1078
+
1079
+ if ( $zip->statusSys ) {
1080
+ $this->warning( $this->get_archive_method(), $zip->statusSys );
1081
+ }
1082
+
1083
+ $zip->close();
1084
+
1085
+ $this->verify_archive();
1086
+
1087
+ }
1088
 
1089
+ public function verify_mysqldump() {
1090
 
1091
+ $this->do_action( 'hmbkp_mysqldump_verify_started' );
1092
 
1093
+ // If we've already passed then no need to check again
1094
+ if ( ! empty( $this->mysqldump_verified ) ) {
1095
+ return true;
1096
  }
1097
 
1098
+ // If there are mysqldump errors delete the database dump file as mysqldump will still have written one
1099
+ if ( $this->get_errors( $this->get_mysqldump_method() ) && file_exists( $this->get_database_dump_filepath() ) ) {
1100
+ unlink( $this->get_database_dump_filepath() );
1101
+ }
 
 
 
1102
 
1103
+ // If we have an empty file delete it
1104
+ if ( @filesize( $this->get_database_dump_filepath() ) === 0 ) {
1105
+ unlink( $this->get_database_dump_filepath() );
1106
+ }
1107
 
1108
+ // If the file still exists then it must be good
1109
+ if ( file_exists( $this->get_database_dump_filepath() ) ) {
1110
+ return $this->mysqldump_verified = true;
1111
+ }
1112
 
1113
+ return false;
1114
 
1115
+ }
1116
 
1117
+ /**
1118
+ * Verify that the archive is valid and contains all the files it should contain.
1119
+ *
1120
+ * @return bool
1121
+ */
1122
+ public function verify_archive() {
1123
 
1124
+ $this->do_action( 'hmbkp_archive_verify_started' );
1125
 
1126
+ // If we've already passed then no need to check again
1127
+ if ( ! empty( $this->archive_verified ) ) {
1128
+ return true;
1129
+ }
 
 
1130
 
1131
+ // If there are errors delete the backup file.
1132
+ if ( $this->get_errors( $this->get_archive_method() ) && file_exists( $this->get_archive_filepath() ) ) {
1133
+ unlink( $this->get_archive_filepath() );
1134
+ }
 
 
1135
 
1136
+ // If the archive file still exists assume it's good
1137
+ if ( file_exists( $this->get_archive_filepath() ) ) {
1138
+ return $this->archive_verified = true;
1139
+ }
1140
+
1141
+ return false;
1142
 
1143
+ }
1144
 
1145
+ /**
1146
+ * Return an array of all files in the filesystem.
1147
+ *
1148
+ * @param bool $ignore_default_exclude_rules If true then will return all files under root. Otherwise returns all files except those matching default exclude rules.
1149
+ *
1150
+ * @return array
1151
+ */
1152
+ public function get_files( $ignore_default_exclude_rules = false ) {
1153
+
1154
+ if ( ! empty( $this->files ) ) {
1155
+ return $this->files;
1156
  }
1157
 
1158
+ $finder = new Finder();
1159
+ $finder->followLinks();
1160
+ $finder->ignoreDotFiles( false );
1161
+ $finder->ignoreUnreadableDirs();
1162
 
1163
+ if ( ! $ignore_default_exclude_rules ) {
1164
+ // Skips folders/files that match default exclude patterns
1165
+ foreach ( $this->default_excludes() as $exclude ) {
1166
+ $finder->notPath( $exclude );
 
1167
  }
1168
+ }
1169
 
1170
+ foreach ( $finder->in( $this->get_root() ) as $entry ) {
1171
+ $this->files[] = $entry;
1172
+ }
 
1173
 
1174
+ return $this->files;
 
 
 
1175
 
1176
+ }
 
 
 
1177
 
1178
+ /**
1179
+ * Returns an array of files that will be included in the backup.
1180
+ *
1181
+ * @return array
1182
+ */
1183
+ public function get_included_files() {
1184
 
1185
+ if ( ! empty( $this->included_files ) ) {
1186
+ return $this->included_files;
1187
  }
1188
 
1189
+ $this->included_files = array();
 
 
 
 
 
1190
 
1191
+ $excludes = $this->exclude_string( 'regex' );
1192
 
1193
+ foreach ( $this->get_files( true ) as $file ) {
1194
+
1195
+ // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1196
+ if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1197
+ continue;
1198
  }
1199
 
1200
+ // Skip unreadable files
1201
+ if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1202
+ continue;
1203
  }
1204
 
1205
+ // Excludes
1206
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
1207
+ continue;
1208
  }
1209
 
1210
+ $this->included_files[] = $file;
1211
 
1212
  }
1213
 
1214
+ return $this->included_files;
 
 
 
 
 
 
 
1215
 
1216
+ }
1217
 
1218
+ /**
1219
+ * Returns an array of files that match the exclude rules.
1220
+ *
1221
+ * @return array
1222
+ */
1223
+ public function get_excluded_files() {
1224
 
1225
+ if ( ! empty( $this->excluded_files ) ) {
1226
+ return $this->excluded_files;
1227
+ }
 
1228
 
1229
+ $this->excluded_files = array();
 
 
 
 
 
1230
 
1231
+ $excludes = $this->exclude_string( 'regex' );
 
 
1232
 
1233
+ foreach ( $this->get_files( true ) as $file ) {
1234
 
1235
+ // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1236
+ if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1237
+ continue;
1238
+ }
1239
 
1240
+ // Skip unreadable files
1241
+ if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1242
+ continue;
1243
+ }
 
 
1244
 
1245
+ // Excludes
1246
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
1247
+ $this->excluded_files[] = $file;
1248
  }
1249
 
1250
+ }
1251
 
1252
+ return $this->excluded_files;
1253
 
1254
+ }
1255
 
1256
+ /**
1257
+ * Returns an array of unreadable files.
1258
+ *
1259
+ * @return array
1260
+ */
1261
+ public function get_unreadable_files() {
1262
 
1263
+ if ( ! empty( $this->unreadable_files ) ) {
1264
+ return $this->unreadable_files;
1265
+ }
 
1266
 
1267
+ $this->unreadable_files = array();
 
 
 
1268
 
1269
+ foreach ( $this->get_files( true ) as $file ) {
1270
 
1271
+ // Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
1272
+ if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
1273
+ continue;
1274
  }
1275
 
1276
+ if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
1277
+ $this->unreadable_files[] = $file;
1278
+ }
1279
 
1280
  }
1281
 
1282
+ return $this->unreadable_files;
 
 
 
 
 
1283
 
1284
+ }
 
 
 
 
1285
 
1286
+ /**
1287
+ * Get an array of exclude rules
1288
+ *
1289
+ * The backup path is automatically excluded
1290
+ *
1291
+ * @return array
1292
+ */
1293
+ public function get_excludes() {
1294
 
1295
+ $excludes = array();
1296
 
1297
+ if ( isset( $this->excludes ) ) {
1298
+ $excludes = $this->excludes;
1299
+ }
 
1300
 
1301
+ // If path() is inside root(), exclude it
1302
+ if ( strpos( $this->get_path(), $this->get_root() ) !== false ) {
1303
+ array_unshift( $excludes, trailingslashit( $this->get_path() ) );
1304
+ }
1305
 
1306
+ return array_unique( $excludes );
 
 
 
1307
 
1308
+ }
1309
 
1310
+ /**
1311
+ * Set the excludes, expects and array
1312
+ *
1313
+ * @param Array $excludes
1314
+ * @param Bool $append
1315
+ */
1316
+ public function set_excludes( $excludes, $append = false ) {
1317
 
1318
+ if ( is_string( $excludes ) ) {
1319
+ $excludes = explode( ',', $excludes );
1320
  }
1321
 
1322
+ if ( $append ) {
1323
+ $excludes = array_merge( $this->excludes, $excludes );
1324
+ }
 
 
 
 
 
 
 
 
 
1325
 
1326
+ $this->excludes = array_filter( array_unique( array_map( 'trim', $excludes ) ) );
1327
 
1328
+ }
 
 
 
1329
 
1330
+ /**
1331
+ * Generate the exclude param string for the zip backup
1332
+ *
1333
+ * Takes the exclude rules and formats them for use with either
1334
+ * the shell zip command or pclzip
1335
+ *
1336
+ * @param string $context . (default: 'zip')
1337
+ *
1338
+ * @return string
1339
+ */
1340
+ public function exclude_string( $context = 'zip' ) {
1341
 
1342
+ // Return a comma separated list by default
1343
+ $separator = ', ';
1344
+ $wildcard = '';
1345
 
1346
+ // The zip command
1347
+ if ( $context === 'zip' ) {
1348
+ $wildcard = '*';
1349
+ $separator = ' -x ';
1350
 
1351
+ // The PclZip fallback library
1352
+ } elseif ( $context === 'regex' ) {
1353
+ $wildcard = '([\s\S]*?)';
1354
+ $separator = '|';
1355
  }
1356
 
1357
+ $excludes = $this->get_excludes();
 
 
 
 
 
1358
 
1359
+ foreach ( $excludes as $key => &$rule ) {
1360
 
1361
+ $file = $absolute = $fragment = false;
1362
 
1363
+ // Files don't end with /
1364
+ if ( ! in_array( substr( $rule, - 1 ), array( '\\', '/' ) ) ) {
1365
+ $file = true;
1366
+ } // If rule starts with a / then treat as absolute path
1367
+ elseif ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
1368
+ $absolute = true;
1369
+ } // Otherwise treat as dir fragment
1370
+ else {
1371
+ $fragment = true;
1372
+ }
1373
 
1374
+ // Strip $this->root and conform
1375
+ $rule = str_ireplace( $this->get_root(), '', untrailingslashit( wp_normalize_path( $rule ) ) );
1376
 
1377
+ // Strip the preceeding slash
1378
+ if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
1379
+ $rule = substr( $rule, 1 );
1380
  }
1381
 
1382
+ // Escape string for regex
1383
+ if ( $context === 'regex' ) {
1384
+ $rule = str_replace( '.', '\.', $rule );
1385
  }
1386
 
1387
+ // Convert any existing wildcards
1388
+ if ( $wildcard !== '*' && false !== strpos( $rule, '*' ) ) {
1389
+ $rule = str_replace( '*', $wildcard, $rule );
1390
+ }
1391
 
1392
+ // Wrap directory fragments and files in wildcards for zip
1393
+ if ( 'zip' === $context && ( $fragment || $file ) ) {
1394
+ $rule = $wildcard . $rule . $wildcard;
1395
+ }
1396
 
1397
+ // Add a wildcard to the end of absolute url for zips
1398
+ if ( 'zip' === $context && $absolute ) {
1399
+ $rule .= $wildcard;
1400
+ }
 
 
 
1401
 
1402
+ // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
1403
+ if ( $file && 'regex' === $context ) {
1404
+ $rule .= '$';
1405
  }
1406
 
1407
+ // Add a start carrot to absolute urls for pclzip
1408
+ if ( $absolute && 'regex' === $context ) {
1409
+ $rule = '^' . $rule;
1410
  }
1411
 
1412
+ }
1413
 
1414
+ // Escape shell args for zip command
1415
+ if ( $context === 'zip' ) {
1416
+ $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
1417
  }
1418
 
1419
+ return implode( $separator, $excludes );
 
 
 
 
 
 
 
 
 
 
1420
 
1421
+ }
 
 
1422
 
1423
+ /**
1424
+ * Add backquotes to tables and db-names in SQL queries. Taken from phpMyAdmin.
1425
+ *
1426
+ * @param mixed $a_name
1427
+ *
1428
+ * @return array|string
1429
+ */
1430
+ private function sql_backquote( $a_name ) {
1431
 
1432
+ if ( ! empty( $a_name ) && $a_name !== '*' ) {
 
 
 
 
1433
 
1434
+ if ( is_array( $a_name ) ) {
1435
 
1436
+ $result = array();
1437
 
1438
+ reset( $a_name );
1439
 
1440
+ while ( list( $key, $val ) = each( $a_name ) ) {
1441
+ $result[ $key ] = '`' . $val . '`';
 
 
 
 
 
 
 
1442
  }
1443
 
1444
+ return $result;
 
1445
 
1446
+ } else {
1447
+ return '`' . $a_name . '`';
1448
+ }
 
1449
 
1450
+ } else {
1451
+ return $a_name;
1452
+ }
 
1453
 
1454
+ }
 
 
 
1455
 
1456
+ /**
1457
+ * Reads the Database table in $table and creates
1458
+ * SQL Statements for recreating structure and data
1459
+ * Taken partially from phpMyAdmin and partially from
1460
+ * Alain Wolf, Zurich - Switzerland
1461
+ * Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
1462
+ *
1463
+ * @param string $sql_file
1464
+ * @param string $table
1465
+ */
1466
+ private function make_sql( $sql_file, $table ) {
1467
 
1468
+ // Add SQL statement to drop existing table
1469
+ $sql_file .= "\n";
1470
+ $sql_file .= "\n";
1471
+ $sql_file .= "#\n";
1472
+ $sql_file .= "# Delete any existing table " . $this->sql_backquote( $table ) . "\n";
1473
+ $sql_file .= "#\n";
1474
+ $sql_file .= "\n";
1475
+ $sql_file .= "DROP TABLE IF EXISTS " . $this->sql_backquote( $table ) . ";\n";
1476
 
1477
+ /* Table Structure */
 
 
 
1478
 
1479
+ // Comment in SQL-file
1480
+ $sql_file .= "\n";
1481
+ $sql_file .= "\n";
1482
+ $sql_file .= "#\n";
1483
+ $sql_file .= "# Table structure of table " . $this->sql_backquote( $table ) . "\n";
1484
+ $sql_file .= "#\n";
1485
+ $sql_file .= "\n";
1486
 
1487
+ // Get table structure
1488
+ $query = 'SHOW CREATE TABLE ' . $this->sql_backquote( $table );
1489
+ $result = mysql_query( $query, $this->db );
1490
+
1491
+ if ( $result ) {
1492
 
1493
+ if ( mysql_num_rows( $result ) > 0 ) {
1494
+ $sql_create_arr = mysql_fetch_array( $result );
1495
+ $sql_file .= $sql_create_arr[1];
1496
  }
1497
 
1498
+ mysql_free_result( $result );
1499
+ $sql_file .= ' ;';
1500
 
1501
  }
1502
 
1503
+ /* Table Contents */
 
 
 
 
 
 
 
1504
 
1505
+ // Get table contents
1506
+ $query = 'SELECT * FROM ' . $this->sql_backquote( $table );
1507
+ $result = mysql_query( $query, $this->db );
1508
 
1509
+ $fields_cnt = 0;
1510
+ $rows_cnt = 0;
1511
 
1512
+ if ( $result ) {
1513
+ $fields_cnt = mysql_num_fields( $result );
1514
+ $rows_cnt = mysql_num_rows( $result );
1515
+ }
1516
 
1517
+ // Comment in SQL-file
1518
+ $sql_file .= "\n";
1519
+ $sql_file .= "\n";
1520
+ $sql_file .= "#\n";
1521
+ $sql_file .= "# Data contents of table " . $table . " (" . $rows_cnt . " records)\n";
1522
+ $sql_file .= "#\n";
1523
 
1524
+ $field_set = $field_num = array();
 
 
1525
 
1526
+ // Checks whether the field is an integer or not
1527
+ for ( $j = 0; $j < $fields_cnt; $j ++ ) {
1528
 
1529
+ $field_set[ $j ] = $this->sql_backquote( mysql_field_name( $result, $j ) );
1530
+ $type = mysql_field_type( $result, $j );
 
1531
 
1532
+ if ( $type === 'tinyint' || $type === 'smallint' || $type === 'mediumint' || $type === 'int' || $type === 'bigint' ) {
1533
+ $field_num[ $j ] = true;
1534
  } else {
1535
+ $field_num[ $j ] = false;
1536
  }
1537
 
1538
  }
1539
 
1540
+ // Sets the scheme
1541
+ $entries = 'INSERT INTO ' . $this->sql_backquote( $table ) . ' VALUES (';
1542
+ $search = array( '\x00', '\x0a', '\x0d', '\x1a' ); //\x08\\x09, not required
1543
+ $replace = array( '\0', '\n', '\r', '\Z' );
1544
+ $current_row = 0;
1545
+ $batch_write = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1546
 
1547
+ $values = array();
 
 
1548
 
1549
+ while ( $row = mysql_fetch_row( $result ) ) {
 
1550
 
1551
+ $current_row ++;
 
 
 
1552
 
1553
+ // build the statement
1554
+ for ( $j = 0; $j < $fields_cnt; $j ++ ) {
 
 
 
 
1555
 
1556
+ if ( ! isset( $row[ $j ] ) ) {
1557
+ $values[] = 'NULL';
1558
 
1559
+ } elseif ( $row[ $j ] === '0' || $row[ $j ] !== '' ) {
 
1560
 
1561
+ // a number
1562
+ if ( $field_num[ $j ] ) {
1563
+ $values[] = $row[ $j ];
1564
+ } else {
1565
+ $values[] = "'" . str_replace( $search, $replace, $this->sql_addslashes( $row[ $j ] ) ) . "'";
1566
+ }
1567
 
 
 
1568
  } else {
1569
+ $values[] = "''";
1570
  }
1571
 
1572
  }
1573
 
1574
+ $sql_file .= " \n" . $entries . implode( ', ', $values ) . ") ;";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1575
 
1576
+ // write the rows in batches of 100
1577
+ if ( $batch_write === 100 ) {
1578
+ $batch_write = 0;
1579
+ $this->write_sql( $sql_file );
1580
+ $sql_file = '';
1581
+ }
1582
 
1583
+ $batch_write ++;
1584
 
1585
+ unset( $values );
 
 
 
 
 
1586
 
1587
+ }
1588
 
1589
+ mysql_free_result( $result );
1590
 
1591
+ // Create footer/closing comment in SQL-file
1592
+ $sql_file .= "\n";
1593
+ $sql_file .= "#\n";
1594
+ $sql_file .= "# End of data contents of table " . $table . "\n";
1595
+ $sql_file .= "# --------------------------------------------------------\n";
1596
+ $sql_file .= "\n";
1597
 
1598
+ $this->write_sql( $sql_file );
1599
 
1600
+ }
 
 
 
 
 
1601
 
1602
+ /**
1603
+ * Better addslashes for SQL queries.
1604
+ * Taken from phpMyAdmin.
1605
+ *
1606
+ * @param string $a_string (default: '')
1607
+ * @param bool $is_like (default: false)
1608
+ *
1609
+ * @return mixed
1610
+ */
1611
+ private function sql_addslashes( $a_string = '', $is_like = false ) {
1612
 
1613
+ if ( $is_like ) {
1614
+ $a_string = str_replace( '\\', '\\\\\\\\', $a_string );
1615
+ } else {
1616
+ $a_string = str_replace( '\\', '\\\\', $a_string );
1617
  }
1618
 
1619
+ $a_string = str_replace( '\'', '\\\'', $a_string );
 
 
 
 
 
 
 
 
 
1620
 
1621
+ return $a_string;
1622
+ }
 
 
 
1623
 
1624
+ /**
1625
+ * Write the SQL file
1626
+ *
1627
+ * @param string $sql
1628
+ *
1629
+ * @return null|boolean
1630
+ */
1631
+ private function write_sql( $sql ) {
1632
 
1633
+ $sqlname = $this->get_database_dump_filepath();
 
1634
 
1635
+ // Actually write the sql file
1636
+ if ( is_writable( $sqlname ) || ! file_exists( $sqlname ) ) {
 
 
 
 
 
 
1637
 
1638
+ if ( ! $handle = @fopen( $sqlname, 'a' ) ) {
1639
+ return;
1640
+ }
1641
 
1642
+ if ( ! fwrite( $handle, $sql ) ) {
1643
+ return;
1644
+ }
1645
 
1646
+ fclose( $handle );
 
 
1647
 
1648
+ return true;
 
 
1649
 
1650
+ }
1651
 
1652
+ }
1653
 
1654
+ /**
1655
+ * Get the errors
1656
+ *
1657
+ */
1658
+ public function get_errors( $context = null ) {
1659
 
1660
+ if ( ! empty( $context ) ) {
1661
+ return isset( $this->errors[ $context ] ) ? $this->errors[ $context ] : array();
1662
  }
1663
 
1664
+ return $this->errors;
 
 
 
 
1665
 
1666
+ }
 
 
1667
 
1668
+ /**
1669
+ * Add an error to the errors stack
1670
+ *
1671
+ * @param string $context
1672
+ * @param mixed $error
1673
+ */
1674
+ public function error( $context, $error ) {
1675
 
1676
+ if ( empty( $context ) || empty( $error ) ) {
1677
+ return;
1678
  }
1679
 
1680
+ $this->do_action( 'hmbkp_error' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1681
 
1682
+ $this->errors[ $context ][ $_key = md5( implode( ':', (array) $error ) ) ] = $error;
1683
 
1684
+ }
 
 
 
 
 
1685
 
1686
+ /**
1687
+ * Migrate errors to warnings
1688
+ *
1689
+ * @param null $context
1690
+ */
1691
+ private function errors_to_warnings( $context = null ) {
1692
 
1693
+ $errors = empty( $context ) ? $this->get_errors() : array( $context => $this->get_errors( $context ) );
 
 
1694
 
1695
+ if ( empty( $errors ) ) {
1696
+ return;
1697
+ }
 
 
1698
 
1699
+ foreach ( $errors as $error_context => $context_errors ) {
1700
+ foreach ( $context_errors as $error ) {
1701
+ $this->warning( $error_context, $error );
 
1702
  }
 
1703
  }
1704
 
1705
+ if ( $context ) {
1706
+ unset( $this->errors[ $context ] );
1707
+ } else {
1708
+ $this->errors = array();
1709
+ }
1710
 
1711
+ }
 
 
1712
 
1713
+ /**
1714
+ * Get the warnings
1715
+ *
1716
+ */
1717
+ public function get_warnings( $context = null ) {
1718
 
1719
+ if ( ! empty( $context ) ) {
1720
+ return isset( $this->warnings[ $context ] ) ? $this->warnings[ $context ] : array();
1721
  }
1722
 
1723
+ return $this->warnings;
 
 
 
 
 
 
1724
 
1725
+ }
 
 
 
 
1726
 
1727
+ /**
1728
+ * Add an warning to the warnings stack
1729
+ *
1730
+ * @param string $context
1731
+ * @param mixed $warning
1732
+ */
1733
+ private function warning( $context, $warning ) {
1734
 
1735
+ if ( empty( $context ) || empty( $warning ) ) {
1736
+ return;
1737
  }
1738
 
1739
+ $this->do_action( 'hmbkp_warning' );
 
 
 
 
 
 
 
 
 
 
 
 
1740
 
1741
+ $this->warnings[ $context ][ $_key = md5( implode( ':', (array) $warning ) ) ] = $warning;
1742
 
1743
+ }
1744
 
1745
+ /**
1746
+ * Custom error handler for catching php errors
1747
+ *
1748
+ * @param $type
1749
+ *
1750
+ * @return bool
1751
+ */
1752
+ public function error_handler( $type ) {
1753
 
1754
+ // Skip strict & deprecated warnings
1755
+ if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 ) {
1756
  return false;
 
1757
  }
1758
 
1759
+ $args = func_get_args();
 
 
 
 
 
1760
 
1761
+ array_shift( $args );
1762
 
1763
+ $this->warning( 'php', implode( ', ', array_splice( $args, 0, 3 ) ) );
 
1764
 
1765
+ return false;
1766
 
1767
+ }
 
 
1768
 
1769
+ /**
1770
+ * Determine if user can connect via the CLI
1771
+ *
1772
+ * @return \WP_Error
1773
+ */
1774
+ public function user_can_connect() {
1775
 
1776
+ // mysql --host=localhost --user=myname --password=mypass mydb
1777
 
1778
+ // Guess port or socket connection type
1779
+ $port_or_socket = strstr( DB_HOST, ':' );
1780
 
1781
+ $host = DB_HOST;
1782
 
1783
+ if ( ! empty( $port_or_socket ) ) {
1784
 
1785
+ $host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
1786
 
1787
+ $port_or_socket = substr( $port_or_socket, 1 );
1788
 
1789
+ if ( 0 !== strpos( $port_or_socket, '/' ) ) {
1790
 
1791
+ $port = intval( $port_or_socket );
1792
 
1793
+ $maybe_socket = strstr( $port_or_socket, ':' );
 
1794
 
1795
+ if ( ! empty( $maybe_socket ) ) {
 
1796
 
1797
+ $socket = substr( $maybe_socket, 1 );
 
1798
 
1799
+ }
 
 
 
1800
 
1801
+ } else {
 
1802
 
1803
+ $socket = $port_or_socket;
 
 
 
1804
 
 
 
 
1805
  }
1806
+ }
1807
 
1808
+ // Path to the mysqldump executable
1809
+ $cmd = 'mysql ';
 
 
 
1810
 
1811
+ // Username
1812
+ $cmd .= ' -u ' . escapeshellarg( DB_USER );
1813
 
1814
+ // Don't pass the password if it's blank
1815
+ if ( DB_PASSWORD ) {
1816
+ $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
1817
+ }
1818
 
1819
+ // Set the host
1820
+ $cmd .= ' -h ' . escapeshellarg( $host );
 
 
1821
 
1822
+ // Set the port if it was set
1823
+ if ( ! empty( $port ) && is_numeric( $port ) ) {
1824
+ $cmd .= ' -P ' . $port;
1825
  }
1826
 
1827
+ // Set the socket path
1828
+ if ( ! empty( $socket ) && ! is_numeric( $socket ) ) {
1829
+ $cmd .= ' --protocol=socket -S ' . $socket;
1830
+ }
1831
 
1832
+ // The database we're dumping
1833
+ $cmd .= ' ' . escapeshellarg( DB_NAME );
1834
 
1835
+ // Quit immediately
1836
+ $cmd .= ' --execute="quit"';
 
1837
 
1838
+ // Pipe STDERR to STDOUT
1839
+ $cmd .= ' 2>&1';
 
 
 
 
 
 
 
 
 
1840
 
1841
+ // Store any returned data in an error
1842
+ $stderr = shell_exec( $cmd );
1843
 
1844
+ // Skip the new password warning that is output in mysql > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
1845
+ if ( 'Warning: Using a password on the command line interface can be insecure.' === trim( $stderr ) ) {
1846
+ $stderr = '';
 
 
 
1847
  }
1848
 
1849
+ if ( $stderr ) {
1850
+ return new \WP_Error( 'mysql-cli-connect-error', __( 'Could not connect to mysql', 'backupwordpress' ) );
1851
+ }
1852
  }
1853
 
1854
  }
1855
+
classes/class-backupwordpress-wp-cli-command.php CHANGED
@@ -57,7 +57,7 @@ class BackUpWordPress_WP_CLI_Command extends WP_CLI_Command {
57
  $hm_backup = new HM\BackUpWordPress\Backup();
58
 
59
  if ( ! empty( $assoc_args['destination'] ) ) {
60
- Path::get_instance()->set_path( $assoc_args['destination'] );
61
  }
62
 
63
  HM\BackUpWordPress\Path::get_instance()->cleanup();
57
  $hm_backup = new HM\BackUpWordPress\Backup();
58
 
59
  if ( ! empty( $assoc_args['destination'] ) ) {
60
+ HM\BackUpWordPress\Path::get_instance()->set_path( $assoc_args['destination'] );
61
  }
62
 
63
  HM\BackUpWordPress\Path::get_instance()->cleanup();
classes/class-email-service.php CHANGED
@@ -31,7 +31,7 @@ class Email_Service extends Service {
31
  <td>
32
  <input type="text" id="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" value="<?php echo esc_attr( $this->get_field_value( 'email' ) ); ?>" placeholder="name@youremail.com" />
33
 
34
- <p class="description"><?php printf( __( 'Receive a notification email when a backup completes, if the backup is small enough (&lt; %s) then it will be attached to the email. Separate multiple email addresses with a comma.', 'backupwordpress' ), '<code>' . size_format( hmbkp_get_max_attachment_size() ) . '</code>' ); ?></p>
35
  </td>
36
 
37
  </tr>
@@ -177,7 +177,7 @@ class Email_Service extends Service {
177
  }
178
 
179
  $subject = sprintf( __( 'Backup of %s Failed', 'backupwordpress' ), $domain );
180
-
181
  $message = sprintf( __( 'BackUpWordPress was unable to backup your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'Here are the errors that we\'re encountered:', 'backupwordpress' ) . "\n\n" . '%2$s' . "\n\n" . __( 'If the errors above look like Martian, forward this email to %3$s and we\'ll take a look', 'backupwordpress' ) . "\n\n" . __( "Kind Regards,\nThe Apologetic BackUpWordPress Backup Emailing Robot", 'backupwordpress' ), home_url(), $error_message, 'backupwordpress@hmn.md' );
182
 
183
  wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
31
  <td>
32
  <input type="text" id="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" value="<?php echo esc_attr( $this->get_field_value( 'email' ) ); ?>" placeholder="name@youremail.com" />
33
 
34
+ <p class="description"><?php printf( __( 'Receive a notification email when a backup completes. If the backup is small enough (&lt; %s), then it will be attached to the email. Separate multiple email addresses with a comma.', 'backupwordpress' ), '<code>' . size_format( hmbkp_get_max_attachment_size() ) . '</code>' ); ?></p>
35
  </td>
36
 
37
  </tr>
177
  }
178
 
179
  $subject = sprintf( __( 'Backup of %s Failed', 'backupwordpress' ), $domain );
180
+
181
  $message = sprintf( __( 'BackUpWordPress was unable to backup your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'Here are the errors that we\'re encountered:', 'backupwordpress' ) . "\n\n" . '%2$s' . "\n\n" . __( 'If the errors above look like Martian, forward this email to %3$s and we\'ll take a look', 'backupwordpress' ) . "\n\n" . __( "Kind Regards,\nThe Apologetic BackUpWordPress Backup Emailing Robot", 'backupwordpress' ), home_url(), $error_message, 'backupwordpress@hmn.md' );
182
 
183
  wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
classes/class-path.php CHANGED
@@ -82,7 +82,7 @@ class Path {
82
  // Ensure the backup directory is protected
83
  $this->protect_path();
84
 
85
- return Backup::conform_dir( $this->path );
86
 
87
  }
88
 
@@ -246,7 +246,7 @@ class Path {
246
  // Protect the directory with a .htaccess file on Apache servers
247
  if ( $is_apache && function_exists( 'insert_with_markers' ) && ! file_exists( $htaccess ) && wp_is_writable( $this->path ) ) {
248
 
249
- $contents[] = '# ' . sprintf( __( 'This %s file ensures that other people cannot download your backup files.', 'hmbkp' ), '.htaccess' );
250
  $contents[] = '';
251
  $contents[] = '<IfModule mod_rewrite.c>';
252
  $contents[] = 'RewriteEngine On';
@@ -255,6 +255,8 @@ class Path {
255
  $contents[] = '</IfModule>';
256
  $contents[] = '';
257
 
 
 
258
  insert_with_markers( $htaccess, 'BackUpWordPress', $contents );
259
 
260
  }
82
  // Ensure the backup directory is protected
83
  $this->protect_path();
84
 
85
+ return wp_normalize_path( $this->path );
86
 
87
  }
88
 
246
  // Protect the directory with a .htaccess file on Apache servers
247
  if ( $is_apache && function_exists( 'insert_with_markers' ) && ! file_exists( $htaccess ) && wp_is_writable( $this->path ) ) {
248
 
249
+ $contents[] = '# ' . sprintf( __( 'This %s file ensures that other people cannot download your backup files.', 'backupwordpress' ), '.htaccess' );
250
  $contents[] = '';
251
  $contents[] = '<IfModule mod_rewrite.c>';
252
  $contents[] = 'RewriteEngine On';
255
  $contents[] = '</IfModule>';
256
  $contents[] = '';
257
 
258
+ file_put_contents( $htaccess, '' );
259
+
260
  insert_with_markers( $htaccess, 'BackUpWordPress', $contents );
261
 
262
  }
classes/class-plugin.php CHANGED
@@ -6,7 +6,7 @@ namespace HM\BackUpWordPress;
6
  * Class Plugin
7
  */
8
  final class Plugin {
9
- const PLUGIN_VERSION = '3.2.7';
10
 
11
  /**
12
  * @var Plugin The singleton instance.
@@ -213,10 +213,10 @@ final class Plugin {
213
  'hmbkp_run_schedule_nonce' => wp_create_nonce( 'hmbkp_run_schedule' ),
214
  'update' => __( 'Update', 'backupwordpress' ),
215
  'cancel' => __( 'Cancel', 'backupwordpress' ),
216
- 'delete_schedule' => __( 'Are you sure you want to delete this schedule? All of it\'s backups will also be deleted.', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n",
217
  'delete_backup' => __( 'Are you sure you want to delete this backup?', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n",
218
  'remove_exclude_rule' => __( 'Are you sure you want to remove this exclude rule?', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n",
219
- 'remove_old_backups' => __( 'Reducing the number of backups that are stored on this server will cause some of your existing backups to be deleted, are you sure that\'s what you want?', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n"
220
  )
221
  );
222
 
6
  * Class Plugin
7
  */
8
  final class Plugin {
9
+ const PLUGIN_VERSION = '3.3.0';
10
 
11
  /**
12
  * @var Plugin The singleton instance.
213
  'hmbkp_run_schedule_nonce' => wp_create_nonce( 'hmbkp_run_schedule' ),
214
  'update' => __( 'Update', 'backupwordpress' ),
215
  'cancel' => __( 'Cancel', 'backupwordpress' ),
216
+ 'delete_schedule' => __( 'Are you sure you want to delete this schedule? All of its backups will also be deleted.', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n",
217
  'delete_backup' => __( 'Are you sure you want to delete this backup?', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n",
218
  'remove_exclude_rule' => __( 'Are you sure you want to remove this exclude rule?', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n",
219
+ 'remove_old_backups' => __( 'Reducing the number of backups that are stored on this server will cause some of your existing backups to be deleted. Are you sure that\'s what you want?', 'backupwordpress' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'backupwordpress' ) . "\n"
220
  )
221
  );
222
 
classes/class-schedule.php CHANGED
@@ -58,7 +58,7 @@ class Scheduled_Backup {
58
 
59
  // Verify the schedule id
60
  if ( ! is_string( $id ) || ! trim( $id ) ) {
61
- throw new \Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non empty string' );
62
  }
63
 
64
  // Store id for later
@@ -140,15 +140,14 @@ class Scheduled_Backup {
140
  * Returns the given option value or WP_Error if it doesn't exist
141
  *
142
  * @param $option_name
143
- *
144
- * @return WP_Error
145
  */
146
  public function get_schedule_option( $option_name ) {
147
 
148
  if ( isset( $this->options[ $option_name ] ) ) {
149
  return $this->options[ $option_name ];
150
  } else {
151
- return new WP_Error( 'invalid_option_name', __( 'Invalid Option Name', 'backupwordpress' ) );
152
  }
153
  }
154
 
@@ -159,9 +158,7 @@ class Scheduled_Backup {
159
  */
160
  public function get_name() {
161
 
162
- $recurrence = ( 'manually' === $this->get_reoccurrence() ) ? $this->get_reoccurrence() : substr( $this->get_reoccurrence(), 6 );
163
-
164
- return ucwords( $this->get_type() ) . ' ' . $recurrence;
165
 
166
  }
167
 
@@ -299,8 +296,12 @@ class Scheduled_Backup {
299
 
300
  /**
301
  * Set the service options for this schedule
 
 
 
302
  */
303
  public function set_service_options( $service, Array $options ) {
 
304
  $this->options[ $service ] = $options;
305
  }
306
 
@@ -311,7 +312,7 @@ class Scheduled_Backup {
311
  *
312
  * @return string
313
  */
314
- public function get_site_size() {
315
 
316
  $size = 0;
317
 
@@ -332,7 +333,7 @@ class Scheduled_Backup {
332
 
333
  $root = new \SplFileInfo( $this->backup->get_root() );
334
 
335
- $size += $this->filesize( $root );
336
 
337
  }
338
 
@@ -347,8 +348,8 @@ class Scheduled_Backup {
347
  *
348
  * @return bool|string
349
  */
350
- public function get_formatted_site_size() {
351
- return size_format( $this->get_site_size() );
352
  }
353
 
354
  /**
@@ -356,7 +357,7 @@ class Scheduled_Backup {
356
  *
357
  * @return int The total of the file or directory
358
  */
359
- function is_site_size_being_calculated() {
360
  return false !== get_transient( 'hmbkp_directory_filesizes_running' );
361
  }
362
 
@@ -365,7 +366,7 @@ class Scheduled_Backup {
365
  *
366
  * @return bool The total of the file or directory
367
  */
368
- function is_site_size_cached() {
369
  return false !== get_transient( 'hmbkp_directory_filesizes' );
370
  }
371
 
@@ -472,9 +473,9 @@ class Scheduled_Backup {
472
  foreach ( $files as $file ) {
473
 
474
  if ( $file->isReadable() ) {
475
- $directory_sizes[ Backup::conform_dir( $file->getRealpath() ) ] = $file->getSize();
476
  } else {
477
- $directory_sizes[ Backup::conform_dir( $file->getRealpath() ) ] = 0;
478
  }
479
 
480
  }
@@ -559,7 +560,7 @@ class Scheduled_Backup {
559
  foreach ( $directory_sizes as $path => $size ) {
560
 
561
  // Skip excluded files if we have excludes
562
- if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( $root, '', Backup::conform_dir( $path ) ) ) ) {
563
  unset( $directory_sizes[ $path ] );
564
  }
565
 
@@ -690,17 +691,7 @@ class Scheduled_Backup {
690
  * @return array
691
  */
692
  public static function get_cron_schedules() {
693
-
694
- $schedules = wp_get_schedules();
695
-
696
- // remove any schedule whose key is not prefixed with 'hmbkp_'
697
- foreach ( $schedules as $key => $arr ) {
698
- if ( ! preg_match( '/^hmbkp_/', $key ) ) {
699
- unset( $schedules[ $key ] );
700
- }
701
- }
702
-
703
- return $schedules;
704
  }
705
 
706
  /**
@@ -862,7 +853,7 @@ class Scheduled_Backup {
862
  ) );
863
 
864
  if ( false === @file_put_contents( $this->get_schedule_running_path(), $status ) ) {
865
- throw new \RuntimeException( sprintf( __( 'Error writing to file. (%s)', 'backpwordpress' ), $this->get_schedule_running_path() ) );
866
  }
867
 
868
  }
@@ -1119,7 +1110,7 @@ class Scheduled_Backup {
1119
 
1120
  // Check that it's a valid filepath
1121
  if ( empty( $filepath ) || ! is_string( $filepath ) ) {
1122
- return new \WP_Error( 'hmbkp_empty_string_error', sprintf( __( 'Argument 1 for %s must be a non empty string', 'backupwordpress' ), __METHOD__ ) );
1123
  }
1124
 
1125
  // Make sure it exists
58
 
59
  // Verify the schedule id
60
  if ( ! is_string( $id ) || ! trim( $id ) ) {
61
+ throw new \Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non-empty string' );
62
  }
63
 
64
  // Store id for later
140
  * Returns the given option value or WP_Error if it doesn't exist
141
  *
142
  * @param $option_name
143
+ * @return \WP_Error
 
144
  */
145
  public function get_schedule_option( $option_name ) {
146
 
147
  if ( isset( $this->options[ $option_name ] ) ) {
148
  return $this->options[ $option_name ];
149
  } else {
150
+ return new \WP_Error( 'invalid_option_name', __( 'Invalid Option Name', 'backupwordpress' ) );
151
  }
152
  }
153
 
158
  */
159
  public function get_name() {
160
 
161
+ return ucwords( $this->get_type() ) . ' ' . $this->get_reoccurrence();
 
 
162
 
163
  }
164
 
296
 
297
  /**
298
  * Set the service options for this schedule
299
+ *
300
+ * @param $service
301
+ * @param array $options
302
  */
303
  public function set_service_options( $service, Array $options ) {
304
+
305
  $this->options[ $service ] = $options;
306
  }
307
 
312
  *
313
  * @return string
314
  */
315
+ public function get_site_size( $skip_excluded_files = false ) {
316
 
317
  $size = 0;
318
 
333
 
334
  $root = new \SplFileInfo( $this->backup->get_root() );
335
 
336
+ $size += $this->filesize( $root, $skip_excluded_files );
337
 
338
  }
339
 
348
  *
349
  * @return bool|string
350
  */
351
+ public function get_formatted_site_size( $skip_excluded_files = false ) {
352
+ return size_format( $this->get_site_size( $skip_excluded_files ) );
353
  }
354
 
355
  /**
357
  *
358
  * @return int The total of the file or directory
359
  */
360
+ public function is_site_size_being_calculated() {
361
  return false !== get_transient( 'hmbkp_directory_filesizes_running' );
362
  }
363
 
366
  *
367
  * @return bool The total of the file or directory
368
  */
369
+ public function is_site_size_cached() {
370
  return false !== get_transient( 'hmbkp_directory_filesizes' );
371
  }
372
 
473
  foreach ( $files as $file ) {
474
 
475
  if ( $file->isReadable() ) {
476
+ $directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = $file->getSize();
477
  } else {
478
+ $directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = 0;
479
  }
480
 
481
  }
560
  foreach ( $directory_sizes as $path => $size ) {
561
 
562
  // Skip excluded files if we have excludes
563
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( $root, '', wp_normalize_path( $path ) ) ) ) {
564
  unset( $directory_sizes[ $path ] );
565
  }
566
 
691
  * @return array
692
  */
693
  public static function get_cron_schedules() {
694
+ return hmbkp_cron_schedules();
 
 
 
 
 
 
 
 
 
 
695
  }
696
 
697
  /**
853
  ) );
854
 
855
  if ( false === @file_put_contents( $this->get_schedule_running_path(), $status ) ) {
856
+ throw new \RuntimeException( sprintf( __( 'Error writing to file. (%s)', 'backupwordpress' ), $this->get_schedule_running_path() ) );
857
  }
858
 
859
  }
1110
 
1111
  // Check that it's a valid filepath
1112
  if ( empty( $filepath ) || ! is_string( $filepath ) ) {
1113
+ return new \WP_Error( 'hmbkp_empty_string_error', sprintf( __( 'Argument 1 for %s must be a non-empty string', 'backupwordpress' ), __METHOD__ ) );
1114
  }
1115
 
1116
  // Make sure it exists
classes/class-service.php CHANGED
@@ -80,11 +80,16 @@ abstract class Service {
80
  * This is where the service should do it's thing
81
  *
82
  * @see Backup::do_action for a list of the actions
 
 
 
 
 
83
  */
84
  abstract public function action( $action, Backup $backup );
85
 
86
  public function get_slug() {
87
- return sanitize_title_with_dashes( $this->name );
88
  }
89
 
90
  /**
@@ -125,8 +130,9 @@ abstract class Service {
125
 
126
  $old_data = $this->schedule->get_service_options( $classname );
127
 
128
- $new_data = isset( $_POST[$classname] ) ? $_POST[$classname] : array();
129
 
 
130
  $errors = $this->update( $new_data, $old_data );
131
 
132
  if ( $errors && $errors = array_flip( $errors ) ) {
@@ -209,4 +215,4 @@ abstract class Service {
209
 
210
  public static function intercom_data_html() {}
211
 
212
- }
80
  * This is where the service should do it's thing
81
  *
82
  * @see Backup::do_action for a list of the actions
83
+ *
84
+ * @param $action
85
+ * @param Backup $backup
86
+ *
87
+ * @return mixed
88
  */
89
  abstract public function action( $action, Backup $backup );
90
 
91
  public function get_slug() {
92
+ return sanitize_key( $this->name );
93
  }
94
 
95
  /**
130
 
131
  $old_data = $this->schedule->get_service_options( $classname );
132
 
133
+ $new_data = isset( $_POST[ $classname ] ) ? $_POST[ $classname ] : array();
134
 
135
+ // $new_data is passed by ref, so it is clean after this method call.
136
  $errors = $this->update( $new_data, $old_data );
137
 
138
  if ( $errors && $errors = array_flip( $errors ) ) {
215
 
216
  public static function intercom_data_html() {}
217
 
218
+ }
classes/deprecated.php CHANGED
@@ -78,7 +78,7 @@ class HMBKP_Services {
78
  private static function instantiate( $classname ) {
79
 
80
  if ( ! class_exists( $classname ) )
81
- return new WP_Error( 'hmbkp_invalid_type_error', sprintf( __( 'Argument 1 for %s must be a valid class', 'backupwordpress' ) ), __METHOD__ );
82
 
83
  /**
84
  * @var HMBKP_Service
78
  private static function instantiate( $classname ) {
79
 
80
  if ( ! class_exists( $classname ) )
81
+ return new \WP_Error( 'hmbkp_invalid_type_error', sprintf( __( 'Argument 1 for %s must be a valid class', 'backupwordpress' ) ), __METHOD__ );
82
 
83
  /**
84
  * @var HMBKP_Service
composer.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name" : "humanmade/backupwordpress",
3
+ "description": "Simple automated backups of your WordPress powered website.",
4
+ "keywords" : [
5
+ "wordpress",
6
+ "backup"
7
+ ],
8
+ "type" : "wordpress-plugin",
9
+ "homepage" : "https://github.com/humanmade/backupwordpress",
10
+ "license" : "GPL-3.0",
11
+ "authors" : [
12
+ {
13
+ "name" : "Human Made Limited",
14
+ "email" : "backupwordpress@hmn.md",
15
+ "homepage": "https://bwp.hmn.md/"
16
+ }
17
+ ],
18
+ "support" : {
19
+ "issues": "https://github.com/humanmade/backupwordpress/issues"
20
+ },
21
+ "require": {
22
+ "symfony/finder": "~2.6"
23
+ }
24
+ }
composer.lock ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "hash": "e5254a26f0409a605db41dec40b32972",
8
+ "packages": [
9
+ {
10
+ "name": "symfony/finder",
11
+ "version": "v2.7.3",
12
+ "source": {
13
+ "type": "git",
14
+ "url": "https://github.com/symfony/Finder.git",
15
+ "reference": "ae0f363277485094edc04c9f3cbe595b183b78e4"
16
+ },
17
+ "dist": {
18
+ "type": "zip",
19
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/ae0f363277485094edc04c9f3cbe595b183b78e4",
20
+ "reference": "ae0f363277485094edc04c9f3cbe595b183b78e4",
21
+ "shasum": ""
22
+ },
23
+ "require": {
24
+ "php": ">=5.3.9"
25
+ },
26
+ "require-dev": {
27
+ "symfony/phpunit-bridge": "~2.7"
28
+ },
29
+ "type": "library",
30
+ "extra": {
31
+ "branch-alias": {
32
+ "dev-master": "2.7-dev"
33
+ }
34
+ },
35
+ "autoload": {
36
+ "psr-4": {
37
+ "Symfony\\Component\\Finder\\": ""
38
+ }
39
+ },
40
+ "notification-url": "https://packagist.org/downloads/",
41
+ "license": [
42
+ "MIT"
43
+ ],
44
+ "authors": [
45
+ {
46
+ "name": "Fabien Potencier",
47
+ "email": "fabien@symfony.com"
48
+ },
49
+ {
50
+ "name": "Symfony Community",
51
+ "homepage": "https://symfony.com/contributors"
52
+ }
53
+ ],
54
+ "description": "Symfony Finder Component",
55
+ "homepage": "https://symfony.com",
56
+ "time": "2015-07-09 16:07:40"
57
+ }
58
+ ],
59
+ "packages-dev": [],
60
+ "aliases": [],
61
+ "minimum-stability": "stable",
62
+ "stability-flags": [],
63
+ "prefer-stable": false,
64
+ "prefer-lowest": false,
65
+ "platform": [],
66
+ "platform-dev": []
67
+ }
functions/core.php CHANGED
@@ -84,7 +84,7 @@ function hmbkp_update() {
84
  }
85
 
86
  // Backup schedule
87
- $legacy_schedule->set_reoccurrence( get_option( 'hmbkp_schedule_frequency', 'hmbkp_daily' ) );
88
 
89
  // Automatic backups disabled?
90
  if ( ( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) && HMBKP_DISABLE_AUTOMATIC_BACKUP ) || get_option( 'hmbkp_disable_automatic_backup' ) ) {
@@ -126,26 +126,6 @@ function hmbkp_update() {
126
 
127
  }
128
 
129
- // Update from 2.2.4
130
- if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '2.2.5', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
131
-
132
- $schedules = HM\BackUpWordPress\Schedules::get_instance();
133
-
134
- // Loop through all schedules and re-set the reccurrence to include hmbkp_
135
- foreach ( $schedules->get_schedules() as $schedule ) {
136
-
137
- $reoccurrence = $schedule->get_reoccurrence();
138
-
139
- if ( $reoccurrence !== 'manually' && strpos( $reoccurrence, 'hmbkp_' ) === false ) {
140
- $schedule->set_reoccurrence( 'hmbkp_' . $schedule->get_reoccurrence() );
141
- }
142
-
143
- $schedule->save();
144
-
145
- }
146
-
147
- }
148
-
149
  // Update from 2.x to 3.0
150
  if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '2.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
151
 
@@ -266,11 +246,31 @@ function hmbkp_update() {
266
  array_map( 'delete_transient', array( 'hmbkp_plugin_data', 'hmbkp_directory_filesizes', 'hmbkp_directory_filesize_running', 'timeout_hmbkp_wp_cron_test_beacon', 'hmbkp_wp_cron_test_beacon' ) );
267
 
268
  }
269
-
270
  restore_current_blog();
271
  }
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  // Every update
275
  if ( get_option( 'hmbkp_plugin_version' ) && version_compare( HM\BackUpWordPress\Plugin::PLUGIN_VERSION, get_option( 'hmbkp_plugin_version' ), '>' ) ) {
276
 
@@ -304,8 +304,8 @@ function hmbkp_setup_default_schedules() {
304
  */
305
  $database_daily = new HM\BackUpWordPress\Scheduled_Backup( (string) time() );
306
  $database_daily->set_type( 'database' );
307
- $database_daily->set_schedule_start_time( hmbkp_determine_start_time( 'hmbkp_daily', array( 'hours' => '23', 'minutes' => '0' ) ) );
308
- $database_daily->set_reoccurrence( 'hmbkp_daily' );
309
  $database_daily->set_max_backups( 7 );
310
  $database_daily->save();
311
 
@@ -315,15 +315,15 @@ function hmbkp_setup_default_schedules() {
315
  */
316
  $complete_weekly = new HM\BackUpWordPress\Scheduled_Backup( (string) ( time() + 1 ) );
317
  $complete_weekly->set_type( 'complete' );
318
- $complete_weekly->set_schedule_start_time( hmbkp_determine_start_time( 'hmbkp_weekly', array( 'day_of_week' => 'sunday', 'hours' => '3', 'minutes' => '0' ) ) );
319
- $complete_weekly->set_reoccurrence( 'hmbkp_weekly' );
320
  $complete_weekly->set_max_backups( 3 );
321
  $complete_weekly->save();
322
 
323
  $schedules->refresh_schedules();
324
 
325
  add_action( 'admin_notices', function() {
326
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has setup your default schedules.', 'backupwordpress' ) . '</strong> ' . __( 'By default BackUpWordPress performs a daily backup of your database and a weekly backup of your database &amp; files. You can modify these schedules.', 'backupwordpress' ) . '</p></div>';
327
  } );
328
 
329
  }
@@ -336,14 +336,16 @@ add_action( 'admin_init', 'hmbkp_setup_default_schedules' );
336
  * @param $schedules
337
  * @return array $reccurrences
338
  */
339
- function hmbkp_cron_schedules( $schedules ) {
340
-
341
- $schedules['hmbkp_hourly'] = array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly', 'backupwordpress' ) );
342
- $schedules['hmbkp_twicedaily'] = array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily', 'backupwordpress' ) );
343
- $schedules['hmbkp_daily'] = array( 'interval' => DAY_IN_SECONDS, 'display' => __( 'Once Daily', 'backupwordpress' ) );
344
- $schedules['hmbkp_weekly'] = array( 'interval' => WEEK_IN_SECONDS, 'display' => __( 'Once Weekly', 'backupwordpress' ) );
345
- $schedules['hmbkp_fortnightly'] = array( 'interval' => 2 * WEEK_IN_SECONDS, 'display' => __( 'Once Biweekly', 'backupwordpress' ) );
346
- $schedules['hmbkp_monthly'] = array( 'interval' => 30 * DAY_IN_SECONDS, 'display' => __( 'Once Monthly', 'backupwordpress' ) );
 
 
347
 
348
  return $schedules;
349
  }
@@ -441,16 +443,7 @@ function hmbkp_is_path_accessible( $dir ) {
441
  * @return array
442
  */
443
  function hmbkp_get_cron_schedules() {
444
-
445
- $schedules = wp_get_schedules();
446
-
447
- // remove any schedule whose key is not prefixed with 'hmbkp_'
448
- foreach ( $schedules as $key => $arr ) {
449
- if ( ! preg_match( '/^hmbkp_/', $key ) )
450
- unset( $schedules[$key] );
451
- }
452
-
453
- return $schedules;
454
  }
455
 
456
  /**
@@ -505,22 +498,22 @@ function hmbkp_determine_start_time( $type, $times = array() ) {
505
 
506
  switch ( $type ) {
507
 
508
- case 'hmbkp_hourly' :
509
- case 'hmbkp_daily' :
510
- case 'hmbkp_twicedaily':
511
 
512
  // The next occurance of the specified time
513
  $schedule_start = $hm;
514
  break;
515
 
516
- case 'hmbkp_weekly' :
517
- case 'hmbkp_fortnightly' :
518
 
519
  // The next day of the week at the specified time
520
  $schedule_start = $args['day_of_week'] . ' ' . $hm;
521
  break;
522
 
523
- case 'hmbkp_monthly' :
524
 
525
  // The occurance of the time on the specified day of the month
526
  $schedule_start = date( 'F', $args['now'] ) . ' ' . $args['day_of_month'] . ' ' . $hm;
84
  }
85
 
86
  // Backup schedule
87
+ $legacy_schedule->set_reoccurrence( get_option( 'hmbkp_schedule_frequency', 'daily' ) );
88
 
89
  // Automatic backups disabled?
90
  if ( ( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) && HMBKP_DISABLE_AUTOMATIC_BACKUP ) || get_option( 'hmbkp_disable_automatic_backup' ) ) {
126
 
127
  }
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  // Update from 2.x to 3.0
130
  if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '2.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
131
 
246
  array_map( 'delete_transient', array( 'hmbkp_plugin_data', 'hmbkp_directory_filesizes', 'hmbkp_directory_filesize_running', 'timeout_hmbkp_wp_cron_test_beacon', 'hmbkp_wp_cron_test_beacon' ) );
247
 
248
  }
249
+
250
  restore_current_blog();
251
  }
252
  }
253
 
254
+ // Update from PRIOR_VERSION
255
+ if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.3.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
256
+
257
+ $schedules = HM\BackUpWordPress\Schedules::get_instance();
258
+
259
+ // Loop through all schedules and re-set the reccurrence to include hmbkp_
260
+ foreach ( $schedules->get_schedules() as $schedule ) {
261
+
262
+ $reoccurrence = $schedule->get_reoccurrence();
263
+
264
+ if ( $reoccurrence !== 'manually' && strpos( $reoccurrence, 'hmbkp_' ) === 0 ) {
265
+ $schedule->set_reoccurrence( substr( $reoccurrence, 6 ) );
266
+ }
267
+
268
+ $schedule->save();
269
+
270
+ }
271
+
272
+ }
273
+
274
  // Every update
275
  if ( get_option( 'hmbkp_plugin_version' ) && version_compare( HM\BackUpWordPress\Plugin::PLUGIN_VERSION, get_option( 'hmbkp_plugin_version' ), '>' ) ) {
276
 
304
  */
305
  $database_daily = new HM\BackUpWordPress\Scheduled_Backup( (string) time() );
306
  $database_daily->set_type( 'database' );
307
+ $database_daily->set_schedule_start_time( hmbkp_determine_start_time( 'daily', array( 'hours' => '23', 'minutes' => '0' ) ) );
308
+ $database_daily->set_reoccurrence( 'daily' );
309
  $database_daily->set_max_backups( 7 );
310
  $database_daily->save();
311
 
315
  */
316
  $complete_weekly = new HM\BackUpWordPress\Scheduled_Backup( (string) ( time() + 1 ) );
317
  $complete_weekly->set_type( 'complete' );
318
+ $complete_weekly->set_schedule_start_time( hmbkp_determine_start_time( 'weekly', array( 'day_of_week' => 'sunday', 'hours' => '3', 'minutes' => '0' ) ) );
319
+ $complete_weekly->set_reoccurrence( 'weekly' );
320
  $complete_weekly->set_max_backups( 3 );
321
  $complete_weekly->save();
322
 
323
  $schedules->refresh_schedules();
324
 
325
  add_action( 'admin_notices', function() {
326
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has set up your default schedules.', 'backupwordpress' ) . '</strong> ' . __( 'By default BackUpWordPress performs a daily backup of your database and a weekly backup of your database &amp; files. You can modify these schedules.', 'backupwordpress' ) . '</p></div>';
327
  } );
328
 
329
  }
336
  * @param $schedules
337
  * @return array $reccurrences
338
  */
339
+ function hmbkp_cron_schedules( $schedules = array() ) {
340
+
341
+ $schedules += array(
342
+ 'hourly' => array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly', 'backupwordpress' ) ),
343
+ 'twicedaily' => array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily', 'backupwordpress' ) ),
344
+ 'daily' => array( 'interval' => DAY_IN_SECONDS, 'display' => __( 'Once Daily', 'backupwordpress' ) ),
345
+ 'weekly' => array( 'interval' => WEEK_IN_SECONDS, 'display' => __( 'Once Weekly', 'backupwordpress' ) ),
346
+ 'fortnightly' => array( 'interval' => 2 * WEEK_IN_SECONDS, 'display' => __( 'Once Every Two Weeks', 'backupwordpress' ) ),
347
+ 'monthly' => array( 'interval' => 30 * DAY_IN_SECONDS, 'display' => __( 'Once Monthly', 'backupwordpress' ) ),
348
+ );
349
 
350
  return $schedules;
351
  }
443
  * @return array
444
  */
445
  function hmbkp_get_cron_schedules() {
446
+ return hmbkp_cron_schedules();
 
 
 
 
 
 
 
 
 
447
  }
448
 
449
  /**
498
 
499
  switch ( $type ) {
500
 
501
+ case 'hourly' :
502
+ case 'daily' :
503
+ case 'twicedaily':
504
 
505
  // The next occurance of the specified time
506
  $schedule_start = $hm;
507
  break;
508
 
509
+ case 'weekly' :
510
+ case 'fortnightly' :
511
 
512
  // The next day of the week at the specified time
513
  $schedule_start = $args['day_of_week'] . ' ' . $hm;
514
  break;
515
 
516
+ case 'monthly' :
517
 
518
  // The occurance of the time on the specified day of the month
519
  $schedule_start = date( 'F', $args['now'] ) . ' ' . $args['day_of_month'] . ' ' . $hm;
functions/interface.php CHANGED
@@ -68,7 +68,7 @@ function hmbkp_admin_notices() {
68
 
69
  <?php if ( ! empty( $notices['backup_errors'] ) ) : ?>
70
 
71
- <div id="hmbkp-warning" class="error fade">
72
  <p>
73
  <strong><?php _e( 'BackUpWordPress detected issues with your last backup.', 'backupwordpress' ); ?></strong>
74
  <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_dismiss_error' ), admin_url( 'admin-post.php' ) ), 'hmbkp_dismiss_error', 'hmbkp_dismiss_error_nonce' ) ); ?>" style="float: right;" class="button">
@@ -77,41 +77,62 @@ function hmbkp_admin_notices() {
77
  </p>
78
 
79
  <ul>
 
80
  <?php foreach ( $notices['backup_errors'] as $notice ) : ?>
 
81
  <li><pre><?php echo esc_html( $notice ); ?></pre></li>
 
82
  <?php endforeach; ?>
 
83
  </ul>
84
 
 
 
85
  </div>
86
 
87
  <?php endif; ?>
88
 
89
  <?php if ( ! empty( $notices['server_config'] ) ) : ?>
90
 
91
- <div id="hmbkp-warning" class="error fade">
92
 
93
  <ul>
 
94
  <?php foreach ( $notices['server_config'] as $notice ) : ?>
 
95
  <li><?php echo wp_kses_data( $notice ); ?></li>
 
96
  <?php endforeach; ?>
 
97
  </ul>
98
 
 
 
99
  </div>
100
 
101
  <?php endif; ?>
102
 
103
  <?php $notices = array_filter( $notices );
104
 
105
- if ( ! empty( $notices ) ) : ?>
 
 
 
 
 
 
106
 
107
- <?php foreach ( $notices as $notice_type ) : ?>
108
- <?php if ( ! ( in_array( $notice_type, array( 'server_config', 'backup_errors' ) ) ) ) : ?>
109
- <div id="hmbkp-warning" class="error fade">
110
  <?php foreach ( array_unique( $notice_type ) as $msg ) : ?>
 
111
  <p><?php echo wp_kses_data( $msg ); ?></p>
 
 
 
112
  <?php endforeach; ?>
113
  </div>
 
114
  <?php endif; ?>
 
115
  <?php endforeach; ?>
116
 
117
  <?php endif; ?>
@@ -138,11 +159,11 @@ function hmbkp_set_server_config_notices() {
138
  }
139
 
140
  if ( ! is_dir( hmbkp_path() ) ) {
141
- $messages[] = sprintf( __( 'The backups directory can\'t be created because your %1$s directory isn\'t writable, run %2$s or %3$s or create the folder yourself.', 'backupwordpress' ), '<code>' . esc_html( dirname( hmbkp_path() ) ) . '</code>', '<code>chown ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html( dirname( hmbkp_path() ) ) . '</code>', '<code>chmod 777 ' . esc_html( dirname( hmbkp_path() ) ) . '</code>' );
142
  }
143
 
144
  if ( is_dir( hmbkp_path() ) && ! wp_is_writable( hmbkp_path() ) ) {
145
- $messages[] = sprintf( __( 'Your backups directory isn\'t writable, run %1$s or %2$s or set the permissions yourself.', 'backupwordpress' ), '<code>chown -R ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html( hmbkp_path() ) . '</code>', '<code>chmod -R 777 ' . esc_html( hmbkp_path() ) . '</code>' );
146
  }
147
 
148
  if ( HM\BackUpWordPress\Backup::is_safe_mode_active() ) {
@@ -313,7 +334,7 @@ function hmbkp_backup_warnings() {
313
 
314
  }
315
 
316
- function hmbkp_backups_number( $schedule ) {
317
 
318
  $number = count( $schedule->get_backups() );
319
 
@@ -332,18 +353,18 @@ function hmbkp_translated_schedule_title( $slug, $title ) {
332
  'complete-hourly' => esc_html__( 'Complete Hourly', 'backupwordpress' ),
333
  'file-hourly' => esc_html__( 'File Hourly', 'backupwordpress' ),
334
  'database-hourly' => esc_html__( 'Database Hourly', 'backupwordpress' ),
335
- 'complete-twicedaily' => esc_html__( 'Complete Twicedaily', 'backupwordpress' ),
336
  'file-twicedaily' => esc_html__( 'File Twicedaily', 'backupwordpress' ),
337
- 'database-twicedaily' => esc_html__( 'Database Twicedaily', 'backupwordpress' ),
338
  'complete-daily' => esc_html__( 'Complete Daily', 'backupwordpress' ),
339
  'file-daily' => esc_html__( 'File Daily', 'backupwordpress' ),
340
  'database-daily' => esc_html__( 'Database Daily', 'backupwordpress' ),
341
  'complete-weekly' => esc_html__( 'Complete Weekly', 'backupwordpress' ),
342
  'file-weekly' => esc_html__( 'File Weekly', 'backupwordpress' ),
343
  'database-weekly' => esc_html__( 'Database Weekly', 'backupwordpress' ),
344
- 'complete-fortnightly' => esc_html__( 'Complete Biweekly', 'backupwordpress' ),
345
- 'file-fortnightly' => esc_html__( 'File Biweekly', 'backupwordpress' ),
346
- 'database-fortnightly' => esc_html__( 'Database Biweekly', 'backupwordpress' ),
347
  'complete-monthly' => esc_html__( 'Complete Monthly', 'backupwordpress' ),
348
  'file-monthly' => esc_html__( 'File Monthly', 'backupwordpress' ),
349
  'database-monthly' => esc_html__( 'Database Monthly', 'backupwordpress' ),
68
 
69
  <?php if ( ! empty( $notices['backup_errors'] ) ) : ?>
70
 
71
+ <div id="hmbkp-warning-backup" class="error notice is-dismissible">
72
  <p>
73
  <strong><?php _e( 'BackUpWordPress detected issues with your last backup.', 'backupwordpress' ); ?></strong>
74
  <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_dismiss_error' ), admin_url( 'admin-post.php' ) ), 'hmbkp_dismiss_error', 'hmbkp_dismiss_error_nonce' ) ); ?>" style="float: right;" class="button">
77
  </p>
78
 
79
  <ul>
80
+
81
  <?php foreach ( $notices['backup_errors'] as $notice ) : ?>
82
+
83
  <li><pre><?php echo esc_html( $notice ); ?></pre></li>
84
+
85
  <?php endforeach; ?>
86
+
87
  </ul>
88
 
89
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'backupwordpress' ); ?></span></button>
90
+
91
  </div>
92
 
93
  <?php endif; ?>
94
 
95
  <?php if ( ! empty( $notices['server_config'] ) ) : ?>
96
 
97
+ <div id="hmbkp-warning-server" class="error notice is-dismissible">
98
 
99
  <ul>
100
+
101
  <?php foreach ( $notices['server_config'] as $notice ) : ?>
102
+
103
  <li><?php echo wp_kses_data( $notice ); ?></li>
104
+
105
  <?php endforeach; ?>
106
+
107
  </ul>
108
 
109
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'backupwordpress' ); ?></span></button>
110
+
111
  </div>
112
 
113
  <?php endif; ?>
114
 
115
  <?php $notices = array_filter( $notices );
116
 
117
+ if ( ! empty( $notices ) ) : ?>
118
+
119
+ <?php foreach ( $notices as $key => $notice_type ) : ?>
120
+
121
+ <?php if ( ! ( in_array( $key, array( 'server_config', 'backup_errors' ) ) ) ) : ?>
122
+
123
+ <div id="hmbkp-warning-other" class="error notice is-dismissible">
124
 
 
 
 
125
  <?php foreach ( array_unique( $notice_type ) as $msg ) : ?>
126
+
127
  <p><?php echo wp_kses_data( $msg ); ?></p>
128
+
129
+ <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'backupwordpress' ); ?></span></button>
130
+
131
  <?php endforeach; ?>
132
  </div>
133
+
134
  <?php endif; ?>
135
+
136
  <?php endforeach; ?>
137
 
138
  <?php endif; ?>
159
  }
160
 
161
  if ( ! is_dir( hmbkp_path() ) ) {
162
+ $messages[] = sprintf( __( 'The backups directory can\'t be created because your %1$s directory isn\'t writable. Run %2$s or %3$s or create the folder yourself.', 'backupwordpress' ), '<code>' . esc_html( dirname( hmbkp_path() ) ) . '</code>', '<code>chown ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html( dirname( hmbkp_path() ) ) . '</code>', '<code>chmod 777 ' . esc_html( dirname( hmbkp_path() ) ) . '</code>' );
163
  }
164
 
165
  if ( is_dir( hmbkp_path() ) && ! wp_is_writable( hmbkp_path() ) ) {
166
+ $messages[] = sprintf( __( 'Your backups directory isn\'t writable. Run %1$s or %2$s or set the permissions yourself.', 'backupwordpress' ), '<code>chown -R ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html( hmbkp_path() ) . '</code>', '<code>chmod -R 777 ' . esc_html( hmbkp_path() ) . '</code>' );
167
  }
168
 
169
  if ( HM\BackUpWordPress\Backup::is_safe_mode_active() ) {
334
 
335
  }
336
 
337
+ function hmbkp_backups_number( \HM\BackUpWordPress\Scheduled_Backup $schedule ) {
338
 
339
  $number = count( $schedule->get_backups() );
340
 
353
  'complete-hourly' => esc_html__( 'Complete Hourly', 'backupwordpress' ),
354
  'file-hourly' => esc_html__( 'File Hourly', 'backupwordpress' ),
355
  'database-hourly' => esc_html__( 'Database Hourly', 'backupwordpress' ),
356
+ 'complete-twicedaily' => esc_html__( 'Complete Twice Daily', 'backupwordpress' ),
357
  'file-twicedaily' => esc_html__( 'File Twicedaily', 'backupwordpress' ),
358
+ 'database-twicedaily' => esc_html__( 'Database Twice Daily', 'backupwordpress' ),
359
  'complete-daily' => esc_html__( 'Complete Daily', 'backupwordpress' ),
360
  'file-daily' => esc_html__( 'File Daily', 'backupwordpress' ),
361
  'database-daily' => esc_html__( 'Database Daily', 'backupwordpress' ),
362
  'complete-weekly' => esc_html__( 'Complete Weekly', 'backupwordpress' ),
363
  'file-weekly' => esc_html__( 'File Weekly', 'backupwordpress' ),
364
  'database-weekly' => esc_html__( 'Database Weekly', 'backupwordpress' ),
365
+ 'complete-fortnightly' => esc_html__( 'Complete Every Two Weeks', 'backupwordpress' ),
366
+ 'file-fortnightly' => esc_html__( 'File Every Two Weeks', 'backupwordpress' ),
367
+ 'database-fortnightly' => esc_html__( 'Database Every Two Weeks', 'backupwordpress' ),
368
  'complete-monthly' => esc_html__( 'Complete Monthly', 'backupwordpress' ),
369
  'file-monthly' => esc_html__( 'File Monthly', 'backupwordpress' ),
370
  'database-monthly' => esc_html__( 'Database Monthly', 'backupwordpress' ),
languages/backupwordpress-en_AU.mo ADDED
Binary file
languages/backupwordpress-en_AU.po ADDED
@@ -0,0 +1,1211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2015 Human Made Limited
2
+ # This file is distributed under the GPL-2.0+.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: BackUpWordPress Backup Plugin 3.2.6\n"
6
+ "POT-Creation-Date: 2015-07-13 12:44+0930\n"
7
+ "MIME-Version: 1.0\n"
8
+ "Content-Type: text/plain; charset=UTF-8\n"
9
+ "Content-Transfer-Encoding: 8bit\n"
10
+ "PO-Revision-Date: 2015-07-13 13:39+0930\n"
11
+ "Last-Translator: ucavus\n"
12
+ "Language-Team: ucavus\n"
13
+ "X-Generator: Poedit 1.8.2\n"
14
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
+ "Language: en_AU\n"
16
+
17
+ #: admin/actions.php:191
18
+ msgid "The schedule ID was not provided. Aborting."
19
+ msgstr ""
20
+
21
+ #: admin/actions.php:241
22
+ msgid "Backup type cannot be empty"
23
+ msgstr ""
24
+
25
+ #: admin/actions.php:245
26
+ msgid "Invalid backup type"
27
+ msgstr ""
28
+
29
+ #: admin/actions.php:259
30
+ msgid "Schedule cannot be empty"
31
+ msgstr ""
32
+
33
+ #: admin/actions.php:263
34
+ msgid "Invalid schedule"
35
+ msgstr ""
36
+
37
+ #: admin/actions.php:277
38
+ msgid "Day of the week must be a valid lowercase day name"
39
+ msgstr ""
40
+
41
+ #: admin/actions.php:296
42
+ msgid "Day of month must be between 1 and 31"
43
+ msgstr ""
44
+
45
+ #: admin/actions.php:315
46
+ msgid "Hours must be between 0 and 23"
47
+ msgstr ""
48
+
49
+ #: admin/actions.php:334
50
+ msgid "Minutes must be between 0 and 59"
51
+ msgstr ""
52
+
53
+ #: admin/actions.php:348
54
+ msgid "Max backups can't be empty"
55
+ msgstr ""
56
+
57
+ #: admin/actions.php:352
58
+ msgid "Max backups must be a number"
59
+ msgstr ""
60
+
61
+ #: admin/actions.php:356
62
+ msgid "Max backups must be greater than 0"
63
+ msgstr ""
64
+
65
+ #: admin/actions.php:708 admin/actions.php:714
66
+ msgid "BackUpWordPress has detected a problem."
67
+ msgstr ""
68
+
69
+ #: admin/actions.php:708 admin/actions.php:714
70
+ msgid ""
71
+ "%1$s is returning a %2$s response which could mean cron jobs aren't getting "
72
+ "fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. "
73
+ "See the %3$s for more details."
74
+ msgstr ""
75
+
76
+ #: admin/backups-table.php:8 admin/schedule-form-excludes.php:105
77
+ msgid "Size"
78
+ msgstr ""
79
+
80
+ #: admin/backups-table.php:9 admin/schedule-form-excludes.php:107
81
+ msgid "Type"
82
+ msgstr ""
83
+
84
+ #: admin/backups-table.php:10
85
+ msgid "Actions"
86
+ msgstr ""
87
+
88
+ #: admin/backups-table.php:35
89
+ msgid "This is where your backups will appear once you have some."
90
+ msgstr ""
91
+
92
+ #: admin/backups.php:22
93
+ msgid "add schedule"
94
+ msgstr ""
95
+
96
+ #: admin/backups.php:26
97
+ msgid "Support"
98
+ msgstr ""
99
+
100
+ #: admin/backups.php:32
101
+ msgid "Enable Support"
102
+ msgstr ""
103
+
104
+ #: admin/constants.php:3
105
+ msgid ""
106
+ "You can %1$s any of the following %2$s in your %3$s to control advanced "
107
+ "settings. %4$s. Defined %5$s will be highlighted."
108
+ msgstr ""
109
+
110
+ #: admin/constants.php:3 admin/menu.php:82
111
+ msgid "Constants"
112
+ msgstr ""
113
+
114
+ #: admin/constants.php:3
115
+ msgid "The Codex can help"
116
+ msgstr ""
117
+
118
+ #: admin/constants.php:14 admin/constants.php:30 admin/constants.php:46
119
+ #: admin/constants.php:62 admin/constants.php:78 admin/constants.php:94
120
+ #: admin/constants.php:110 classes/class-email-service.php:60
121
+ msgid "You've set it to: %s"
122
+ msgstr ""
123
+
124
+ #: admin/constants.php:17
125
+ msgid ""
126
+ "The path to folder you would like to store your backup files in, defaults to "
127
+ "%s."
128
+ msgstr ""
129
+
130
+ #: admin/constants.php:17 admin/constants.php:33 admin/constants.php:49
131
+ #: admin/constants.php:65 admin/constants.php:81 admin/constants.php:97
132
+ #: admin/constants.php:113 classes/class-email-service.php:63
133
+ msgid "e.g."
134
+ msgstr ""
135
+
136
+ #: admin/constants.php:33
137
+ msgid ""
138
+ "The path to your %1$s executable. Will be used for the %2$s part of the back "
139
+ "up if available."
140
+ msgstr ""
141
+
142
+ #: admin/constants.php:33 admin/constants.php:49
143
+ msgid "database"
144
+ msgstr ""
145
+
146
+ #: admin/constants.php:49
147
+ msgid ""
148
+ "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
149
+ "if available."
150
+ msgstr ""
151
+
152
+ #: admin/constants.php:49
153
+ msgid "files"
154
+ msgstr ""
155
+
156
+ #: admin/constants.php:65
157
+ msgid ""
158
+ "Comma separated list of files or directories to exclude, the backups "
159
+ "directory is automatically excluded."
160
+ msgstr ""
161
+
162
+ #: admin/constants.php:81
163
+ msgid "The capability to use when calling %1$s. Defaults to %2$s."
164
+ msgstr ""
165
+
166
+ #: admin/constants.php:97
167
+ msgid "The root directory that is backed up. Defaults to %s."
168
+ msgstr ""
169
+
170
+ #: admin/constants.php:113
171
+ msgid "The time that your schedules should run. Defaults to %s."
172
+ msgstr ""
173
+
174
+ #: admin/enable-support.php:3
175
+ msgid "Enable BackUpWordPress Support"
176
+ msgstr ""
177
+
178
+ #: admin/enable-support.php:5
179
+ msgid ""
180
+ "BackUpWordPress uses %s to provide support. In addition to allowing you to "
181
+ "send and receive messages we also send the following server information "
182
+ "along with your requests:"
183
+ msgstr ""
184
+
185
+ #: admin/enable-support.php:58
186
+ msgid "You can disable support in the future by deactivating BackUpWordPress."
187
+ msgstr ""
188
+
189
+ #: admin/enable-support.php:60
190
+ msgid "No thanks"
191
+ msgstr ""
192
+
193
+ #: admin/enable-support.php:61
194
+ msgid "Yes I want to enable support"
195
+ msgstr ""
196
+
197
+ #: admin/faq.php:2
198
+ msgid "Where does BackUpWordPress store the backup files?"
199
+ msgstr ""
200
+
201
+ #: admin/faq.php:4
202
+ msgid ""
203
+ "Backups are stored on your server in <code>/wp-content/backups</code>, you "
204
+ "can change the directory."
205
+ msgstr ""
206
+
207
+ #: admin/faq.php:6
208
+ msgid ""
209
+ "Important: By default BackUpWordPress backs up everything in your site root "
210
+ "as well as your database, this includes any non WordPress folders that "
211
+ "happen to be in your site root. This does mean that your backup directory "
212
+ "can get quite large."
213
+ msgstr ""
214
+
215
+ #: admin/faq.php:8
216
+ msgid "What if I want to back up my site to another destination?"
217
+ msgstr ""
218
+
219
+ #: admin/faq.php:10
220
+ msgid ""
221
+ "BackUpWordPress Pro supports Dropbox, Google Drive, Amazon S3, Rackspace, "
222
+ "Azure, DreamObjects and FTP/SFTP. Check it out here: <a href=\"http://bwp."
223
+ "hmn.md/?utm_source=wordpress-org&utm_medium=plugin-"
224
+ "page&utm_campaign=freeplugin\" title=\"BackUpWordPress Homepage\" target="
225
+ "\"_blank\">https://bwp.hmn.md</a>"
226
+ msgstr ""
227
+
228
+ #: admin/faq.php:12
229
+ msgid "How do I restore my site from a backup?"
230
+ msgstr ""
231
+
232
+ #: admin/faq.php:14
233
+ msgid ""
234
+ "You need to download the latest backup file either by clicking download on "
235
+ "the backups page or via <code>FTP</code>. <code>Unzip</code> the files and "
236
+ "upload all the files to your server overwriting your site. You can then "
237
+ "import the database using your hosts database management tool (likely "
238
+ "<code>phpMyAdmin</code>)."
239
+ msgstr ""
240
+
241
+ #: admin/faq.php:16
242
+ msgid ""
243
+ "See this guide for more details - <a href=\"https://bwp.hmn.md/support-"
244
+ "center/restore-backup/\" title=\"Go to support center\" target=\"_blank"
245
+ "\">How to restore from backup</a>."
246
+ msgstr ""
247
+
248
+ #: admin/faq.php:18
249
+ msgid "Does BackUpWordPress back up the backups directory?"
250
+ msgstr ""
251
+
252
+ #: admin/faq.php:20
253
+ msgid "No."
254
+ msgstr ""
255
+
256
+ #: admin/faq.php:22
257
+ msgid "I'm not receiving my backups by email?"
258
+ msgstr ""
259
+
260
+ #: admin/faq.php:24
261
+ msgid ""
262
+ "Most servers have a filesize limit on email attachments, it's generally "
263
+ "about 10mb. If your backup file is over that limit it won't be sent attached "
264
+ "to the email, instead you should receive an email with a link to download "
265
+ "the backup, if you aren't even receiving that then you likely have a mail "
266
+ "issue on your server that you'll need to contact your host about."
267
+ msgstr ""
268
+
269
+ #: admin/faq.php:26
270
+ msgid "How many backups are stored by default?"
271
+ msgstr ""
272
+
273
+ #: admin/faq.php:28
274
+ msgid "BackUpWordPress stores the last 10 backups by default."
275
+ msgstr ""
276
+
277
+ #: admin/faq.php:30
278
+ msgid "How long should a backup take?"
279
+ msgstr ""
280
+
281
+ #: admin/faq.php:32
282
+ msgid ""
283
+ "Unless your site is very large (many gigabytes) it should only take a few "
284
+ "minutes to perform a back up, if your back up has been running for longer "
285
+ "than an hour it's safe to assume that something has gone wrong, try de-"
286
+ "activating and re-activating the plugin, if it keeps happening, contact "
287
+ "support."
288
+ msgstr ""
289
+
290
+ #: admin/faq.php:34
291
+ msgid "What do I do if I get the wp-cron error message?"
292
+ msgstr ""
293
+
294
+ #: admin/faq.php:36
295
+ msgid ""
296
+ "The issue is that your <code>wp-cron.php</code> is not returning a "
297
+ "<code>200</code> response when hit with a HTTP request originating from your "
298
+ "own server, it could be several things, in most cases, it's an issue with "
299
+ "the server / site."
300
+ msgstr ""
301
+
302
+ #: admin/faq.php:38
303
+ msgid "There are some things you can test to confirm this is the issue."
304
+ msgstr ""
305
+
306
+ #: admin/faq.php:40
307
+ msgid "Are scheduled posts working? (They use wp-cron as well ). "
308
+ msgstr ""
309
+
310
+ #: admin/faq.php:42
311
+ msgid ""
312
+ "Are you hosted on Heart Internet? (wp-cron may not be supported by Heart "
313
+ "Internet, see below for work-around)."
314
+ msgstr ""
315
+
316
+ #: admin/faq.php:44
317
+ msgid "If you click manual backup does it work?"
318
+ msgstr ""
319
+
320
+ #: admin/faq.php:46
321
+ msgid ""
322
+ "Try adding <code>define( 'ALTERNATE_WP_CRON', true );</code> to your "
323
+ "<code>wp-config.php</code>, do automatic backups work?"
324
+ msgstr ""
325
+
326
+ #: admin/faq.php:48
327
+ msgid ""
328
+ "Is your site private (I.E. is it behind some kind of authentication, "
329
+ "maintenance plugin, .htaccess) if so wp-cron won't work until you remove it, "
330
+ "if you are and you temporarily remove the authentication, do backups start "
331
+ "working?"
332
+ msgstr ""
333
+
334
+ #: admin/faq.php:50
335
+ msgid ""
336
+ "Report the results to our support team for further help. To do this, either "
337
+ "enable suport from your Admin Dashboard (recommended), or email support@hmn."
338
+ "md"
339
+ msgstr ""
340
+
341
+ #: admin/faq.php:52
342
+ msgid "How to get BackUpWordPress working in Heart Internet"
343
+ msgstr ""
344
+
345
+ #: admin/faq.php:54
346
+ msgid ""
347
+ "The script to be entered into the Heart Internet cPanel is: <code>/usr/bin/"
348
+ "php5 /home/sites/yourdomain.com/public_html/wp-cron.php</code> (note the "
349
+ "space between php5 and the location of the file). The file <code>wp-cron."
350
+ "php</code> <code>chmod</code> must be set to <code>711</code>."
351
+ msgstr ""
352
+
353
+ #: admin/faq.php:56
354
+ msgid "My backups seem to be failing?"
355
+ msgstr ""
356
+
357
+ #: admin/faq.php:58
358
+ msgid ""
359
+ "If your backups are failing - it's commonly caused by lack of available "
360
+ "resources on your server. The easiest way to establish this to exclude some "
361
+ "[of] or your entire uploades folder, running a backup an if that succeeds. "
362
+ "If so, we know it's probably a server issue. If not, report the results to "
363
+ "our support team for further help. To do this, either enable suport from "
364
+ "your Admin Dashboard (recommended), or email support@hmn.md"
365
+ msgstr ""
366
+
367
+ #: admin/menu.php:13 admin/menu.php:17
368
+ msgid "Manage Backups"
369
+ msgstr ""
370
+
371
+ #: admin/menu.php:13 admin/menu.php:17 admin/menu.php:46
372
+ msgid "Backups"
373
+ msgstr ""
374
+
375
+ #: admin/menu.php:77
376
+ msgid "FAQ"
377
+ msgstr ""
378
+
379
+ #: admin/menu.php:95
380
+ msgid "Server Info"
381
+ msgstr ""
382
+
383
+ #: admin/menu.php:102
384
+ msgid "For more information:"
385
+ msgstr ""
386
+
387
+ #: admin/menu.php:104
388
+ msgid "Support Forums"
389
+ msgstr ""
390
+
391
+ #: admin/menu.php:105
392
+ msgid "Help with translation"
393
+ msgstr ""
394
+
395
+ #: admin/page.php:7
396
+ msgid ""
397
+ "If you're finding BackUpWordPress useful, please %1$s rate it on the plugin "
398
+ "directory%2$s."
399
+ msgstr ""
400
+
401
+ #: admin/schedule-form-excludes.php:6
402
+ msgid "Currently Excluded"
403
+ msgstr ""
404
+
405
+ #: admin/schedule-form-excludes.php:9
406
+ msgid ""
407
+ "We automatically detect and ignore common <abbr title=\"Version Control "
408
+ "Systems\">VCS</abbr> folders and other backup plugin folders."
409
+ msgstr ""
410
+
411
+ #: admin/schedule-form-excludes.php:44
412
+ msgid "Default rule"
413
+ msgstr ""
414
+
415
+ #: admin/schedule-form-excludes.php:48
416
+ msgid "Defined in wp-config.php"
417
+ msgstr ""
418
+
419
+ #: admin/schedule-form-excludes.php:55
420
+ msgid "Stop excluding"
421
+ msgstr ""
422
+
423
+ #: admin/schedule-form-excludes.php:71
424
+ msgid "Directory Listing"
425
+ msgstr ""
426
+
427
+ #: admin/schedule-form-excludes.php:73
428
+ msgid ""
429
+ "Here's a directory listing of all files on your site, you can browse through "
430
+ "and exclude files or folders that you don't want included in your backup."
431
+ msgstr ""
432
+
433
+ #: admin/schedule-form-excludes.php:104
434
+ msgid "Name"
435
+ msgstr ""
436
+
437
+ #: admin/schedule-form-excludes.php:106
438
+ msgid "Permissions"
439
+ msgstr ""
440
+
441
+ #: admin/schedule-form-excludes.php:108
442
+ msgid "Status"
443
+ msgstr ""
444
+
445
+ #: admin/schedule-form-excludes.php:168 admin/schedule-form-excludes.php:284
446
+ msgid "Refresh"
447
+ msgstr ""
448
+
449
+ #: admin/schedule-form-excludes.php:185 admin/schedule-form-excludes.php:308
450
+ msgid "Symlink"
451
+ msgstr ""
452
+
453
+ #: admin/schedule-form-excludes.php:189 admin/schedule-form-excludes.php:312
454
+ msgid "Folder"
455
+ msgstr ""
456
+
457
+ #: admin/schedule-form-excludes.php:282
458
+ msgid "Recalculate the size of this directory"
459
+ msgstr ""
460
+
461
+ #: admin/schedule-form-excludes.php:316
462
+ msgid "File"
463
+ msgstr ""
464
+
465
+ #: admin/schedule-form-excludes.php:327
466
+ msgid "Unreadable files won't be backed up."
467
+ msgstr ""
468
+
469
+ #: admin/schedule-form-excludes.php:327
470
+ msgid "Unreadable"
471
+ msgstr ""
472
+
473
+ #: admin/schedule-form-excludes.php:331
474
+ msgid "Excluded"
475
+ msgstr ""
476
+
477
+ #: admin/schedule-form-excludes.php:347
478
+ msgid "Exclude &rarr;"
479
+ msgstr ""
480
+
481
+ #: admin/schedule-form-excludes.php:365 admin/schedule-form.php:192
482
+ #: admin/schedule-settings.php:88
483
+ msgid "Done"
484
+ msgstr ""
485
+
486
+ #: admin/schedule-form.php:1 admin/schedule-settings.php:9
487
+ msgid "Settings"
488
+ msgstr ""
489
+
490
+ #: admin/schedule-form.php:36
491
+ msgid "Backup"
492
+ msgstr ""
493
+
494
+ #: admin/schedule-form.php:43
495
+ msgid "Both Database &amp; files"
496
+ msgstr ""
497
+
498
+ #: admin/schedule-form.php:45
499
+ msgid "Files only"
500
+ msgstr ""
501
+
502
+ #: admin/schedule-form.php:47
503
+ msgid "Database only"
504
+ msgstr ""
505
+
506
+ #: admin/schedule-form.php:58
507
+ msgid "Schedule"
508
+ msgstr ""
509
+
510
+ #: admin/schedule-form.php:65
511
+ msgid "Manual Only"
512
+ msgstr ""
513
+
514
+ #: admin/schedule-form.php:92
515
+ msgid "Start Day"
516
+ msgstr ""
517
+
518
+ #: admin/schedule-form.php:100
519
+ msgid "Monday"
520
+ msgstr ""
521
+
522
+ #: admin/schedule-form.php:101
523
+ msgid "Tuesday"
524
+ msgstr ""
525
+
526
+ #: admin/schedule-form.php:102
527
+ msgid "Wednesday"
528
+ msgstr ""
529
+
530
+ #: admin/schedule-form.php:103
531
+ msgid "Thursday"
532
+ msgstr ""
533
+
534
+ #: admin/schedule-form.php:104
535
+ msgid "Friday"
536
+ msgstr ""
537
+
538
+ #: admin/schedule-form.php:105
539
+ msgid "Saturday"
540
+ msgstr ""
541
+
542
+ #: admin/schedule-form.php:106
543
+ msgid "Sunday"
544
+ msgstr ""
545
+
546
+ #: admin/schedule-form.php:124
547
+ msgid "Start Day of Month"
548
+ msgstr ""
549
+
550
+ #: admin/schedule-form.php:136
551
+ msgid "Start Time"
552
+ msgstr ""
553
+
554
+ #: admin/schedule-form.php:145
555
+ msgid "Hours"
556
+ msgstr ""
557
+
558
+ #: admin/schedule-form.php:149
559
+ msgid "Minutes"
560
+ msgstr ""
561
+
562
+ #: admin/schedule-form.php:152
563
+ msgid "Please use 24 hour format for hours"
564
+ msgstr ""
565
+
566
+ #: admin/schedule-form.php:153
567
+ msgid "The second backup will run 12 hours after the first"
568
+ msgstr ""
569
+
570
+ #: admin/schedule-form.php:162
571
+ msgid "Number of backups to store on this server"
572
+ msgstr ""
573
+
574
+ #: admin/schedule-form.php:171
575
+ msgid "Past this limit older backups will be deleted automatically."
576
+ msgstr ""
577
+
578
+ #: admin/schedule-form.php:174
579
+ msgid "This schedule will store a maximum of %s of backups."
580
+ msgstr ""
581
+
582
+ #: admin/schedule-sentence.php:11
583
+ msgid "The next backup will be on %1$s at %2$s %3$s"
584
+ msgstr ""
585
+
586
+ #: admin/schedule-sentence.php:18
587
+ msgid "hourly on the hour"
588
+ msgstr ""
589
+
590
+ #: admin/schedule-sentence.php:18
591
+ msgid "hourly at %s minutes past the hour"
592
+ msgstr ""
593
+
594
+ #: admin/schedule-sentence.php:24
595
+ msgid "daily at %s"
596
+ msgstr ""
597
+
598
+ #: admin/schedule-sentence.php:35
599
+ msgid "every 12 hours at %1$s &amp; %2$s"
600
+ msgstr ""
601
+
602
+ #: admin/schedule-sentence.php:41
603
+ msgid "weekly on %1$s at %2$s"
604
+ msgstr ""
605
+
606
+ #: admin/schedule-sentence.php:47
607
+ msgid "biweekly on %1$s at %2$s"
608
+ msgstr "fortnightly on %1$s at %2$s"
609
+
610
+ #: admin/schedule-sentence.php:53
611
+ msgid "on the %1$s of each month at %2$s"
612
+ msgstr ""
613
+
614
+ #: admin/schedule-sentence.php:59 admin/schedule-sentence.php:65
615
+ msgid "manually"
616
+ msgstr ""
617
+
618
+ #: admin/schedule-sentence.php:70
619
+ msgid "this server"
620
+ msgstr ""
621
+
622
+ #: admin/schedule-sentence.php:78
623
+ msgid "store the most recent backup in %s"
624
+ msgstr ""
625
+
626
+ #: admin/schedule-sentence.php:84
627
+ msgid "don't store any backups in on this server"
628
+ msgstr ""
629
+
630
+ #: admin/schedule-sentence.php:90
631
+ msgid "store the last %1$s backups in %2$s"
632
+ msgstr ""
633
+
634
+ #: admin/schedule-sentence.php:123
635
+ msgid "%s. "
636
+ msgstr ""
637
+
638
+ #: admin/schedule-sentence.php:127
639
+ msgid "Send a copy of each backup to %s."
640
+ msgstr ""
641
+
642
+ #: admin/schedule-sentence.php:158
643
+ msgid "Backups will be compressed and should be smaller than this."
644
+ msgstr ""
645
+
646
+ #: admin/schedule-sentence.php:162
647
+ msgid "this shouldn't take long&hellip;"
648
+ msgstr ""
649
+
650
+ #: admin/schedule-sentence.php:162
651
+ msgid "calculating the size of your backup&hellip;"
652
+ msgstr ""
653
+
654
+ #: admin/schedule-settings.php:7
655
+ msgid "Run now"
656
+ msgstr ""
657
+
658
+ #: admin/schedule-settings.php:15
659
+ msgid "Excludes"
660
+ msgstr ""
661
+
662
+ #: admin/schedule-settings.php:27 functions/interface.php:34
663
+ msgid "Delete"
664
+ msgstr ""
665
+
666
+ #: admin/server-info.php:43
667
+ msgid "%1$s - %2$s"
668
+ msgstr ""
669
+
670
+ #: admin/upsell.php:3
671
+ msgid "Backup to"
672
+ msgstr ""
673
+
674
+ #: admin/upsell.php:18
675
+ msgid ""
676
+ "%1$sor buy the %2$sDeveloper Bundle%3$s now for only &dollar;99 (all "
677
+ "Destinations &amp; Unlimited Sites)%4$s"
678
+ msgstr ""
679
+
680
+ #: backupwordpress.php:53
681
+ msgid ""
682
+ "BackUpWordPress will not work on this site. ( PHP Version %s is unsupported )"
683
+ msgstr ""
684
+
685
+ #: backupwordpress.php:53
686
+ msgid "BackUpWordPress Error"
687
+ msgstr ""
688
+
689
+ #: classes/class-backup.php:388
690
+ msgid "archive filename must be a non empty string"
691
+ msgstr ""
692
+
693
+ #: classes/class-backup.php:392
694
+ msgid "invalid file extension for archive filename <code>%s</code>"
695
+ msgstr ""
696
+
697
+ #: classes/class-backup.php:433
698
+ msgid "database dump filename must be a non empty string"
699
+ msgstr ""
700
+
701
+ #: classes/class-backup.php:437
702
+ msgid "invalid file extension for database dump filename <code>%s</code>"
703
+ msgstr ""
704
+
705
+ #: classes/class-backup.php:471
706
+ msgid "Invalid root path <code>%s</code> must be a valid directory path"
707
+ msgstr ""
708
+
709
+ #: classes/class-backup.php:497
710
+ msgid ""
711
+ "Invalid existing archive filepath <code>%s</code> must be a non empty "
712
+ "(string)"
713
+ msgstr ""
714
+
715
+ #: classes/class-backup.php:552
716
+ msgid ""
717
+ "Invalid backup type <code>%s</code> must be one of (string) file, database "
718
+ "or complete"
719
+ msgstr ""
720
+
721
+ #: classes/class-backup.php:1926
722
+ msgid "Could not connect to mysql"
723
+ msgstr ""
724
+
725
+ #: classes/class-backupwordpress-wp-cli-command.php:50
726
+ msgid "Backup: Dumping database..."
727
+ msgstr ""
728
+
729
+ #: classes/class-backupwordpress-wp-cli-command.php:54
730
+ msgid "Backup: Zipping everything up..."
731
+ msgstr ""
732
+
733
+ #: classes/class-backupwordpress-wp-cli-command.php:70
734
+ msgid "Invalid backup path"
735
+ msgstr ""
736
+
737
+ #: classes/class-backupwordpress-wp-cli-command.php:75
738
+ msgid "Invalid root path"
739
+ msgstr ""
740
+
741
+ #: classes/class-backupwordpress-wp-cli-command.php:106
742
+ msgid "Backup Complete: "
743
+ msgstr ""
744
+
745
+ #: classes/class-backupwordpress-wp-cli-command.php:108
746
+ msgid "Backup Failed"
747
+ msgstr ""
748
+
749
+ #: classes/class-email-service.php:28
750
+ msgid "Email notification"
751
+ msgstr ""
752
+
753
+ #: classes/class-email-service.php:34
754
+ msgid ""
755
+ "Receive a notification email when a backup completes, if the backup is small "
756
+ "enough (&lt; %s) then it will be attached to the email. Separate multiple "
757
+ "email addresses with a comma."
758
+ msgstr ""
759
+
760
+ #: classes/class-email-service.php:63
761
+ msgid ""
762
+ "The maximum filesize of your backup that will be attached to your "
763
+ "notification emails . Defaults to %s."
764
+ msgstr ""
765
+
766
+ #: classes/class-email-service.php:82
767
+ msgid "Send an email notification to %s"
768
+ msgstr ""
769
+
770
+ #: classes/class-email-service.php:117
771
+ msgid "%s isn't a valid email"
772
+ msgstr ""
773
+
774
+ #: classes/class-email-service.php:179 classes/class-webhook-service.php:59
775
+ msgid "Backup of %s Failed"
776
+ msgstr ""
777
+
778
+ #: classes/class-email-service.php:181
779
+ msgid "BackUpWordPress was unable to backup your site %1$s."
780
+ msgstr ""
781
+
782
+ #: classes/class-email-service.php:181
783
+ msgid "Here are the errors that we're encountered:"
784
+ msgstr ""
785
+
786
+ #: classes/class-email-service.php:181
787
+ msgid ""
788
+ "If the errors above look like Martian, forward this email to %3$s and we'll "
789
+ "take a look"
790
+ msgstr ""
791
+
792
+ #: classes/class-email-service.php:181
793
+ msgid ""
794
+ "Kind Regards,\n"
795
+ "The Apologetic BackUpWordPress Backup Emailing Robot"
796
+ msgstr ""
797
+
798
+ #: classes/class-email-service.php:189
799
+ msgid "Backup of %s"
800
+ msgstr ""
801
+
802
+ #: classes/class-email-service.php:194 classes/class-email-service.php:203
803
+ msgid "BackUpWordPress has completed a backup of your site %1$s."
804
+ msgstr ""
805
+
806
+ #: classes/class-email-service.php:194
807
+ msgid "The backup file should be attached to this email."
808
+ msgstr ""
809
+
810
+ #: classes/class-email-service.php:194 classes/class-email-service.php:203
811
+ msgid "You can download the backup file by clicking the link below:"
812
+ msgstr ""
813
+
814
+ #: classes/class-email-service.php:194 classes/class-email-service.php:203
815
+ msgid ""
816
+ "Kind Regards,\n"
817
+ "The Happy BackUpWordPress Backup Emailing Robot"
818
+ msgstr ""
819
+
820
+ #: classes/class-email-service.php:203
821
+ msgid "Unfortunately the backup file was too large to attach to this email."
822
+ msgstr ""
823
+
824
+ #: classes/class-path.php:249
825
+ msgid ""
826
+ "This %s file ensures that other people cannot download your backup files."
827
+ msgstr ""
828
+
829
+ #: classes/class-plugin.php:214
830
+ msgid "Update"
831
+ msgstr ""
832
+
833
+ #: classes/class-plugin.php:215
834
+ msgid "Cancel"
835
+ msgstr ""
836
+
837
+ #: classes/class-plugin.php:216
838
+ msgid ""
839
+ "Are you sure you want to delete this schedule? All of it's backups will also "
840
+ "be deleted."
841
+ msgstr ""
842
+
843
+ #: classes/class-plugin.php:216 classes/class-plugin.php:217
844
+ #: classes/class-plugin.php:218 classes/class-plugin.php:219
845
+ msgid "'Cancel' to go back, 'OK' to delete."
846
+ msgstr ""
847
+
848
+ #: classes/class-plugin.php:217
849
+ msgid "Are you sure you want to delete this backup?"
850
+ msgstr ""
851
+
852
+ #: classes/class-plugin.php:218
853
+ msgid "Are you sure you want to remove this exclude rule?"
854
+ msgstr ""
855
+
856
+ #: classes/class-plugin.php:219
857
+ msgid ""
858
+ "Reducing the number of backups that are stored on this server will cause "
859
+ "some of your existing backups to be deleted, are you sure that's what you "
860
+ "want?"
861
+ msgstr ""
862
+
863
+ #: classes/class-schedule.php:151
864
+ msgid "Invalid Option Name"
865
+ msgstr ""
866
+
867
+ #: classes/class-schedule.php:264
868
+ msgid "Argument 1 for %s must be a valid integer"
869
+ msgstr ""
870
+
871
+ #: classes/class-schedule.php:612
872
+ msgid "Argument 1 for %s must be a valid future timestamp"
873
+ msgstr ""
874
+
875
+ #: classes/class-schedule.php:649
876
+ msgid "Argument 1 for %s must be a valid cron reoccurrence or \"manually\""
877
+ msgstr ""
878
+
879
+ #: classes/class-schedule.php:778 functions/interface.php:267
880
+ msgid "Starting Backup"
881
+ msgstr ""
882
+
883
+ #: classes/class-schedule.php:865
884
+ msgid "Error writing to file. (%s)"
885
+ msgstr ""
886
+
887
+ #: classes/class-schedule.php:916
888
+ msgid "Dumping Database %s"
889
+ msgstr ""
890
+
891
+ #: classes/class-schedule.php:921
892
+ msgid "Verifying Database Dump %s"
893
+ msgstr ""
894
+
895
+ #: classes/class-schedule.php:926
896
+ msgid "Creating zip archive %s"
897
+ msgstr ""
898
+
899
+ #: classes/class-schedule.php:931
900
+ msgid "Verifying Zip Archive %s"
901
+ msgstr ""
902
+
903
+ #: classes/class-schedule.php:936
904
+ msgid "Finishing Backup"
905
+ msgstr ""
906
+
907
+ #: classes/class-schedule.php:987
908
+ msgid "An unexpected error occured"
909
+ msgstr ""
910
+
911
+ #. translators: min=minute
912
+ #: classes/class-schedule.php:1050
913
+ msgid "%s min"
914
+ msgid_plural "%s mins"
915
+ msgstr[0] ""
916
+ msgstr[1] ""
917
+
918
+ #: classes/class-schedule.php:1060
919
+ msgid "%s hour"
920
+ msgid_plural "%s hours"
921
+ msgstr[0] ""
922
+ msgstr[1] ""
923
+
924
+ #: classes/class-schedule.php:1122
925
+ msgid "Argument 1 for %s must be a non empty string"
926
+ msgstr ""
927
+
928
+ #: classes/class-schedule.php:1127
929
+ msgid "%s doesn't exist"
930
+ msgstr ""
931
+
932
+ #: classes/class-schedule.php:1132
933
+ msgid "That backup wasn't created by this schedule"
934
+ msgstr ""
935
+
936
+ #: classes/class-services.php:80
937
+ msgid "Argument 1 for %s must be a valid filepath"
938
+ msgstr ""
939
+
940
+ #: classes/class-services.php:96
941
+ msgid "Argument 1 for %s must be a registered service"
942
+ msgstr ""
943
+
944
+ #: classes/class-services.php:114 classes/deprecated.php:81
945
+ msgid "Argument 1 for %s must be a valid class"
946
+ msgstr ""
947
+
948
+ #: classes/class-setup.php:34
949
+ msgid "BackUpWordPress"
950
+ msgstr ""
951
+
952
+ #: classes/class-setup.php:170
953
+ msgid ""
954
+ "BackUpWordPress requires PHP version %1$s or later and WordPress version "
955
+ "%2$s or later to run. It has not been activated. %3$s%4$s%5$sLearn more%6$s"
956
+ msgstr ""
957
+
958
+ #: classes/class-webhook-service.php:103
959
+ msgid "Error: %s"
960
+ msgstr ""
961
+
962
+ #: functions/core.php:326
963
+ msgid "BackUpWordPress has setup your default schedules."
964
+ msgstr ""
965
+
966
+ #: functions/core.php:326
967
+ msgid ""
968
+ "By default BackUpWordPress performs a daily backup of your database and a "
969
+ "weekly backup of your database &amp; files. You can modify these schedules."
970
+ msgstr ""
971
+
972
+ #: functions/core.php:341
973
+ msgid "Once Hourly"
974
+ msgstr ""
975
+
976
+ #: functions/core.php:342
977
+ msgid "Twice Daily"
978
+ msgstr ""
979
+
980
+ #: functions/core.php:343
981
+ msgid "Once Daily"
982
+ msgstr ""
983
+
984
+ #: functions/core.php:344
985
+ msgid "Once Weekly"
986
+ msgstr ""
987
+
988
+ #: functions/core.php:345
989
+ msgid "Once Biweekly"
990
+ msgstr "Once Fortnightly"
991
+
992
+ #: functions/core.php:346
993
+ msgid "Once Monthly"
994
+ msgstr ""
995
+
996
+ #: functions/core.php:364
997
+ msgid "You can only delete directories inside your WordPress installation"
998
+ msgstr ""
999
+
1000
+ #: functions/interface.php:31
1001
+ msgid "Download"
1002
+ msgstr ""
1003
+
1004
+ #: functions/interface.php:68
1005
+ msgid "BackUpWordPress detected issues with your last backup."
1006
+ msgstr ""
1007
+
1008
+ #: functions/interface.php:70
1009
+ msgid "Dismiss"
1010
+ msgstr ""
1011
+
1012
+ #: functions/interface.php:136
1013
+ msgid ""
1014
+ "The backups directory can't be created because your %1$s directory isn't "
1015
+ "writable, run %2$s or %3$s or create the folder yourself."
1016
+ msgstr ""
1017
+
1018
+ #: functions/interface.php:140
1019
+ msgid ""
1020
+ "Your backups directory isn't writable, run %1$s or %2$s or set the "
1021
+ "permissions yourself."
1022
+ msgstr ""
1023
+
1024
+ #: functions/interface.php:144
1025
+ msgid ""
1026
+ "%1$s is running in %2$s, please contact your host and ask them to disable "
1027
+ "it. BackUpWordPress may not work correctly whilst %3$s is on."
1028
+ msgstr ""
1029
+
1030
+ #: functions/interface.php:144
1031
+ msgid "http://php.net/manual/en/features.safe-mode.php"
1032
+ msgstr ""
1033
+
1034
+ #: functions/interface.php:144
1035
+ msgid "Safe Mode"
1036
+ msgstr ""
1037
+
1038
+ #: functions/interface.php:152
1039
+ msgid "Your custom path does not exist"
1040
+ msgstr ""
1041
+
1042
+ #: functions/interface.php:156
1043
+ msgid ""
1044
+ "Your custom path is unreachable due to a restriction set in your PHP "
1045
+ "configuration (open_basedir)"
1046
+ msgstr ""
1047
+
1048
+ #: functions/interface.php:161
1049
+ msgid ""
1050
+ "Your custom backups directory %1$s doesn't exist and can't be created, your "
1051
+ "backups will be saved to %2$s instead."
1052
+ msgstr ""
1053
+
1054
+ #: functions/interface.php:165
1055
+ msgid ""
1056
+ "Your custom backups directory %1$s isn't writable, new backups will be saved "
1057
+ "to %2$s instead."
1058
+ msgstr ""
1059
+
1060
+ #: functions/interface.php:174
1061
+ msgid "Your site root path %s isn't readable."
1062
+ msgstr ""
1063
+
1064
+ #: functions/interface.php:236
1065
+ msgid "Database and Files"
1066
+ msgstr ""
1067
+
1068
+ #: functions/interface.php:240
1069
+ msgid "Files"
1070
+ msgstr ""
1071
+
1072
+ #: functions/interface.php:244
1073
+ msgid "Database"
1074
+ msgstr ""
1075
+
1076
+ #: functions/interface.php:251
1077
+ msgid "Legacy"
1078
+ msgstr ""
1079
+
1080
+ #: functions/interface.php:266
1081
+ msgid "Started %s ago"
1082
+ msgstr ""
1083
+
1084
+ #: functions/interface.php:268
1085
+ msgid "cancel"
1086
+ msgstr ""
1087
+
1088
+ #: functions/interface.php:316
1089
+ msgid "No backups completed"
1090
+ msgstr ""
1091
+
1092
+ #: functions/interface.php:327
1093
+ msgid "Complete Hourly"
1094
+ msgstr ""
1095
+
1096
+ #: functions/interface.php:328
1097
+ msgid "File Hourly"
1098
+ msgstr ""
1099
+
1100
+ #: functions/interface.php:329
1101
+ msgid "Database Hourly"
1102
+ msgstr ""
1103
+
1104
+ #: functions/interface.php:330
1105
+ msgid "Complete Twicedaily"
1106
+ msgstr ""
1107
+
1108
+ #: functions/interface.php:331
1109
+ msgid "File Twicedaily"
1110
+ msgstr ""
1111
+
1112
+ #: functions/interface.php:332
1113
+ msgid "Database Twicedaily"
1114
+ msgstr ""
1115
+
1116
+ #: functions/interface.php:333
1117
+ msgid "Complete Daily"
1118
+ msgstr ""
1119
+
1120
+ #: functions/interface.php:334
1121
+ msgid "File Daily"
1122
+ msgstr ""
1123
+
1124
+ #: functions/interface.php:335
1125
+ msgid "Database Daily"
1126
+ msgstr ""
1127
+
1128
+ #: functions/interface.php:336
1129
+ msgid "Complete Weekly"
1130
+ msgstr ""
1131
+
1132
+ #: functions/interface.php:337
1133
+ msgid "File Weekly"
1134
+ msgstr ""
1135
+
1136
+ #: functions/interface.php:338
1137
+ msgid "Database Weekly"
1138
+ msgstr ""
1139
+
1140
+ #: functions/interface.php:339
1141
+ msgid "Complete Biweekly"
1142
+ msgstr "Complete Fortnightly"
1143
+
1144
+ #: functions/interface.php:340
1145
+ msgid "File Biweekly"
1146
+ msgstr "File Fortnightly"
1147
+
1148
+ #: functions/interface.php:341
1149
+ msgid "Database Biweekly"
1150
+ msgstr "Database Fortnightly"
1151
+
1152
+ #: functions/interface.php:342
1153
+ msgid "Complete Monthly"
1154
+ msgstr ""
1155
+
1156
+ #: functions/interface.php:343
1157
+ msgid "File Monthly"
1158
+ msgstr ""
1159
+
1160
+ #: functions/interface.php:344
1161
+ msgid "Database Monthly"
1162
+ msgstr ""
1163
+
1164
+ #: functions/interface.php:345
1165
+ msgid "Complete Manually"
1166
+ msgstr ""
1167
+
1168
+ #: functions/interface.php:346
1169
+ msgid "File Manually"
1170
+ msgstr ""
1171
+
1172
+ #: functions/interface.php:347
1173
+ msgid "Database Manually"
1174
+ msgstr ""
1175
+
1176
+ #. Plugin Name of the plugin/theme
1177
+ msgid "BackUpWordPress Backup Plugin"
1178
+ msgstr ""
1179
+
1180
+ #. Plugin URI of the plugin/theme
1181
+ msgid "http://bwp.hmn.md/"
1182
+ msgstr ""
1183
+
1184
+ #. Description of the plugin/theme
1185
+ msgid ""
1186
+ "Simple automated backups of your WordPress powered website. Once activated "
1187
+ "you'll find me under <strong>Tools &rarr; Backups</strong>. On multisite, "
1188
+ "you'll find me under the Network Settings menu."
1189
+ msgstr ""
1190
+
1191
+ #. Author of the plugin/theme
1192
+ msgid "Human Made Limited"
1193
+ msgstr ""
1194
+
1195
+ #. Author URI of the plugin/theme
1196
+ msgid "http://hmn.md/"
1197
+ msgstr ""
1198
+
1199
+ #: admin/schedule-sentence.php:120
1200
+ msgctxt ""
1201
+ "1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to "
1202
+ "store"
1203
+ msgid "Backup my %1$s %2$s %3$s, %4$s."
1204
+ msgstr ""
1205
+
1206
+ #: functions/interface.php:318
1207
+ msgctxt "backups count"
1208
+ msgid "One backup completed"
1209
+ msgid_plural "%1$s backups completed"
1210
+ msgstr[0] ""
1211
+ msgstr[1] ""
languages/backupwordpress-en_GB.mo ADDED
Binary file
languages/backupwordpress-en_GB.po ADDED
@@ -0,0 +1,1211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2015 Human Made Limited
2
+ # This file is distributed under the GPL-2.0+.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: BackUpWordPress Backup Plugin 3.2.6\n"
6
+ "POT-Creation-Date: 2015-07-13 12:44+0930\n"
7
+ "MIME-Version: 1.0\n"
8
+ "Content-Type: text/plain; charset=UTF-8\n"
9
+ "Content-Transfer-Encoding: 8bit\n"
10
+ "PO-Revision-Date: 2015-07-13 13:39+0930\n"
11
+ "Last-Translator: ucavus\n"
12
+ "Language-Team: ucavus\n"
13
+ "X-Generator: Poedit 1.8.2\n"
14
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
+ "Language: en_GB\n"
16
+
17
+ #: admin/actions.php:191
18
+ msgid "The schedule ID was not provided. Aborting."
19
+ msgstr ""
20
+
21
+ #: admin/actions.php:241
22
+ msgid "Backup type cannot be empty"
23
+ msgstr ""
24
+
25
+ #: admin/actions.php:245
26
+ msgid "Invalid backup type"
27
+ msgstr ""
28
+
29
+ #: admin/actions.php:259
30
+ msgid "Schedule cannot be empty"
31
+ msgstr ""
32
+
33
+ #: admin/actions.php:263
34
+ msgid "Invalid schedule"
35
+ msgstr ""
36
+
37
+ #: admin/actions.php:277
38
+ msgid "Day of the week must be a valid lowercase day name"
39
+ msgstr ""
40
+
41
+ #: admin/actions.php:296
42
+ msgid "Day of month must be between 1 and 31"
43
+ msgstr ""
44
+
45
+ #: admin/actions.php:315
46
+ msgid "Hours must be between 0 and 23"
47
+ msgstr ""
48
+
49
+ #: admin/actions.php:334
50
+ msgid "Minutes must be between 0 and 59"
51
+ msgstr ""
52
+
53
+ #: admin/actions.php:348
54
+ msgid "Max backups can't be empty"
55
+ msgstr ""
56
+
57
+ #: admin/actions.php:352
58
+ msgid "Max backups must be a number"
59
+ msgstr ""
60
+
61
+ #: admin/actions.php:356
62
+ msgid "Max backups must be greater than 0"
63
+ msgstr ""
64
+
65
+ #: admin/actions.php:708 admin/actions.php:714
66
+ msgid "BackUpWordPress has detected a problem."
67
+ msgstr ""
68
+
69
+ #: admin/actions.php:708 admin/actions.php:714
70
+ msgid ""
71
+ "%1$s is returning a %2$s response which could mean cron jobs aren't getting "
72
+ "fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. "
73
+ "See the %3$s for more details."
74
+ msgstr ""
75
+
76
+ #: admin/backups-table.php:8 admin/schedule-form-excludes.php:105
77
+ msgid "Size"
78
+ msgstr ""
79
+
80
+ #: admin/backups-table.php:9 admin/schedule-form-excludes.php:107
81
+ msgid "Type"
82
+ msgstr ""
83
+
84
+ #: admin/backups-table.php:10
85
+ msgid "Actions"
86
+ msgstr ""
87
+
88
+ #: admin/backups-table.php:35
89
+ msgid "This is where your backups will appear once you have some."
90
+ msgstr ""
91
+
92
+ #: admin/backups.php:22
93
+ msgid "add schedule"
94
+ msgstr ""
95
+
96
+ #: admin/backups.php:26
97
+ msgid "Support"
98
+ msgstr ""
99
+
100
+ #: admin/backups.php:32
101
+ msgid "Enable Support"
102
+ msgstr ""
103
+
104
+ #: admin/constants.php:3
105
+ msgid ""
106
+ "You can %1$s any of the following %2$s in your %3$s to control advanced "
107
+ "settings. %4$s. Defined %5$s will be highlighted."
108
+ msgstr ""
109
+
110
+ #: admin/constants.php:3 admin/menu.php:82
111
+ msgid "Constants"
112
+ msgstr ""
113
+
114
+ #: admin/constants.php:3
115
+ msgid "The Codex can help"
116
+ msgstr ""
117
+
118
+ #: admin/constants.php:14 admin/constants.php:30 admin/constants.php:46
119
+ #: admin/constants.php:62 admin/constants.php:78 admin/constants.php:94
120
+ #: admin/constants.php:110 classes/class-email-service.php:60
121
+ msgid "You've set it to: %s"
122
+ msgstr ""
123
+
124
+ #: admin/constants.php:17
125
+ msgid ""
126
+ "The path to folder you would like to store your backup files in, defaults to "
127
+ "%s."
128
+ msgstr ""
129
+
130
+ #: admin/constants.php:17 admin/constants.php:33 admin/constants.php:49
131
+ #: admin/constants.php:65 admin/constants.php:81 admin/constants.php:97
132
+ #: admin/constants.php:113 classes/class-email-service.php:63
133
+ msgid "e.g."
134
+ msgstr ""
135
+
136
+ #: admin/constants.php:33
137
+ msgid ""
138
+ "The path to your %1$s executable. Will be used for the %2$s part of the back "
139
+ "up if available."
140
+ msgstr ""
141
+
142
+ #: admin/constants.php:33 admin/constants.php:49
143
+ msgid "database"
144
+ msgstr ""
145
+
146
+ #: admin/constants.php:49
147
+ msgid ""
148
+ "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
149
+ "if available."
150
+ msgstr ""
151
+
152
+ #: admin/constants.php:49
153
+ msgid "files"
154
+ msgstr ""
155
+
156
+ #: admin/constants.php:65
157
+ msgid ""
158
+ "Comma separated list of files or directories to exclude, the backups "
159
+ "directory is automatically excluded."
160
+ msgstr ""
161
+
162
+ #: admin/constants.php:81
163
+ msgid "The capability to use when calling %1$s. Defaults to %2$s."
164
+ msgstr ""
165
+
166
+ #: admin/constants.php:97
167
+ msgid "The root directory that is backed up. Defaults to %s."
168
+ msgstr ""
169
+
170
+ #: admin/constants.php:113
171
+ msgid "The time that your schedules should run. Defaults to %s."
172
+ msgstr ""
173
+
174
+ #: admin/enable-support.php:3
175
+ msgid "Enable BackUpWordPress Support"
176
+ msgstr ""
177
+
178
+ #: admin/enable-support.php:5
179
+ msgid ""
180
+ "BackUpWordPress uses %s to provide support. In addition to allowing you to "
181
+ "send and receive messages we also send the following server information "
182
+ "along with your requests:"
183
+ msgstr ""
184
+
185
+ #: admin/enable-support.php:58
186
+ msgid "You can disable support in the future by deactivating BackUpWordPress."
187
+ msgstr ""
188
+
189
+ #: admin/enable-support.php:60
190
+ msgid "No thanks"
191
+ msgstr ""
192
+
193
+ #: admin/enable-support.php:61
194
+ msgid "Yes I want to enable support"
195
+ msgstr ""
196
+
197
+ #: admin/faq.php:2
198
+ msgid "Where does BackUpWordPress store the backup files?"
199
+ msgstr ""
200
+
201
+ #: admin/faq.php:4
202
+ msgid ""
203
+ "Backups are stored on your server in <code>/wp-content/backups</code>, you "
204
+ "can change the directory."
205
+ msgstr ""
206
+
207
+ #: admin/faq.php:6
208
+ msgid ""
209
+ "Important: By default BackUpWordPress backs up everything in your site root "
210
+ "as well as your database, this includes any non WordPress folders that "
211
+ "happen to be in your site root. This does mean that your backup directory "
212
+ "can get quite large."
213
+ msgstr ""
214
+
215
+ #: admin/faq.php:8
216
+ msgid "What if I want to back up my site to another destination?"
217
+ msgstr ""
218
+
219
+ #: admin/faq.php:10
220
+ msgid ""
221
+ "BackUpWordPress Pro supports Dropbox, Google Drive, Amazon S3, Rackspace, "
222
+ "Azure, DreamObjects and FTP/SFTP. Check it out here: <a href=\"http://bwp."
223
+ "hmn.md/?utm_source=wordpress-org&utm_medium=plugin-"
224
+ "page&utm_campaign=freeplugin\" title=\"BackUpWordPress Homepage\" target="
225
+ "\"_blank\">https://bwp.hmn.md</a>"
226
+ msgstr ""
227
+
228
+ #: admin/faq.php:12
229
+ msgid "How do I restore my site from a backup?"
230
+ msgstr ""
231
+
232
+ #: admin/faq.php:14
233
+ msgid ""
234
+ "You need to download the latest backup file either by clicking download on "
235
+ "the backups page or via <code>FTP</code>. <code>Unzip</code> the files and "
236
+ "upload all the files to your server overwriting your site. You can then "
237
+ "import the database using your hosts database management tool (likely "
238
+ "<code>phpMyAdmin</code>)."
239
+ msgstr ""
240
+
241
+ #: admin/faq.php:16
242
+ msgid ""
243
+ "See this guide for more details - <a href=\"https://bwp.hmn.md/support-"
244
+ "center/restore-backup/\" title=\"Go to support center\" target=\"_blank"
245
+ "\">How to restore from backup</a>."
246
+ msgstr ""
247
+
248
+ #: admin/faq.php:18
249
+ msgid "Does BackUpWordPress back up the backups directory?"
250
+ msgstr ""
251
+
252
+ #: admin/faq.php:20
253
+ msgid "No."
254
+ msgstr ""
255
+
256
+ #: admin/faq.php:22
257
+ msgid "I'm not receiving my backups by email?"
258
+ msgstr ""
259
+
260
+ #: admin/faq.php:24
261
+ msgid ""
262
+ "Most servers have a filesize limit on email attachments, it's generally "
263
+ "about 10mb. If your backup file is over that limit it won't be sent attached "
264
+ "to the email, instead you should receive an email with a link to download "
265
+ "the backup, if you aren't even receiving that then you likely have a mail "
266
+ "issue on your server that you'll need to contact your host about."
267
+ msgstr ""
268
+
269
+ #: admin/faq.php:26
270
+ msgid "How many backups are stored by default?"
271
+ msgstr ""
272
+
273
+ #: admin/faq.php:28
274
+ msgid "BackUpWordPress stores the last 10 backups by default."
275
+ msgstr ""
276
+
277
+ #: admin/faq.php:30
278
+ msgid "How long should a backup take?"
279
+ msgstr ""
280
+
281
+ #: admin/faq.php:32
282
+ msgid ""
283
+ "Unless your site is very large (many gigabytes) it should only take a few "
284
+ "minutes to perform a back up, if your back up has been running for longer "
285
+ "than an hour it's safe to assume that something has gone wrong, try de-"
286
+ "activating and re-activating the plugin, if it keeps happening, contact "
287
+ "support."
288
+ msgstr ""
289
+
290
+ #: admin/faq.php:34
291
+ msgid "What do I do if I get the wp-cron error message?"
292
+ msgstr ""
293
+
294
+ #: admin/faq.php:36
295
+ msgid ""
296
+ "The issue is that your <code>wp-cron.php</code> is not returning a "
297
+ "<code>200</code> response when hit with a HTTP request originating from your "
298
+ "own server, it could be several things, in most cases, it's an issue with "
299
+ "the server / site."
300
+ msgstr ""
301
+
302
+ #: admin/faq.php:38
303
+ msgid "There are some things you can test to confirm this is the issue."
304
+ msgstr ""
305
+
306
+ #: admin/faq.php:40
307
+ msgid "Are scheduled posts working? (They use wp-cron as well ). "
308
+ msgstr ""
309
+
310
+ #: admin/faq.php:42
311
+ msgid ""
312
+ "Are you hosted on Heart Internet? (wp-cron may not be supported by Heart "
313
+ "Internet, see below for work-around)."
314
+ msgstr ""
315
+
316
+ #: admin/faq.php:44
317
+ msgid "If you click manual backup does it work?"
318
+ msgstr ""
319
+
320
+ #: admin/faq.php:46
321
+ msgid ""
322
+ "Try adding <code>define( 'ALTERNATE_WP_CRON', true );</code> to your "
323
+ "<code>wp-config.php</code>, do automatic backups work?"
324
+ msgstr ""
325
+
326
+ #: admin/faq.php:48
327
+ msgid ""
328
+ "Is your site private (I.E. is it behind some kind of authentication, "
329
+ "maintenance plugin, .htaccess) if so wp-cron won't work until you remove it, "
330
+ "if you are and you temporarily remove the authentication, do backups start "
331
+ "working?"
332
+ msgstr ""
333
+
334
+ #: admin/faq.php:50
335
+ msgid ""
336
+ "Report the results to our support team for further help. To do this, either "
337
+ "enable suport from your Admin Dashboard (recommended), or email support@hmn."
338
+ "md"
339
+ msgstr ""
340
+
341
+ #: admin/faq.php:52
342
+ msgid "How to get BackUpWordPress working in Heart Internet"
343
+ msgstr ""
344
+
345
+ #: admin/faq.php:54
346
+ msgid ""
347
+ "The script to be entered into the Heart Internet cPanel is: <code>/usr/bin/"
348
+ "php5 /home/sites/yourdomain.com/public_html/wp-cron.php</code> (note the "
349
+ "space between php5 and the location of the file). The file <code>wp-cron."
350
+ "php</code> <code>chmod</code> must be set to <code>711</code>."
351
+ msgstr ""
352
+
353
+ #: admin/faq.php:56
354
+ msgid "My backups seem to be failing?"
355
+ msgstr ""
356
+
357
+ #: admin/faq.php:58
358
+ msgid ""
359
+ "If your backups are failing - it's commonly caused by lack of available "
360
+ "resources on your server. The easiest way to establish this to exclude some "
361
+ "[of] or your entire uploades folder, running a backup an if that succeeds. "
362
+ "If so, we know it's probably a server issue. If not, report the results to "
363
+ "our support team for further help. To do this, either enable suport from "
364
+ "your Admin Dashboard (recommended), or email support@hmn.md"
365
+ msgstr ""
366
+
367
+ #: admin/menu.php:13 admin/menu.php:17
368
+ msgid "Manage Backups"
369
+ msgstr ""
370
+
371
+ #: admin/menu.php:13 admin/menu.php:17 admin/menu.php:46
372
+ msgid "Backups"
373
+ msgstr ""
374
+
375
+ #: admin/menu.php:77
376
+ msgid "FAQ"
377
+ msgstr ""
378
+
379
+ #: admin/menu.php:95
380
+ msgid "Server Info"
381
+ msgstr ""
382
+
383
+ #: admin/menu.php:102
384
+ msgid "For more information:"
385
+ msgstr ""
386
+
387
+ #: admin/menu.php:104
388
+ msgid "Support Forums"
389
+ msgstr ""
390
+
391
+ #: admin/menu.php:105
392
+ msgid "Help with translation"
393
+ msgstr ""
394
+
395
+ #: admin/page.php:7
396
+ msgid ""
397
+ "If you're finding BackUpWordPress useful, please %1$s rate it on the plugin "
398
+ "directory%2$s."
399
+ msgstr ""
400
+
401
+ #: admin/schedule-form-excludes.php:6
402
+ msgid "Currently Excluded"
403
+ msgstr ""
404
+
405
+ #: admin/schedule-form-excludes.php:9
406
+ msgid ""
407
+ "We automatically detect and ignore common <abbr title=\"Version Control "
408
+ "Systems\">VCS</abbr> folders and other backup plugin folders."
409
+ msgstr ""
410
+
411
+ #: admin/schedule-form-excludes.php:44
412
+ msgid "Default rule"
413
+ msgstr ""
414
+
415
+ #: admin/schedule-form-excludes.php:48
416
+ msgid "Defined in wp-config.php"
417
+ msgstr ""
418
+
419
+ #: admin/schedule-form-excludes.php:55
420
+ msgid "Stop excluding"
421
+ msgstr ""
422
+
423
+ #: admin/schedule-form-excludes.php:71
424
+ msgid "Directory Listing"
425
+ msgstr ""
426
+
427
+ #: admin/schedule-form-excludes.php:73
428
+ msgid ""
429
+ "Here's a directory listing of all files on your site, you can browse through "
430
+ "and exclude files or folders that you don't want included in your backup."
431
+ msgstr ""
432
+
433
+ #: admin/schedule-form-excludes.php:104
434
+ msgid "Name"
435
+ msgstr ""
436
+
437
+ #: admin/schedule-form-excludes.php:106
438
+ msgid "Permissions"
439
+ msgstr ""
440
+
441
+ #: admin/schedule-form-excludes.php:108
442
+ msgid "Status"
443
+ msgstr ""
444
+
445
+ #: admin/schedule-form-excludes.php:168 admin/schedule-form-excludes.php:284
446
+ msgid "Refresh"
447
+ msgstr ""
448
+
449
+ #: admin/schedule-form-excludes.php:185 admin/schedule-form-excludes.php:308
450
+ msgid "Symlink"
451
+ msgstr ""
452
+
453
+ #: admin/schedule-form-excludes.php:189 admin/schedule-form-excludes.php:312
454
+ msgid "Folder"
455
+ msgstr ""
456
+
457
+ #: admin/schedule-form-excludes.php:282
458
+ msgid "Recalculate the size of this directory"
459
+ msgstr ""
460
+
461
+ #: admin/schedule-form-excludes.php:316
462
+ msgid "File"
463
+ msgstr ""
464
+
465
+ #: admin/schedule-form-excludes.php:327
466
+ msgid "Unreadable files won't be backed up."
467
+ msgstr ""
468
+
469
+ #: admin/schedule-form-excludes.php:327
470
+ msgid "Unreadable"
471
+ msgstr ""
472
+
473
+ #: admin/schedule-form-excludes.php:331
474
+ msgid "Excluded"
475
+ msgstr ""
476
+
477
+ #: admin/schedule-form-excludes.php:347
478
+ msgid "Exclude &rarr;"
479
+ msgstr ""
480
+
481
+ #: admin/schedule-form-excludes.php:365 admin/schedule-form.php:192
482
+ #: admin/schedule-settings.php:88
483
+ msgid "Done"
484
+ msgstr ""
485
+
486
+ #: admin/schedule-form.php:1 admin/schedule-settings.php:9
487
+ msgid "Settings"
488
+ msgstr ""
489
+
490
+ #: admin/schedule-form.php:36
491
+ msgid "Backup"
492
+ msgstr ""
493
+
494
+ #: admin/schedule-form.php:43
495
+ msgid "Both Database &amp; files"
496
+ msgstr ""
497
+
498
+ #: admin/schedule-form.php:45
499
+ msgid "Files only"
500
+ msgstr ""
501
+
502
+ #: admin/schedule-form.php:47
503
+ msgid "Database only"
504
+ msgstr ""
505
+
506
+ #: admin/schedule-form.php:58
507
+ msgid "Schedule"
508
+ msgstr ""
509
+
510
+ #: admin/schedule-form.php:65
511
+ msgid "Manual Only"
512
+ msgstr ""
513
+
514
+ #: admin/schedule-form.php:92
515
+ msgid "Start Day"
516
+ msgstr ""
517
+
518
+ #: admin/schedule-form.php:100
519
+ msgid "Monday"
520
+ msgstr ""
521
+
522
+ #: admin/schedule-form.php:101
523
+ msgid "Tuesday"
524
+ msgstr ""
525
+
526
+ #: admin/schedule-form.php:102
527
+ msgid "Wednesday"
528
+ msgstr ""
529
+
530
+ #: admin/schedule-form.php:103
531
+ msgid "Thursday"
532
+ msgstr ""
533
+
534
+ #: admin/schedule-form.php:104
535
+ msgid "Friday"
536
+ msgstr ""
537
+
538
+ #: admin/schedule-form.php:105
539
+ msgid "Saturday"
540
+ msgstr ""
541
+
542
+ #: admin/schedule-form.php:106
543
+ msgid "Sunday"
544
+ msgstr ""
545
+
546
+ #: admin/schedule-form.php:124
547
+ msgid "Start Day of Month"
548
+ msgstr ""
549
+
550
+ #: admin/schedule-form.php:136
551
+ msgid "Start Time"
552
+ msgstr ""
553
+
554
+ #: admin/schedule-form.php:145
555
+ msgid "Hours"
556
+ msgstr ""
557
+
558
+ #: admin/schedule-form.php:149
559
+ msgid "Minutes"
560
+ msgstr ""
561
+
562
+ #: admin/schedule-form.php:152
563
+ msgid "Please use 24 hour format for hours"
564
+ msgstr ""
565
+
566
+ #: admin/schedule-form.php:153
567
+ msgid "The second backup will run 12 hours after the first"
568
+ msgstr ""
569
+
570
+ #: admin/schedule-form.php:162
571
+ msgid "Number of backups to store on this server"
572
+ msgstr ""
573
+
574
+ #: admin/schedule-form.php:171
575
+ msgid "Past this limit older backups will be deleted automatically."
576
+ msgstr ""
577
+
578
+ #: admin/schedule-form.php:174
579
+ msgid "This schedule will store a maximum of %s of backups."
580
+ msgstr ""
581
+
582
+ #: admin/schedule-sentence.php:11
583
+ msgid "The next backup will be on %1$s at %2$s %3$s"
584
+ msgstr ""
585
+
586
+ #: admin/schedule-sentence.php:18
587
+ msgid "hourly on the hour"
588
+ msgstr ""
589
+
590
+ #: admin/schedule-sentence.php:18
591
+ msgid "hourly at %s minutes past the hour"
592
+ msgstr ""
593
+
594
+ #: admin/schedule-sentence.php:24
595
+ msgid "daily at %s"
596
+ msgstr ""
597
+
598
+ #: admin/schedule-sentence.php:35
599
+ msgid "every 12 hours at %1$s &amp; %2$s"
600
+ msgstr ""
601
+
602
+ #: admin/schedule-sentence.php:41
603
+ msgid "weekly on %1$s at %2$s"
604
+ msgstr ""
605
+
606
+ #: admin/schedule-sentence.php:47
607
+ msgid "biweekly on %1$s at %2$s"
608
+ msgstr "fortnightly on %1$s at %2$s"
609
+
610
+ #: admin/schedule-sentence.php:53
611
+ msgid "on the %1$s of each month at %2$s"
612
+ msgstr ""
613
+
614
+ #: admin/schedule-sentence.php:59 admin/schedule-sentence.php:65
615
+ msgid "manually"
616
+ msgstr ""
617
+
618
+ #: admin/schedule-sentence.php:70
619
+ msgid "this server"
620
+ msgstr ""
621
+
622
+ #: admin/schedule-sentence.php:78
623
+ msgid "store the most recent backup in %s"
624
+ msgstr ""
625
+
626
+ #: admin/schedule-sentence.php:84
627
+ msgid "don't store any backups in on this server"
628
+ msgstr ""
629
+
630
+ #: admin/schedule-sentence.php:90
631
+ msgid "store the last %1$s backups in %2$s"
632
+ msgstr ""
633
+
634
+ #: admin/schedule-sentence.php:123
635
+ msgid "%s. "
636
+ msgstr ""
637
+
638
+ #: admin/schedule-sentence.php:127
639
+ msgid "Send a copy of each backup to %s."
640
+ msgstr ""
641
+
642
+ #: admin/schedule-sentence.php:158
643
+ msgid "Backups will be compressed and should be smaller than this."
644
+ msgstr ""
645
+
646
+ #: admin/schedule-sentence.php:162
647
+ msgid "this shouldn't take long&hellip;"
648
+ msgstr ""
649
+
650
+ #: admin/schedule-sentence.php:162
651
+ msgid "calculating the size of your backup&hellip;"
652
+ msgstr ""
653
+
654
+ #: admin/schedule-settings.php:7
655
+ msgid "Run now"
656
+ msgstr ""
657
+
658
+ #: admin/schedule-settings.php:15
659
+ msgid "Excludes"
660
+ msgstr ""
661
+
662
+ #: admin/schedule-settings.php:27 functions/interface.php:34
663
+ msgid "Delete"
664
+ msgstr ""
665
+
666
+ #: admin/server-info.php:43
667
+ msgid "%1$s - %2$s"
668
+ msgstr ""
669
+
670
+ #: admin/upsell.php:3
671
+ msgid "Backup to"
672
+ msgstr ""
673
+
674
+ #: admin/upsell.php:18
675
+ msgid ""
676
+ "%1$sor buy the %2$sDeveloper Bundle%3$s now for only &dollar;99 (all "
677
+ "Destinations &amp; Unlimited Sites)%4$s"
678
+ msgstr ""
679
+
680
+ #: backupwordpress.php:53
681
+ msgid ""
682
+ "BackUpWordPress will not work on this site. ( PHP Version %s is unsupported )"
683
+ msgstr ""
684
+
685
+ #: backupwordpress.php:53
686
+ msgid "BackUpWordPress Error"
687
+ msgstr ""
688
+
689
+ #: classes/class-backup.php:388
690
+ msgid "archive filename must be a non empty string"
691
+ msgstr ""
692
+
693
+ #: classes/class-backup.php:392
694
+ msgid "invalid file extension for archive filename <code>%s</code>"
695
+ msgstr ""
696
+
697
+ #: classes/class-backup.php:433
698
+ msgid "database dump filename must be a non empty string"
699
+ msgstr ""
700
+
701
+ #: classes/class-backup.php:437
702
+ msgid "invalid file extension for database dump filename <code>%s</code>"
703
+ msgstr ""
704
+
705
+ #: classes/class-backup.php:471
706
+ msgid "Invalid root path <code>%s</code> must be a valid directory path"
707
+ msgstr ""
708
+
709
+ #: classes/class-backup.php:497
710
+ msgid ""
711
+ "Invalid existing archive filepath <code>%s</code> must be a non empty "
712
+ "(string)"
713
+ msgstr ""
714
+
715
+ #: classes/class-backup.php:552
716
+ msgid ""
717
+ "Invalid backup type <code>%s</code> must be one of (string) file, database "
718
+ "or complete"
719
+ msgstr ""
720
+
721
+ #: classes/class-backup.php:1926
722
+ msgid "Could not connect to mysql"
723
+ msgstr ""
724
+
725
+ #: classes/class-backupwordpress-wp-cli-command.php:50
726
+ msgid "Backup: Dumping database..."
727
+ msgstr ""
728
+
729
+ #: classes/class-backupwordpress-wp-cli-command.php:54
730
+ msgid "Backup: Zipping everything up..."
731
+ msgstr ""
732
+
733
+ #: classes/class-backupwordpress-wp-cli-command.php:70
734
+ msgid "Invalid backup path"
735
+ msgstr ""
736
+
737
+ #: classes/class-backupwordpress-wp-cli-command.php:75
738
+ msgid "Invalid root path"
739
+ msgstr ""
740
+
741
+ #: classes/class-backupwordpress-wp-cli-command.php:106
742
+ msgid "Backup Complete: "
743
+ msgstr ""
744
+
745
+ #: classes/class-backupwordpress-wp-cli-command.php:108
746
+ msgid "Backup Failed"
747
+ msgstr ""
748
+
749
+ #: classes/class-email-service.php:28
750
+ msgid "Email notification"
751
+ msgstr ""
752
+
753
+ #: classes/class-email-service.php:34
754
+ msgid ""
755
+ "Receive a notification email when a backup completes, if the backup is small "
756
+ "enough (&lt; %s) then it will be attached to the email. Separate multiple "
757
+ "email addresses with a comma."
758
+ msgstr ""
759
+
760
+ #: classes/class-email-service.php:63
761
+ msgid ""
762
+ "The maximum filesize of your backup that will be attached to your "
763
+ "notification emails . Defaults to %s."
764
+ msgstr ""
765
+
766
+ #: classes/class-email-service.php:82
767
+ msgid "Send an email notification to %s"
768
+ msgstr ""
769
+
770
+ #: classes/class-email-service.php:117
771
+ msgid "%s isn't a valid email"
772
+ msgstr ""
773
+
774
+ #: classes/class-email-service.php:179 classes/class-webhook-service.php:59
775
+ msgid "Backup of %s Failed"
776
+ msgstr ""
777
+
778
+ #: classes/class-email-service.php:181
779
+ msgid "BackUpWordPress was unable to backup your site %1$s."
780
+ msgstr ""
781
+
782
+ #: classes/class-email-service.php:181
783
+ msgid "Here are the errors that we're encountered:"
784
+ msgstr ""
785
+
786
+ #: classes/class-email-service.php:181
787
+ msgid ""
788
+ "If the errors above look like Martian, forward this email to %3$s and we'll "
789
+ "take a look"
790
+ msgstr ""
791
+
792
+ #: classes/class-email-service.php:181
793
+ msgid ""
794
+ "Kind Regards,\n"
795
+ "The Apologetic BackUpWordPress Backup Emailing Robot"
796
+ msgstr ""
797
+
798
+ #: classes/class-email-service.php:189
799
+ msgid "Backup of %s"
800
+ msgstr ""
801
+
802
+ #: classes/class-email-service.php:194 classes/class-email-service.php:203
803
+ msgid "BackUpWordPress has completed a backup of your site %1$s."
804
+ msgstr ""
805
+
806
+ #: classes/class-email-service.php:194
807
+ msgid "The backup file should be attached to this email."
808
+ msgstr ""
809
+
810
+ #: classes/class-email-service.php:194 classes/class-email-service.php:203
811
+ msgid "You can download the backup file by clicking the link below:"
812
+ msgstr ""
813
+
814
+ #: classes/class-email-service.php:194 classes/class-email-service.php:203
815
+ msgid ""
816
+ "Kind Regards,\n"
817
+ "The Happy BackUpWordPress Backup Emailing Robot"
818
+ msgstr ""
819
+
820
+ #: classes/class-email-service.php:203
821
+ msgid "Unfortunately the backup file was too large to attach to this email."
822
+ msgstr ""
823
+
824
+ #: classes/class-path.php:249
825
+ msgid ""
826
+ "This %s file ensures that other people cannot download your backup files."
827
+ msgstr ""
828
+
829
+ #: classes/class-plugin.php:214
830
+ msgid "Update"
831
+ msgstr ""
832
+
833
+ #: classes/class-plugin.php:215
834
+ msgid "Cancel"
835
+ msgstr ""
836
+
837
+ #: classes/class-plugin.php:216
838
+ msgid ""
839
+ "Are you sure you want to delete this schedule? All of it's backups will also "
840
+ "be deleted."
841
+ msgstr ""
842
+
843
+ #: classes/class-plugin.php:216 classes/class-plugin.php:217
844
+ #: classes/class-plugin.php:218 classes/class-plugin.php:219
845
+ msgid "'Cancel' to go back, 'OK' to delete."
846
+ msgstr ""
847
+
848
+ #: classes/class-plugin.php:217
849
+ msgid "Are you sure you want to delete this backup?"
850
+ msgstr ""
851
+
852
+ #: classes/class-plugin.php:218
853
+ msgid "Are you sure you want to remove this exclude rule?"
854
+ msgstr ""
855
+
856
+ #: classes/class-plugin.php:219
857
+ msgid ""
858
+ "Reducing the number of backups that are stored on this server will cause "
859
+ "some of your existing backups to be deleted, are you sure that's what you "
860
+ "want?"
861
+ msgstr ""
862
+
863
+ #: classes/class-schedule.php:151
864
+ msgid "Invalid Option Name"
865
+ msgstr ""
866
+
867
+ #: classes/class-schedule.php:264
868
+ msgid "Argument 1 for %s must be a valid integer"
869
+ msgstr ""
870
+
871
+ #: classes/class-schedule.php:612
872
+ msgid "Argument 1 for %s must be a valid future timestamp"
873
+ msgstr ""
874
+
875
+ #: classes/class-schedule.php:649
876
+ msgid "Argument 1 for %s must be a valid cron reoccurrence or \"manually\""
877
+ msgstr ""
878
+
879
+ #: classes/class-schedule.php:778 functions/interface.php:267
880
+ msgid "Starting Backup"
881
+ msgstr ""
882
+
883
+ #: classes/class-schedule.php:865
884
+ msgid "Error writing to file. (%s)"
885
+ msgstr ""
886
+
887
+ #: classes/class-schedule.php:916
888
+ msgid "Dumping Database %s"
889
+ msgstr ""
890
+
891
+ #: classes/class-schedule.php:921
892
+ msgid "Verifying Database Dump %s"
893
+ msgstr ""
894
+
895
+ #: classes/class-schedule.php:926
896
+ msgid "Creating zip archive %s"
897
+ msgstr ""
898
+
899
+ #: classes/class-schedule.php:931
900
+ msgid "Verifying Zip Archive %s"
901
+ msgstr ""
902
+
903
+ #: classes/class-schedule.php:936
904
+ msgid "Finishing Backup"
905
+ msgstr ""
906
+
907
+ #: classes/class-schedule.php:987
908
+ msgid "An unexpected error occured"
909
+ msgstr ""
910
+
911
+ #. translators: min=minute
912
+ #: classes/class-schedule.php:1050
913
+ msgid "%s min"
914
+ msgid_plural "%s mins"
915
+ msgstr[0] ""
916
+ msgstr[1] ""
917
+
918
+ #: classes/class-schedule.php:1060
919
+ msgid "%s hour"
920
+ msgid_plural "%s hours"
921
+ msgstr[0] ""
922
+ msgstr[1] ""
923
+
924
+ #: classes/class-schedule.php:1122
925
+ msgid "Argument 1 for %s must be a non empty string"
926
+ msgstr ""
927
+
928
+ #: classes/class-schedule.php:1127
929
+ msgid "%s doesn't exist"
930
+ msgstr ""
931
+
932
+ #: classes/class-schedule.php:1132
933
+ msgid "That backup wasn't created by this schedule"
934
+ msgstr ""
935
+
936
+ #: classes/class-services.php:80
937
+ msgid "Argument 1 for %s must be a valid filepath"
938
+ msgstr ""
939
+
940
+ #: classes/class-services.php:96
941
+ msgid "Argument 1 for %s must be a registered service"
942
+ msgstr ""
943
+
944
+ #: classes/class-services.php:114 classes/deprecated.php:81
945
+ msgid "Argument 1 for %s must be a valid class"
946
+ msgstr ""
947
+
948
+ #: classes/class-setup.php:34
949
+ msgid "BackUpWordPress"
950
+ msgstr ""
951
+
952
+ #: classes/class-setup.php:170
953
+ msgid ""
954
+ "BackUpWordPress requires PHP version %1$s or later and WordPress version "
955
+ "%2$s or later to run. It has not been activated. %3$s%4$s%5$sLearn more%6$s"
956
+ msgstr ""
957
+
958
+ #: classes/class-webhook-service.php:103
959
+ msgid "Error: %s"
960
+ msgstr ""
961
+
962
+ #: functions/core.php:326
963
+ msgid "BackUpWordPress has setup your default schedules."
964
+ msgstr ""
965
+
966
+ #: functions/core.php:326
967
+ msgid ""
968
+ "By default BackUpWordPress performs a daily backup of your database and a "
969
+ "weekly backup of your database &amp; files. You can modify these schedules."
970
+ msgstr ""
971
+
972
+ #: functions/core.php:341
973
+ msgid "Once Hourly"
974
+ msgstr ""
975
+
976
+ #: functions/core.php:342
977
+ msgid "Twice Daily"
978
+ msgstr ""
979
+
980
+ #: functions/core.php:343
981
+ msgid "Once Daily"
982
+ msgstr ""
983
+
984
+ #: functions/core.php:344
985
+ msgid "Once Weekly"
986
+ msgstr ""
987
+
988
+ #: functions/core.php:345
989
+ msgid "Once Biweekly"
990
+ msgstr "Once Fortnightly"
991
+
992
+ #: functions/core.php:346
993
+ msgid "Once Monthly"
994
+ msgstr ""
995
+
996
+ #: functions/core.php:364
997
+ msgid "You can only delete directories inside your WordPress installation"
998
+ msgstr ""
999
+
1000
+ #: functions/interface.php:31
1001
+ msgid "Download"
1002
+ msgstr ""
1003
+
1004
+ #: functions/interface.php:68
1005
+ msgid "BackUpWordPress detected issues with your last backup."
1006
+ msgstr ""
1007
+
1008
+ #: functions/interface.php:70
1009
+ msgid "Dismiss"
1010
+ msgstr ""
1011
+
1012
+ #: functions/interface.php:136
1013
+ msgid ""
1014
+ "The backups directory can't be created because your %1$s directory isn't "
1015
+ "writable, run %2$s or %3$s or create the folder yourself."
1016
+ msgstr ""
1017
+
1018
+ #: functions/interface.php:140
1019
+ msgid ""
1020
+ "Your backups directory isn't writable, run %1$s or %2$s or set the "
1021
+ "permissions yourself."
1022
+ msgstr ""
1023
+
1024
+ #: functions/interface.php:144
1025
+ msgid ""
1026
+ "%1$s is running in %2$s, please contact your host and ask them to disable "
1027
+ "it. BackUpWordPress may not work correctly whilst %3$s is on."
1028
+ msgstr ""
1029
+
1030
+ #: functions/interface.php:144
1031
+ msgid "http://php.net/manual/en/features.safe-mode.php"
1032
+ msgstr ""
1033
+
1034
+ #: functions/interface.php:144
1035
+ msgid "Safe Mode"
1036
+ msgstr ""
1037
+
1038
+ #: functions/interface.php:152
1039
+ msgid "Your custom path does not exist"
1040
+ msgstr ""
1041
+
1042
+ #: functions/interface.php:156
1043
+ msgid ""
1044
+ "Your custom path is unreachable due to a restriction set in your PHP "
1045
+ "configuration (open_basedir)"
1046
+ msgstr ""
1047
+
1048
+ #: functions/interface.php:161
1049
+ msgid ""
1050
+ "Your custom backups directory %1$s doesn't exist and can't be created, your "
1051
+ "backups will be saved to %2$s instead."
1052
+ msgstr ""
1053
+
1054
+ #: functions/interface.php:165
1055
+ msgid ""
1056
+ "Your custom backups directory %1$s isn't writable, new backups will be saved "
1057
+ "to %2$s instead."
1058
+ msgstr ""
1059
+
1060
+ #: functions/interface.php:174
1061
+ msgid "Your site root path %s isn't readable."
1062
+ msgstr ""
1063
+
1064
+ #: functions/interface.php:236
1065
+ msgid "Database and Files"
1066
+ msgstr ""
1067
+
1068
+ #: functions/interface.php:240
1069
+ msgid "Files"
1070
+ msgstr ""
1071
+
1072
+ #: functions/interface.php:244
1073
+ msgid "Database"
1074
+ msgstr ""
1075
+
1076
+ #: functions/interface.php:251
1077
+ msgid "Legacy"
1078
+ msgstr ""
1079
+
1080
+ #: functions/interface.php:266
1081
+ msgid "Started %s ago"
1082
+ msgstr ""
1083
+
1084
+ #: functions/interface.php:268
1085
+ msgid "cancel"
1086
+ msgstr ""
1087
+
1088
+ #: functions/interface.php:316
1089
+ msgid "No backups completed"
1090
+ msgstr ""
1091
+
1092
+ #: functions/interface.php:327
1093
+ msgid "Complete Hourly"
1094
+ msgstr ""
1095
+
1096
+ #: functions/interface.php:328
1097
+ msgid "File Hourly"
1098
+ msgstr ""
1099
+
1100
+ #: functions/interface.php:329
1101
+ msgid "Database Hourly"
1102
+ msgstr ""
1103
+
1104
+ #: functions/interface.php:330
1105
+ msgid "Complete Twicedaily"
1106
+ msgstr ""
1107
+
1108
+ #: functions/interface.php:331
1109
+ msgid "File Twicedaily"
1110
+ msgstr ""
1111
+
1112
+ #: functions/interface.php:332
1113
+ msgid "Database Twicedaily"
1114
+ msgstr ""
1115
+
1116
+ #: functions/interface.php:333
1117
+ msgid "Complete Daily"
1118
+ msgstr ""
1119
+
1120
+ #: functions/interface.php:334
1121
+ msgid "File Daily"
1122
+ msgstr ""
1123
+
1124
+ #: functions/interface.php:335
1125
+ msgid "Database Daily"
1126
+ msgstr ""
1127
+
1128
+ #: functions/interface.php:336
1129
+ msgid "Complete Weekly"
1130
+ msgstr ""
1131
+
1132
+ #: functions/interface.php:337
1133
+ msgid "File Weekly"
1134
+ msgstr ""
1135
+
1136
+ #: functions/interface.php:338
1137
+ msgid "Database Weekly"
1138
+ msgstr ""
1139
+
1140
+ #: functions/interface.php:339
1141
+ msgid "Complete Biweekly"
1142
+ msgstr "Complete Fortnightly"
1143
+
1144
+ #: functions/interface.php:340
1145
+ msgid "File Biweekly"
1146
+ msgstr "File Fortnightly"
1147
+
1148
+ #: functions/interface.php:341
1149
+ msgid "Database Biweekly"
1150
+ msgstr "Database Fortnightly"
1151
+
1152
+ #: functions/interface.php:342
1153
+ msgid "Complete Monthly"
1154
+ msgstr ""
1155
+
1156
+ #: functions/interface.php:343
1157
+ msgid "File Monthly"
1158
+ msgstr ""
1159
+
1160
+ #: functions/interface.php:344
1161
+ msgid "Database Monthly"
1162
+ msgstr ""
1163
+
1164
+ #: functions/interface.php:345
1165
+ msgid "Complete Manually"
1166
+ msgstr ""
1167
+
1168
+ #: functions/interface.php:346
1169
+ msgid "File Manually"
1170
+ msgstr ""
1171
+
1172
+ #: functions/interface.php:347
1173
+ msgid "Database Manually"
1174
+ msgstr ""
1175
+
1176
+ #. Plugin Name of the plugin/theme
1177
+ msgid "BackUpWordPress Backup Plugin"
1178
+ msgstr ""
1179
+
1180
+ #. Plugin URI of the plugin/theme
1181
+ msgid "http://bwp.hmn.md/"
1182
+ msgstr ""
1183
+
1184
+ #. Description of the plugin/theme
1185
+ msgid ""
1186
+ "Simple automated backups of your WordPress powered website. Once activated "
1187
+ "you'll find me under <strong>Tools &rarr; Backups</strong>. On multisite, "
1188
+ "you'll find me under the Network Settings menu."
1189
+ msgstr ""
1190
+
1191
+ #. Author of the plugin/theme
1192
+ msgid "Human Made Limited"
1193
+ msgstr ""
1194
+
1195
+ #. Author URI of the plugin/theme
1196
+ msgid "http://hmn.md/"
1197
+ msgstr ""
1198
+
1199
+ #: admin/schedule-sentence.php:120
1200
+ msgctxt ""
1201
+ "1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to "
1202
+ "store"
1203
+ msgid "Backup my %1$s %2$s %3$s, %4$s."
1204
+ msgstr ""
1205
+
1206
+ #: functions/interface.php:318
1207
+ msgctxt "backups count"
1208
+ msgid "One backup completed"
1209
+ msgid_plural "%1$s backups completed"
1210
+ msgstr[0] ""
1211
+ msgstr[1] ""
languages/backupwordpress.pot CHANGED
@@ -1,126 +1,137 @@
1
  # Copyright (C) 2015 Human Made Limited
2
- # This file is distributed under the GPL-2.0+.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: BackUpWordPress 3.2.6\n"
6
  "Report-Msgid-Bugs-To: backupwordpress@hmn.md\n"
7
- "POT-Creation-Date: 2015-07-18 14:46:49+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: 2015-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: Human Made Limited\n"
13
  "Language-Team: Human Made Limited\n"
14
- "X-Generator: grunt-wp-i18n 0.4.9\n"
15
 
16
- #: admin/actions.php:191
17
  msgid "The schedule ID was not provided. Aborting."
18
  msgstr ""
19
 
20
- #: admin/actions.php:241
21
  msgid "Backup type cannot be empty"
22
  msgstr ""
23
 
24
- #: admin/actions.php:245
25
  msgid "Invalid backup type"
26
  msgstr ""
27
 
28
- #: admin/actions.php:259
29
  msgid "Schedule cannot be empty"
30
  msgstr ""
31
 
32
- #: admin/actions.php:263
33
  msgid "Invalid schedule"
34
  msgstr ""
35
 
36
- #: admin/actions.php:277
37
- msgid "Day of the week must be a valid lowercase day name"
38
  msgstr ""
39
 
40
- #: admin/actions.php:296
41
  msgid "Day of month must be between 1 and 31"
42
  msgstr ""
43
 
44
- #: admin/actions.php:315
45
  msgid "Hours must be between 0 and 23"
46
  msgstr ""
47
 
48
- #: admin/actions.php:334
49
  msgid "Minutes must be between 0 and 59"
50
  msgstr ""
51
 
52
- #: admin/actions.php:348
53
  msgid "Max backups can't be empty"
54
  msgstr ""
55
 
56
- #: admin/actions.php:352
57
  msgid "Max backups must be a number"
58
  msgstr ""
59
 
60
- #: admin/actions.php:356
61
  msgid "Max backups must be greater than 0"
62
  msgstr ""
63
 
64
  #: admin/actions.php:708 admin/actions.php:714
 
65
  msgid "BackUpWordPress has detected a problem."
66
  msgstr ""
67
 
68
- #: admin/actions.php:708 admin/actions.php:714
69
  msgid ""
70
  "%1$s is returning a %2$s response which could mean cron jobs aren't getting "
71
  "fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. "
72
  "See the %3$s for more details."
73
  msgstr ""
74
 
75
- #: admin/backups-table.php:8 admin/schedule-form-excludes.php:105
 
 
 
 
 
 
 
 
 
 
76
  msgid "Size"
77
  msgstr ""
78
 
79
- #: admin/backups-table.php:9 admin/schedule-form-excludes.php:107
 
 
80
  msgid "Type"
81
  msgstr ""
82
 
83
- #: admin/backups-table.php:10
84
  msgid "Actions"
85
  msgstr ""
86
 
87
- #: admin/backups-table.php:35
88
  msgid "This is where your backups will appear once you have some."
89
  msgstr ""
90
 
91
- #: admin/backups.php:22
92
  msgid "add schedule"
93
  msgstr ""
94
 
95
- #: admin/backups.php:26
96
- msgid "Support"
97
- msgstr ""
98
-
99
- #: admin/backups.php:32
100
- msgid "Enable Support"
101
- msgstr ""
102
-
103
- #: admin/constants.php:3
104
  msgid ""
105
  "You can %1$s any of the following %2$s in your %3$s to control advanced "
106
  "settings. %4$s. Defined %5$s will be highlighted."
107
  msgstr ""
108
 
109
- #: admin/constants.php:3 admin/menu.php:82
 
110
  msgid "Constants"
111
  msgstr ""
112
 
113
- #: admin/constants.php:3
114
  msgid "The Codex can help"
115
  msgstr ""
116
 
117
  #: admin/constants.php:14 admin/constants.php:30 admin/constants.php:46
118
  #: admin/constants.php:62 admin/constants.php:78 admin/constants.php:94
119
  #: admin/constants.php:110 classes/class-email-service.php:60
 
 
 
 
 
120
  msgid "You've set it to: %s"
121
  msgstr ""
122
 
123
- #: admin/constants.php:17
124
  msgid ""
125
  "The path to folder you would like to store your backup files in, defaults "
126
  "to %s."
@@ -129,81 +140,87 @@ msgstr ""
129
  #: admin/constants.php:17 admin/constants.php:33 admin/constants.php:49
130
  #: admin/constants.php:65 admin/constants.php:81 admin/constants.php:97
131
  #: admin/constants.php:113 classes/class-email-service.php:63
 
 
 
 
 
132
  msgid "e.g."
133
  msgstr ""
134
 
135
- #: admin/constants.php:33
136
  msgid ""
137
  "The path to your %1$s executable. Will be used for the %2$s part of the "
138
  "back up if available."
139
  msgstr ""
140
 
141
  #: admin/constants.php:33 admin/constants.php:49
 
142
  msgid "database"
143
  msgstr ""
144
 
145
- #: admin/constants.php:49
146
  msgid ""
147
  "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
148
  "if available."
149
  msgstr ""
150
 
151
- #: admin/constants.php:49
152
  msgid "files"
153
  msgstr ""
154
 
155
- #: admin/constants.php:65
156
  msgid ""
157
  "Comma separated list of files or directories to exclude, the backups "
158
  "directory is automatically excluded."
159
  msgstr ""
160
 
161
- #: admin/constants.php:81
162
  msgid "The capability to use when calling %1$s. Defaults to %2$s."
163
  msgstr ""
164
 
165
- #: admin/constants.php:97
166
  msgid "The root directory that is backed up. Defaults to %s."
167
  msgstr ""
168
 
169
- #: admin/constants.php:113
170
  msgid "The time that your schedules should run. Defaults to %s."
171
  msgstr ""
172
 
173
- #: admin/enable-support.php:3
174
  msgid "Enable BackUpWordPress Support"
175
  msgstr ""
176
 
177
- #: admin/enable-support.php:5
178
  msgid ""
179
  "BackUpWordPress uses %s to provide support. In addition to allowing you to "
180
  "send and receive messages we also send the following server information "
181
  "along with your requests:"
182
  msgstr ""
183
 
184
- #: admin/enable-support.php:58
185
  msgid "You can disable support in the future by deactivating BackUpWordPress."
186
  msgstr ""
187
 
188
- #: admin/enable-support.php:60
189
- msgid "No thanks"
190
  msgstr ""
191
 
192
- #: admin/enable-support.php:61
193
- msgid "Yes I want to enable support"
194
  msgstr ""
195
 
196
- #: admin/faq.php:2
197
  msgid "Where does BackUpWordPress store the backup files?"
198
  msgstr ""
199
 
200
- #: admin/faq.php:4
201
  msgid ""
202
  "Backups are stored on your server in <code>/wp-content/backups</code>, you "
203
  "can change the directory."
204
  msgstr ""
205
 
206
- #: admin/faq.php:6
207
  msgid ""
208
  "Important: By default BackUpWordPress backs up everything in your site root "
209
  "as well as your database, this includes any non WordPress folders that "
@@ -211,11 +228,11 @@ msgid ""
211
  "can get quite large."
212
  msgstr ""
213
 
214
- #: admin/faq.php:8
215
  msgid "What if I want to back up my site to another destination?"
216
  msgstr ""
217
 
218
- #: admin/faq.php:10
219
  msgid ""
220
  "BackUpWordPress Pro supports Dropbox, Google Drive, Amazon S3, Rackspace, "
221
  "Azure, DreamObjects and FTP/SFTP. Check it out here: <a "
@@ -224,11 +241,11 @@ msgid ""
224
  "target=\"_blank\">https://bwp.hmn.md</a>"
225
  msgstr ""
226
 
227
- #: admin/faq.php:12
228
  msgid "How do I restore my site from a backup?"
229
  msgstr ""
230
 
231
- #: admin/faq.php:14
232
  msgid ""
233
  "You need to download the latest backup file either by clicking download on "
234
  "the backups page or via <code>FTP</code>. <code>Unzip</code> the files and "
@@ -237,26 +254,26 @@ msgid ""
237
  "<code>phpMyAdmin</code>)."
238
  msgstr ""
239
 
240
- #: admin/faq.php:16
241
  msgid ""
242
  "See this guide for more details - <a "
243
  "href=\"https://bwp.hmn.md/support-center/restore-backup/\" title=\"Go to "
244
  "support center\" target=\"_blank\">How to restore from backup</a>."
245
  msgstr ""
246
 
247
- #: admin/faq.php:18
248
  msgid "Does BackUpWordPress back up the backups directory?"
249
  msgstr ""
250
 
251
- #: admin/faq.php:20
252
  msgid "No."
253
  msgstr ""
254
 
255
- #: admin/faq.php:22
256
- msgid "I'm not receiving my backups by email?"
257
  msgstr ""
258
 
259
- #: admin/faq.php:24
260
  msgid ""
261
  "Most servers have a filesize limit on email attachments, it's generally "
262
  "about 10mb. If your backup file is over that limit it won't be sent "
@@ -265,19 +282,19 @@ msgid ""
265
  "a mail issue on your server that you'll need to contact your host about."
266
  msgstr ""
267
 
268
- #: admin/faq.php:26
269
  msgid "How many backups are stored by default?"
270
  msgstr ""
271
 
272
- #: admin/faq.php:28
273
  msgid "BackUpWordPress stores the last 10 backups by default."
274
  msgstr ""
275
 
276
- #: admin/faq.php:30
277
  msgid "How long should a backup take?"
278
  msgstr ""
279
 
280
- #: admin/faq.php:32
281
  msgid ""
282
  "Unless your site is very large (many gigabytes) it should only take a few "
283
  "minutes to perform a back up, if your back up has been running for longer "
@@ -286,11 +303,11 @@ msgid ""
286
  "support."
287
  msgstr ""
288
 
289
- #: admin/faq.php:34
290
  msgid "What do I do if I get the wp-cron error message?"
291
  msgstr ""
292
 
293
- #: admin/faq.php:36
294
  msgid ""
295
  "The issue is that your <code>wp-cron.php</code> is not returning a "
296
  "<code>200</code> response when hit with a HTTP request originating from "
@@ -298,50 +315,50 @@ msgid ""
298
  "with the server / site."
299
  msgstr ""
300
 
301
- #: admin/faq.php:38
302
  msgid "There are some things you can test to confirm this is the issue."
303
  msgstr ""
304
 
305
- #: admin/faq.php:40
306
- msgid "Are scheduled posts working? (They use wp-cron as well ). "
307
  msgstr ""
308
 
309
- #: admin/faq.php:42
310
  msgid ""
311
  "Are you hosted on Heart Internet? (wp-cron may not be supported by Heart "
312
- "Internet, see below for work-around)."
313
  msgstr ""
314
 
315
- #: admin/faq.php:44
316
  msgid "If you click manual backup does it work?"
317
  msgstr ""
318
 
319
- #: admin/faq.php:46
320
  msgid ""
321
  "Try adding <code>define( 'ALTERNATE_WP_CRON', true );</code> to your "
322
  "<code>wp-config.php</code>, do automatic backups work?"
323
  msgstr ""
324
 
325
- #: admin/faq.php:48
326
  msgid ""
327
- "Is your site private (I.E. is it behind some kind of authentication, "
328
- "maintenance plugin, .htaccess) if so wp-cron won't work until you remove "
329
- "it, if you are and you temporarily remove the authentication, do backups "
330
  "start working?"
331
  msgstr ""
332
 
333
- #: admin/faq.php:50
334
  msgid ""
335
  "Report the results to our support team for further help. To do this, either "
336
  "enable suport from your Admin Dashboard (recommended), or email "
337
  "backupwordpress@hmn.md"
338
  msgstr ""
339
 
340
- #: admin/faq.php:52
341
  msgid "How to get BackUpWordPress working in Heart Internet"
342
  msgstr ""
343
 
344
- #: admin/faq.php:54
345
  msgid ""
346
  "The script to be entered into the Heart Internet cPanel is: "
347
  "<code>/usr/bin/php5 "
@@ -350,599 +367,689 @@ msgid ""
350
  "<code>wp-cron.php</code> <code>chmod</code> must be set to <code>711</code>."
351
  msgstr ""
352
 
353
- #: admin/faq.php:56
354
  msgid "My backups seem to be failing?"
355
  msgstr ""
356
 
357
- #: admin/faq.php:58
358
  msgid ""
359
- "If your backups are failing - it's commonly caused by lack of available "
360
- "resources on your server. The easiest way to establish this to exclude some "
361
- "[of] or your entire uploades folder, running a backup an if that succeeds. "
362
- "If so, we know it's probably a server issue. If not, report the results to "
363
- "our support team for further help. To do this, either enable suport from "
364
- "your Admin Dashboard (recommended), or email backupwordpress@hmn.md"
 
365
  msgstr ""
366
 
367
- #: admin/menu.php:13 admin/menu.php:17
 
368
  msgid "Manage Backups"
369
  msgstr ""
370
 
371
  #: admin/menu.php:13 admin/menu.php:17 admin/menu.php:46
 
 
372
  msgid "Backups"
373
  msgstr ""
374
 
375
- #: admin/menu.php:77
376
  msgid "FAQ"
377
  msgstr ""
378
 
379
- #: admin/menu.php:95
380
  msgid "Server Info"
381
  msgstr ""
382
 
383
- #: admin/menu.php:102
384
  msgid "For more information:"
385
  msgstr ""
386
 
387
- #: admin/menu.php:104
388
  msgid "Support Forums"
389
  msgstr ""
390
 
391
- #: admin/menu.php:105
392
  msgid "Help with translation"
393
  msgstr ""
394
 
395
- #: admin/page.php:7
 
 
 
 
 
 
 
 
396
  msgid ""
397
  "If you're finding BackUpWordPress useful, please %1$s rate it on the plugin "
398
  "directory%2$s."
399
  msgstr ""
400
 
401
  #: admin/schedule-form-excludes.php:6
 
402
  msgid "Currently Excluded"
403
  msgstr ""
404
 
405
  #: admin/schedule-form-excludes.php:9
 
406
  msgid ""
407
  "We automatically detect and ignore common <abbr title=\"Version Control "
408
  "Systems\">VCS</abbr> folders and other backup plugin folders."
409
  msgstr ""
410
 
411
  #: admin/schedule-form-excludes.php:44
 
412
  msgid "Default rule"
413
  msgstr ""
414
 
415
  #: admin/schedule-form-excludes.php:48
 
416
  msgid "Defined in wp-config.php"
417
  msgstr ""
418
 
419
  #: admin/schedule-form-excludes.php:55
 
420
  msgid "Stop excluding"
421
  msgstr ""
422
 
423
  #: admin/schedule-form-excludes.php:71
424
- msgid "Directory Listing"
 
425
  msgstr ""
426
 
427
  #: admin/schedule-form-excludes.php:73
 
428
  msgid ""
429
  "Here's a directory listing of all files on your site, you can browse "
430
  "through and exclude files or folders that you don't want included in your "
431
  "backup."
432
  msgstr ""
433
 
434
- #: admin/schedule-form-excludes.php:104
 
435
  msgid "Name"
436
  msgstr ""
437
 
438
- #: admin/schedule-form-excludes.php:106
 
439
  msgid "Permissions"
440
  msgstr ""
441
 
442
- #: admin/schedule-form-excludes.php:108
 
443
  msgid "Status"
444
  msgstr ""
445
 
446
- #: admin/schedule-form-excludes.php:168 admin/schedule-form-excludes.php:284
 
 
447
  msgid "Refresh"
448
  msgstr ""
449
 
450
- #: admin/schedule-form-excludes.php:185 admin/schedule-form-excludes.php:308
 
 
451
  msgid "Symlink"
452
  msgstr ""
453
 
454
- #: admin/schedule-form-excludes.php:189 admin/schedule-form-excludes.php:312
 
 
455
  msgid "Folder"
456
  msgstr ""
457
 
458
  #: admin/schedule-form-excludes.php:282
 
459
  msgid "Recalculate the size of this directory"
460
  msgstr ""
461
 
462
  #: admin/schedule-form-excludes.php:316
 
463
  msgid "File"
464
  msgstr ""
465
 
466
  #: admin/schedule-form-excludes.php:327
 
467
  msgid "Unreadable files won't be backed up."
468
  msgstr ""
469
 
470
  #: admin/schedule-form-excludes.php:327
 
471
  msgid "Unreadable"
472
  msgstr ""
473
 
474
  #: admin/schedule-form-excludes.php:331
 
475
  msgid "Excluded"
476
  msgstr ""
477
 
478
  #: admin/schedule-form-excludes.php:347
 
479
  msgid "Exclude &rarr;"
480
  msgstr ""
481
 
482
- #: admin/schedule-form-excludes.php:365 admin/schedule-form.php:192
 
 
 
 
 
483
  #: admin/schedule-settings.php:88
 
 
 
484
  msgid "Done"
485
  msgstr ""
486
 
487
  #: admin/schedule-form.php:1 admin/schedule-settings.php:9
 
 
488
  msgid "Settings"
489
  msgstr ""
490
 
491
- #: admin/schedule-form.php:36
492
  msgid "Backup"
493
  msgstr ""
494
 
495
- #: admin/schedule-form.php:43
496
  msgid "Both Database &amp; files"
497
  msgstr ""
498
 
499
- #: admin/schedule-form.php:45
500
  msgid "Files only"
501
  msgstr ""
502
 
503
- #: admin/schedule-form.php:47
504
  msgid "Database only"
505
  msgstr ""
506
 
507
- #: admin/schedule-form.php:58
508
  msgid "Schedule"
509
  msgstr ""
510
 
511
- #: admin/schedule-form.php:65
512
  msgid "Manual Only"
513
  msgstr ""
514
 
515
- #: admin/schedule-form.php:92
516
  msgid "Start Day"
517
  msgstr ""
518
 
519
- #: admin/schedule-form.php:100
520
  msgid "Monday"
521
  msgstr ""
522
 
523
- #: admin/schedule-form.php:101
524
  msgid "Tuesday"
525
  msgstr ""
526
 
527
- #: admin/schedule-form.php:102
528
  msgid "Wednesday"
529
  msgstr ""
530
 
531
- #: admin/schedule-form.php:103
532
  msgid "Thursday"
533
  msgstr ""
534
 
535
- #: admin/schedule-form.php:104
536
  msgid "Friday"
537
  msgstr ""
538
 
539
- #: admin/schedule-form.php:105
540
  msgid "Saturday"
541
  msgstr ""
542
 
543
- #: admin/schedule-form.php:106
544
  msgid "Sunday"
545
  msgstr ""
546
 
547
- #: admin/schedule-form.php:124
548
  msgid "Start Day of Month"
549
  msgstr ""
550
 
551
- #: admin/schedule-form.php:136
552
  msgid "Start Time"
553
  msgstr ""
554
 
555
- #: admin/schedule-form.php:145
556
  msgid "Hours"
557
  msgstr ""
558
 
559
- #: admin/schedule-form.php:149
560
  msgid "Minutes"
561
  msgstr ""
562
 
563
- #: admin/schedule-form.php:152
564
- msgid "Please use 24 hour format for hours"
565
  msgstr ""
566
 
567
- #: admin/schedule-form.php:153
568
- msgid "The second backup will run 12 hours after the first"
569
  msgstr ""
570
 
571
- #: admin/schedule-form.php:162
572
  msgid "Number of backups to store on this server"
573
  msgstr ""
574
 
575
- #: admin/schedule-form.php:171
576
  msgid "Past this limit older backups will be deleted automatically."
577
  msgstr ""
578
 
579
- #: admin/schedule-form.php:174
580
  msgid "This schedule will store a maximum of %s of backups."
581
  msgstr ""
582
 
583
- #: admin/schedule-sentence.php:11
584
  msgid "The next backup will be on %1$s at %2$s %3$s"
585
  msgstr ""
586
 
587
- #: admin/schedule-sentence.php:18
588
  msgid "hourly on the hour"
589
  msgstr ""
590
 
591
- #: admin/schedule-sentence.php:18
592
  msgid "hourly at %s minutes past the hour"
593
  msgstr ""
594
 
595
- #: admin/schedule-sentence.php:24
596
  msgid "daily at %s"
597
  msgstr ""
598
 
599
- #: admin/schedule-sentence.php:35
600
  msgid "every 12 hours at %1$s &amp; %2$s"
601
  msgstr ""
602
 
603
- #: admin/schedule-sentence.php:41
604
  msgid "weekly on %1$s at %2$s"
605
  msgstr ""
606
 
607
- #: admin/schedule-sentence.php:47
608
- msgid "biweekly on %1$s at %2$s"
609
  msgstr ""
610
 
611
- #: admin/schedule-sentence.php:53
612
  msgid "on the %1$s of each month at %2$s"
613
  msgstr ""
614
 
615
  #: admin/schedule-sentence.php:59 admin/schedule-sentence.php:65
 
 
616
  msgid "manually"
617
  msgstr ""
618
 
619
- #: admin/schedule-sentence.php:70
620
  msgid "this server"
621
  msgstr ""
622
 
623
- #: admin/schedule-sentence.php:78
624
  msgid "store the most recent backup in %s"
625
  msgstr ""
626
 
627
- #: admin/schedule-sentence.php:84
628
  msgid "don't store any backups in on this server"
629
  msgstr ""
630
 
631
- #: admin/schedule-sentence.php:90
632
  msgid "store the last %1$s backups in %2$s"
633
  msgstr ""
634
 
635
- #: admin/schedule-sentence.php:123
636
  msgid "%s. "
637
  msgstr ""
638
 
639
- #: admin/schedule-sentence.php:127
640
  msgid "Send a copy of each backup to %s."
641
  msgstr ""
642
 
643
- #: admin/schedule-sentence.php:158
644
  msgid "Backups will be compressed and should be smaller than this."
645
  msgstr ""
646
 
647
- #: admin/schedule-sentence.php:162
648
  msgid "this shouldn't take long&hellip;"
649
  msgstr ""
650
 
651
- #: admin/schedule-sentence.php:162
652
  msgid "calculating the size of your backup&hellip;"
653
  msgstr ""
654
 
655
- #: admin/schedule-settings.php:7
656
  msgid "Run now"
657
  msgstr ""
658
 
659
- #: admin/schedule-settings.php:15
660
  msgid "Excludes"
661
  msgstr ""
662
 
663
  #: admin/schedule-settings.php:27 functions/interface.php:34
 
 
664
  msgid "Delete"
665
  msgstr ""
666
 
667
- #: admin/server-info.php:43
668
- msgid "%1$s - %2$s"
669
- msgstr ""
670
-
671
- #: admin/upsell.php:3
672
  msgid "Backup to"
673
  msgstr ""
674
 
675
- #: admin/upsell.php:18
676
  msgid ""
677
  "%1$sor buy the %2$sDeveloper Bundle%3$s now for only &dollar;99 (all "
678
  "Destinations &amp; Unlimited Sites)%4$s"
679
  msgstr ""
680
 
681
- #: backupwordpress.php:53
682
- msgid ""
683
- "BackUpWordPress will not work on this site. ( PHP Version %s is unsupported "
684
- ")"
685
  msgstr ""
686
 
687
- #: backupwordpress.php:53
688
  msgid "BackUpWordPress Error"
689
  msgstr ""
690
 
691
- #: classes/class-backup.php:388
692
- msgid "archive filename must be a non empty string"
693
  msgstr ""
694
 
695
- #: classes/class-backup.php:392
696
  msgid "invalid file extension for archive filename <code>%s</code>"
697
  msgstr ""
698
 
699
- #: classes/class-backup.php:433
700
- msgid "database dump filename must be a non empty string"
701
  msgstr ""
702
 
703
- #: classes/class-backup.php:437
704
  msgid "invalid file extension for database dump filename <code>%s</code>"
705
  msgstr ""
706
 
707
- #: classes/class-backup.php:471
708
  msgid "Invalid root path <code>%s</code> must be a valid directory path"
709
  msgstr ""
710
 
711
- #: classes/class-backup.php:497
712
  msgid ""
713
- "Invalid existing archive filepath <code>%s</code> must be a non empty "
714
  "(string)"
715
  msgstr ""
716
 
717
- #: classes/class-backup.php:552
718
  msgid ""
719
  "Invalid backup type <code>%s</code> must be one of (string) file, database "
720
  "or complete"
721
  msgstr ""
722
 
723
- #: classes/class-backup.php:1926
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  msgid "Could not connect to mysql"
725
  msgstr ""
726
 
727
  #: classes/class-backupwordpress-wp-cli-command.php:50
 
728
  msgid "Backup: Dumping database..."
729
  msgstr ""
730
 
731
  #: classes/class-backupwordpress-wp-cli-command.php:54
 
732
  msgid "Backup: Zipping everything up..."
733
  msgstr ""
734
 
735
  #: classes/class-backupwordpress-wp-cli-command.php:70
 
736
  msgid "Invalid backup path"
737
  msgstr ""
738
 
739
  #: classes/class-backupwordpress-wp-cli-command.php:75
 
740
  msgid "Invalid root path"
741
  msgstr ""
742
 
743
  #: classes/class-backupwordpress-wp-cli-command.php:106
 
744
  msgid "Backup Complete: "
745
  msgstr ""
746
 
747
  #: classes/class-backupwordpress-wp-cli-command.php:108
 
748
  msgid "Backup Failed"
749
  msgstr ""
750
 
751
  #: classes/class-email-service.php:28
 
752
  msgid "Email notification"
753
  msgstr ""
754
 
755
  #: classes/class-email-service.php:34
 
756
  msgid ""
757
- "Receive a notification email when a backup completes, if the backup is "
758
- "small enough (&lt; %s) then it will be attached to the email. Separate "
759
  "multiple email addresses with a comma."
760
  msgstr ""
761
 
762
  #: classes/class-email-service.php:63
 
763
  msgid ""
764
  "The maximum filesize of your backup that will be attached to your "
765
  "notification emails . Defaults to %s."
766
  msgstr ""
767
 
768
  #: classes/class-email-service.php:82
 
769
  msgid "Send an email notification to %s"
770
  msgstr ""
771
 
772
  #: classes/class-email-service.php:117
 
773
  msgid "%s isn't a valid email"
774
  msgstr ""
775
 
776
  #: classes/class-email-service.php:179 classes/class-webhook-service.php:59
 
 
777
  msgid "Backup of %s Failed"
778
  msgstr ""
779
 
780
  #: classes/class-email-service.php:181
 
781
  msgid "BackUpWordPress was unable to backup your site %1$s."
782
  msgstr ""
783
 
784
  #: classes/class-email-service.php:181
 
785
  msgid "Here are the errors that we're encountered:"
786
  msgstr ""
787
 
788
  #: classes/class-email-service.php:181
 
789
  msgid ""
790
  "If the errors above look like Martian, forward this email to %3$s and we'll "
791
  "take a look"
792
  msgstr ""
793
 
794
  #: classes/class-email-service.php:181
 
795
  msgid ""
796
  "Kind Regards,\n"
797
  "The Apologetic BackUpWordPress Backup Emailing Robot"
798
  msgstr ""
799
 
800
  #: classes/class-email-service.php:189
 
801
  msgid "Backup of %s"
802
  msgstr ""
803
 
804
  #: classes/class-email-service.php:194 classes/class-email-service.php:203
 
 
805
  msgid "BackUpWordPress has completed a backup of your site %1$s."
806
  msgstr ""
807
 
808
  #: classes/class-email-service.php:194
 
809
  msgid "The backup file should be attached to this email."
810
  msgstr ""
811
 
812
  #: classes/class-email-service.php:194 classes/class-email-service.php:203
 
 
813
  msgid "You can download the backup file by clicking the link below:"
814
  msgstr ""
815
 
816
  #: classes/class-email-service.php:194 classes/class-email-service.php:203
 
 
817
  msgid ""
818
  "Kind Regards,\n"
819
  "The Happy BackUpWordPress Backup Emailing Robot"
820
  msgstr ""
821
 
822
  #: classes/class-email-service.php:203
 
823
  msgid "Unfortunately the backup file was too large to attach to this email."
824
  msgstr ""
825
 
826
- #: classes/class-path.php:249
827
  msgid "This %s file ensures that other people cannot download your backup files."
828
  msgstr ""
829
 
830
- #: classes/class-plugin.php:214
831
  msgid "Update"
832
  msgstr ""
833
 
834
- #: classes/class-plugin.php:215
835
  msgid "Cancel"
836
  msgstr ""
837
 
838
- #: classes/class-plugin.php:216
839
  msgid ""
840
- "Are you sure you want to delete this schedule? All of it's backups will "
841
- "also be deleted."
842
  msgstr ""
843
 
844
  #: classes/class-plugin.php:216 classes/class-plugin.php:217
845
  #: classes/class-plugin.php:218 classes/class-plugin.php:219
 
 
 
 
846
  msgid "'Cancel' to go back, 'OK' to delete."
847
  msgstr ""
848
 
849
- #: classes/class-plugin.php:217
850
  msgid "Are you sure you want to delete this backup?"
851
  msgstr ""
852
 
853
- #: classes/class-plugin.php:218
854
  msgid "Are you sure you want to remove this exclude rule?"
855
  msgstr ""
856
 
857
- #: classes/class-plugin.php:219
858
  msgid ""
859
  "Reducing the number of backups that are stored on this server will cause "
860
- "some of your existing backups to be deleted, are you sure that's what you "
861
  "want?"
862
  msgstr ""
863
 
864
- #: classes/class-schedule.php:151
865
  msgid "Invalid Option Name"
866
  msgstr ""
867
 
868
- #: classes/class-schedule.php:264
869
  msgid "Argument 1 for %s must be a valid integer"
870
  msgstr ""
871
 
872
- #: classes/class-schedule.php:612
873
  msgid "Argument 1 for %s must be a valid future timestamp"
874
  msgstr ""
875
 
876
- #: classes/class-schedule.php:649
877
  msgid "Argument 1 for %s must be a valid cron reoccurrence or \"manually\""
878
  msgstr ""
879
 
880
- #: classes/class-schedule.php:778 functions/interface.php:272
 
 
881
  msgid "Starting Backup"
882
  msgstr ""
883
 
884
- #: classes/class-schedule.php:865
885
  msgid "Error writing to file. (%s)"
886
  msgstr ""
887
 
888
- #: classes/class-schedule.php:916
889
  msgid "Dumping Database %s"
890
  msgstr ""
891
 
892
- #: classes/class-schedule.php:921
893
  msgid "Verifying Database Dump %s"
894
  msgstr ""
895
 
896
- #: classes/class-schedule.php:926
897
  msgid "Creating zip archive %s"
898
  msgstr ""
899
 
900
- #: classes/class-schedule.php:931
901
  msgid "Verifying Zip Archive %s"
902
  msgstr ""
903
 
904
- #: classes/class-schedule.php:936
905
  msgid "Finishing Backup"
906
  msgstr ""
907
 
908
- #: classes/class-schedule.php:987
909
  msgid "An unexpected error occured"
910
  msgstr ""
911
 
912
- #: classes/class-schedule.php:1050
913
  #. translators: min=minute
914
  msgid "%s min"
915
  msgid_plural "%s mins"
916
  msgstr[0] ""
917
  msgstr[1] ""
918
 
919
- #: classes/class-schedule.php:1060
920
  msgid "%s hour"
921
  msgid_plural "%s hours"
922
  msgstr[0] ""
923
  msgstr[1] ""
924
 
925
- #: classes/class-schedule.php:1122
926
- msgid "Argument 1 for %s must be a non empty string"
927
  msgstr ""
928
 
929
- #: classes/class-schedule.php:1127
930
  msgid "%s doesn't exist"
931
  msgstr ""
932
 
933
- #: classes/class-schedule.php:1132
934
  msgid "That backup wasn't created by this schedule"
935
  msgstr ""
936
 
937
- #: classes/class-services.php:80
938
  msgid "Argument 1 for %s must be a valid filepath"
939
  msgstr ""
940
 
941
- #: classes/class-services.php:96
942
  msgid "Argument 1 for %s must be a registered service"
943
  msgstr ""
944
 
945
  #: classes/class-services.php:114 classes/deprecated.php:81
 
 
946
  msgid "Argument 1 for %s must be a valid class"
947
  msgstr ""
948
 
@@ -950,230 +1057,254 @@ msgstr ""
950
  msgid "BackUpWordPress"
951
  msgstr ""
952
 
953
- #: classes/class-setup.php:170
954
  msgid ""
955
  "BackUpWordPress requires PHP version %1$s or later and WordPress version "
956
  "%2$s or later to run. It has not been activated. %3$s%4$s%5$sLearn more%6$s"
957
  msgstr ""
958
 
959
  #: classes/class-webhook-service.php:103
 
960
  msgid "Error: %s"
961
  msgstr ""
962
 
963
- #: functions/core.php:326
964
- msgid "BackUpWordPress has setup your default schedules."
965
  msgstr ""
966
 
967
- #: functions/core.php:326
968
  msgid ""
969
  "By default BackUpWordPress performs a daily backup of your database and a "
970
  "weekly backup of your database &amp; files. You can modify these schedules."
971
  msgstr ""
972
 
973
- #: functions/core.php:341
974
  msgid "Once Hourly"
975
  msgstr ""
976
 
977
- #: functions/core.php:342
978
  msgid "Twice Daily"
979
  msgstr ""
980
 
981
- #: functions/core.php:343
982
  msgid "Once Daily"
983
  msgstr ""
984
 
985
- #: functions/core.php:344
986
  msgid "Once Weekly"
987
  msgstr ""
988
 
989
- #: functions/core.php:345
990
- msgid "Once Biweekly"
991
  msgstr ""
992
 
993
- #: functions/core.php:346
994
  msgid "Once Monthly"
995
  msgstr ""
996
 
997
- #: functions/core.php:364
998
  msgid "You can only delete directories inside your WordPress installation"
999
  msgstr ""
1000
 
1001
- #: functions/interface.php:31
1002
  msgid "Download"
1003
  msgstr ""
1004
 
1005
- #: functions/interface.php:73
1006
  msgid "BackUpWordPress detected issues with your last backup."
1007
  msgstr ""
1008
 
1009
- #: functions/interface.php:75
1010
  msgid "Dismiss"
1011
  msgstr ""
1012
 
1013
- #: functions/interface.php:141
 
 
 
 
 
 
 
1014
  msgid ""
1015
  "The backups directory can't be created because your %1$s directory isn't "
1016
- "writable, run %2$s or %3$s or create the folder yourself."
1017
  msgstr ""
1018
 
1019
- #: functions/interface.php:145
1020
  msgid ""
1021
- "Your backups directory isn't writable, run %1$s or %2$s or set the "
1022
  "permissions yourself."
1023
  msgstr ""
1024
 
1025
- #: functions/interface.php:149
1026
  msgid ""
1027
  "%1$s is running in %2$s, please contact your host and ask them to disable "
1028
  "it. BackUpWordPress may not work correctly whilst %3$s is on."
1029
  msgstr ""
1030
 
1031
- #: functions/interface.php:149
1032
  msgid "http://php.net/manual/en/features.safe-mode.php"
1033
  msgstr ""
1034
 
1035
- #: functions/interface.php:149
1036
  msgid "Safe Mode"
1037
  msgstr ""
1038
 
1039
- #: functions/interface.php:157
1040
  msgid "Your custom path does not exist"
1041
  msgstr ""
1042
 
1043
- #: functions/interface.php:161
1044
  msgid ""
1045
  "Your custom path is unreachable due to a restriction set in your PHP "
1046
  "configuration (open_basedir)"
1047
  msgstr ""
1048
 
1049
- #: functions/interface.php:166
1050
  msgid ""
1051
  "Your custom backups directory %1$s doesn't exist and can't be created, your "
1052
  "backups will be saved to %2$s instead."
1053
  msgstr ""
1054
 
1055
- #: functions/interface.php:170
1056
  msgid ""
1057
  "Your custom backups directory %1$s isn't writable, new backups will be "
1058
  "saved to %2$s instead."
1059
  msgstr ""
1060
 
1061
- #: functions/interface.php:179
1062
  msgid "Your site root path %s isn't readable."
1063
  msgstr ""
1064
 
1065
- #: functions/interface.php:241
1066
  msgid "Database and Files"
1067
  msgstr ""
1068
 
1069
- #: functions/interface.php:245
1070
  msgid "Files"
1071
  msgstr ""
1072
 
1073
- #: functions/interface.php:249
1074
  msgid "Database"
1075
  msgstr ""
1076
 
1077
- #: functions/interface.php:256
1078
  msgid "Legacy"
1079
  msgstr ""
1080
 
1081
- #: functions/interface.php:271
1082
  msgid "Started %s ago"
1083
  msgstr ""
1084
 
1085
- #: functions/interface.php:273
1086
  msgid "cancel"
1087
  msgstr ""
1088
 
1089
- #: functions/interface.php:321
1090
  msgid "No backups completed"
1091
  msgstr ""
1092
 
1093
- #: functions/interface.php:332
1094
  msgid "Complete Hourly"
1095
  msgstr ""
1096
 
1097
- #: functions/interface.php:333
1098
  msgid "File Hourly"
1099
  msgstr ""
1100
 
1101
- #: functions/interface.php:334
1102
  msgid "Database Hourly"
1103
  msgstr ""
1104
 
1105
- #: functions/interface.php:335
1106
- msgid "Complete Twicedaily"
1107
  msgstr ""
1108
 
1109
- #: functions/interface.php:336
1110
  msgid "File Twicedaily"
1111
  msgstr ""
1112
 
1113
- #: functions/interface.php:337
1114
- msgid "Database Twicedaily"
1115
  msgstr ""
1116
 
1117
- #: functions/interface.php:338
1118
  msgid "Complete Daily"
1119
  msgstr ""
1120
 
1121
- #: functions/interface.php:339
1122
  msgid "File Daily"
1123
  msgstr ""
1124
 
1125
- #: functions/interface.php:340
1126
  msgid "Database Daily"
1127
  msgstr ""
1128
 
1129
- #: functions/interface.php:341
1130
  msgid "Complete Weekly"
1131
  msgstr ""
1132
 
1133
- #: functions/interface.php:342
1134
  msgid "File Weekly"
1135
  msgstr ""
1136
 
1137
- #: functions/interface.php:343
1138
  msgid "Database Weekly"
1139
  msgstr ""
1140
 
1141
- #: functions/interface.php:344
1142
- msgid "Complete Biweekly"
1143
  msgstr ""
1144
 
1145
- #: functions/interface.php:345
1146
- msgid "File Biweekly"
1147
  msgstr ""
1148
 
1149
- #: functions/interface.php:346
1150
- msgid "Database Biweekly"
1151
  msgstr ""
1152
 
1153
- #: functions/interface.php:347
1154
  msgid "Complete Monthly"
1155
  msgstr ""
1156
 
1157
- #: functions/interface.php:348
1158
  msgid "File Monthly"
1159
  msgstr ""
1160
 
1161
- #: functions/interface.php:349
1162
  msgid "Database Monthly"
1163
  msgstr ""
1164
 
1165
- #: functions/interface.php:350
1166
  msgid "Complete Manually"
1167
  msgstr ""
1168
 
1169
- #: functions/interface.php:351
1170
  msgid "File Manually"
1171
  msgstr ""
1172
 
1173
- #: functions/interface.php:352
1174
  msgid "Database Manually"
1175
  msgstr ""
1176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1177
  #. Plugin URI of the plugin/theme
1178
  msgid "http://bwp.hmn.md/"
1179
  msgstr ""
@@ -1193,14 +1324,14 @@ msgstr ""
1193
  msgid "http://hmn.md/"
1194
  msgstr ""
1195
 
1196
- #: admin/schedule-sentence.php:120
1197
  msgctxt ""
1198
  "1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to "
1199
  "store"
1200
  msgid "Backup my %1$s %2$s %3$s, %4$s."
1201
  msgstr ""
1202
 
1203
- #: functions/interface.php:323
1204
  msgctxt "backups count"
1205
  msgid "One backup completed"
1206
  msgid_plural "%1$s backups completed"
1
  # Copyright (C) 2015 Human Made Limited
2
+ # This file is distributed under the GPL-2+.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: BackUpWordPress 3.3.0\n"
6
  "Report-Msgid-Bugs-To: backupwordpress@hmn.md\n"
7
+ "POT-Creation-Date: 2015-10-09 18:16:23+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: 2015-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: Human Made Limited\n"
13
  "Language-Team: Human Made Limited\n"
14
+ "X-Generator: grunt-wp-i18n 0.5.3\n"
15
 
16
+ #: admin/actions.php:191 releases/svn/admin/actions.php:191
17
  msgid "The schedule ID was not provided. Aborting."
18
  msgstr ""
19
 
20
+ #: admin/actions.php:241 releases/svn/admin/actions.php:241
21
  msgid "Backup type cannot be empty"
22
  msgstr ""
23
 
24
+ #: admin/actions.php:245 releases/svn/admin/actions.php:245
25
  msgid "Invalid backup type"
26
  msgstr ""
27
 
28
+ #: admin/actions.php:259 releases/svn/admin/actions.php:259
29
  msgid "Schedule cannot be empty"
30
  msgstr ""
31
 
32
+ #: admin/actions.php:263 releases/svn/admin/actions.php:263
33
  msgid "Invalid schedule"
34
  msgstr ""
35
 
36
+ #: admin/actions.php:277 releases/svn/admin/actions.php:277
37
+ msgid "Day of the week must be a valid, lowercase day name"
38
  msgstr ""
39
 
40
+ #: admin/actions.php:296 releases/svn/admin/actions.php:296
41
  msgid "Day of month must be between 1 and 31"
42
  msgstr ""
43
 
44
+ #: admin/actions.php:315 releases/svn/admin/actions.php:315
45
  msgid "Hours must be between 0 and 23"
46
  msgstr ""
47
 
48
+ #: admin/actions.php:334 releases/svn/admin/actions.php:334
49
  msgid "Minutes must be between 0 and 59"
50
  msgstr ""
51
 
52
+ #: admin/actions.php:348 releases/svn/admin/actions.php:348
53
  msgid "Max backups can't be empty"
54
  msgstr ""
55
 
56
+ #: admin/actions.php:352 releases/svn/admin/actions.php:352
57
  msgid "Max backups must be a number"
58
  msgstr ""
59
 
60
+ #: admin/actions.php:356 releases/svn/admin/actions.php:356
61
  msgid "Max backups must be greater than 0"
62
  msgstr ""
63
 
64
  #: admin/actions.php:708 admin/actions.php:714
65
+ #: releases/svn/admin/actions.php:708 releases/svn/admin/actions.php:714
66
  msgid "BackUpWordPress has detected a problem."
67
  msgstr ""
68
 
69
+ #: admin/actions.php:708 releases/svn/admin/actions.php:708
70
  msgid ""
71
  "%1$s is returning a %2$s response which could mean cron jobs aren't getting "
72
  "fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. "
73
  "See the %3$s for more details."
74
  msgstr ""
75
 
76
+ #: admin/actions.php:714 releases/svn/admin/actions.php:714
77
+ msgid ""
78
+ "%1$s is returning a %2$s response which could mean cron jobs aren't getting "
79
+ "fired properly. BackUpWordPress relies on wp-cron to run scheduled backups, "
80
+ "and more generally relies on HTTP loopback connections not being blocked "
81
+ "for manual backups. See the %3$s for more details."
82
+ msgstr ""
83
+
84
+ #: admin/backups-table.php:8 admin/schedule-form-excludes.php:103
85
+ #: releases/svn/admin/backups-table.php:8
86
+ #: releases/svn/admin/schedule-form-excludes.php:103
87
  msgid "Size"
88
  msgstr ""
89
 
90
+ #: admin/backups-table.php:9 admin/schedule-form-excludes.php:105
91
+ #: releases/svn/admin/backups-table.php:9
92
+ #: releases/svn/admin/schedule-form-excludes.php:105
93
  msgid "Type"
94
  msgstr ""
95
 
96
+ #: admin/backups-table.php:10 releases/svn/admin/backups-table.php:10
97
  msgid "Actions"
98
  msgstr ""
99
 
100
+ #: admin/backups-table.php:35 releases/svn/admin/backups-table.php:35
101
  msgid "This is where your backups will appear once you have some."
102
  msgstr ""
103
 
104
+ #: admin/backups.php:22 releases/svn/admin/backups.php:22
105
  msgid "add schedule"
106
  msgstr ""
107
 
108
+ #: admin/constants.php:3 releases/svn/admin/constants.php:3
 
 
 
 
 
 
 
 
109
  msgid ""
110
  "You can %1$s any of the following %2$s in your %3$s to control advanced "
111
  "settings. %4$s. Defined %5$s will be highlighted."
112
  msgstr ""
113
 
114
+ #: admin/constants.php:3 admin/menu.php:82 releases/svn/admin/constants.php:3
115
+ #: releases/svn/admin/menu.php:82
116
  msgid "Constants"
117
  msgstr ""
118
 
119
+ #: admin/constants.php:3 releases/svn/admin/constants.php:3
120
  msgid "The Codex can help"
121
  msgstr ""
122
 
123
  #: admin/constants.php:14 admin/constants.php:30 admin/constants.php:46
124
  #: admin/constants.php:62 admin/constants.php:78 admin/constants.php:94
125
  #: admin/constants.php:110 classes/class-email-service.php:60
126
+ #: releases/svn/admin/constants.php:14 releases/svn/admin/constants.php:30
127
+ #: releases/svn/admin/constants.php:46 releases/svn/admin/constants.php:62
128
+ #: releases/svn/admin/constants.php:78 releases/svn/admin/constants.php:94
129
+ #: releases/svn/admin/constants.php:110
130
+ #: releases/svn/classes/class-email-service.php:60
131
  msgid "You've set it to: %s"
132
  msgstr ""
133
 
134
+ #: admin/constants.php:17 releases/svn/admin/constants.php:17
135
  msgid ""
136
  "The path to folder you would like to store your backup files in, defaults "
137
  "to %s."
140
  #: admin/constants.php:17 admin/constants.php:33 admin/constants.php:49
141
  #: admin/constants.php:65 admin/constants.php:81 admin/constants.php:97
142
  #: admin/constants.php:113 classes/class-email-service.php:63
143
+ #: releases/svn/admin/constants.php:17 releases/svn/admin/constants.php:33
144
+ #: releases/svn/admin/constants.php:49 releases/svn/admin/constants.php:65
145
+ #: releases/svn/admin/constants.php:81 releases/svn/admin/constants.php:97
146
+ #: releases/svn/admin/constants.php:113
147
+ #: releases/svn/classes/class-email-service.php:63
148
  msgid "e.g."
149
  msgstr ""
150
 
151
+ #: admin/constants.php:33 releases/svn/admin/constants.php:33
152
  msgid ""
153
  "The path to your %1$s executable. Will be used for the %2$s part of the "
154
  "back up if available."
155
  msgstr ""
156
 
157
  #: admin/constants.php:33 admin/constants.php:49
158
+ #: releases/svn/admin/constants.php:33 releases/svn/admin/constants.php:49
159
  msgid "database"
160
  msgstr ""
161
 
162
+ #: admin/constants.php:49 releases/svn/admin/constants.php:49
163
  msgid ""
164
  "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
165
  "if available."
166
  msgstr ""
167
 
168
+ #: admin/constants.php:49 releases/svn/admin/constants.php:49
169
  msgid "files"
170
  msgstr ""
171
 
172
+ #: admin/constants.php:65 releases/svn/admin/constants.php:65
173
  msgid ""
174
  "Comma separated list of files or directories to exclude, the backups "
175
  "directory is automatically excluded."
176
  msgstr ""
177
 
178
+ #: admin/constants.php:81 releases/svn/admin/constants.php:81
179
  msgid "The capability to use when calling %1$s. Defaults to %2$s."
180
  msgstr ""
181
 
182
+ #: admin/constants.php:97 releases/svn/admin/constants.php:97
183
  msgid "The root directory that is backed up. Defaults to %s."
184
  msgstr ""
185
 
186
+ #: admin/constants.php:113 releases/svn/admin/constants.php:113
187
  msgid "The time that your schedules should run. Defaults to %s."
188
  msgstr ""
189
 
190
+ #: admin/enable-support.php:3 releases/svn/admin/enable-support.php:3
191
  msgid "Enable BackUpWordPress Support"
192
  msgstr ""
193
 
194
+ #: admin/enable-support.php:5 releases/svn/admin/enable-support.php:5
195
  msgid ""
196
  "BackUpWordPress uses %s to provide support. In addition to allowing you to "
197
  "send and receive messages we also send the following server information "
198
  "along with your requests:"
199
  msgstr ""
200
 
201
+ #: admin/enable-support.php:58 releases/svn/admin/enable-support.php:58
202
  msgid "You can disable support in the future by deactivating BackUpWordPress."
203
  msgstr ""
204
 
205
+ #: admin/enable-support.php:60 releases/svn/admin/enable-support.php:60
206
+ msgid "No, thanks"
207
  msgstr ""
208
 
209
+ #: admin/enable-support.php:61 releases/svn/admin/enable-support.php:61
210
+ msgid "Yes, I want to enable support"
211
  msgstr ""
212
 
213
+ #: admin/faq.php:2 releases/svn/admin/faq.php:2
214
  msgid "Where does BackUpWordPress store the backup files?"
215
  msgstr ""
216
 
217
+ #: admin/faq.php:4 releases/svn/admin/faq.php:4
218
  msgid ""
219
  "Backups are stored on your server in <code>/wp-content/backups</code>, you "
220
  "can change the directory."
221
  msgstr ""
222
 
223
+ #: admin/faq.php:6 releases/svn/admin/faq.php:6
224
  msgid ""
225
  "Important: By default BackUpWordPress backs up everything in your site root "
226
  "as well as your database, this includes any non WordPress folders that "
228
  "can get quite large."
229
  msgstr ""
230
 
231
+ #: admin/faq.php:8 releases/svn/admin/faq.php:8
232
  msgid "What if I want to back up my site to another destination?"
233
  msgstr ""
234
 
235
+ #: admin/faq.php:10 releases/svn/admin/faq.php:10
236
  msgid ""
237
  "BackUpWordPress Pro supports Dropbox, Google Drive, Amazon S3, Rackspace, "
238
  "Azure, DreamObjects and FTP/SFTP. Check it out here: <a "
241
  "target=\"_blank\">https://bwp.hmn.md</a>"
242
  msgstr ""
243
 
244
+ #: admin/faq.php:12 releases/svn/admin/faq.php:12
245
  msgid "How do I restore my site from a backup?"
246
  msgstr ""
247
 
248
+ #: admin/faq.php:14 releases/svn/admin/faq.php:14
249
  msgid ""
250
  "You need to download the latest backup file either by clicking download on "
251
  "the backups page or via <code>FTP</code>. <code>Unzip</code> the files and "
254
  "<code>phpMyAdmin</code>)."
255
  msgstr ""
256
 
257
+ #: admin/faq.php:16 releases/svn/admin/faq.php:16
258
  msgid ""
259
  "See this guide for more details - <a "
260
  "href=\"https://bwp.hmn.md/support-center/restore-backup/\" title=\"Go to "
261
  "support center\" target=\"_blank\">How to restore from backup</a>."
262
  msgstr ""
263
 
264
+ #: admin/faq.php:18 releases/svn/admin/faq.php:18
265
  msgid "Does BackUpWordPress back up the backups directory?"
266
  msgstr ""
267
 
268
+ #: admin/faq.php:20 releases/svn/admin/faq.php:20
269
  msgid "No."
270
  msgstr ""
271
 
272
+ #: admin/faq.php:22 releases/svn/admin/faq.php:22
273
+ msgid "I'm not receiving my backups by email"
274
  msgstr ""
275
 
276
+ #: admin/faq.php:24 releases/svn/admin/faq.php:24
277
  msgid ""
278
  "Most servers have a filesize limit on email attachments, it's generally "
279
  "about 10mb. If your backup file is over that limit it won't be sent "
282
  "a mail issue on your server that you'll need to contact your host about."
283
  msgstr ""
284
 
285
+ #: admin/faq.php:26 releases/svn/admin/faq.php:26
286
  msgid "How many backups are stored by default?"
287
  msgstr ""
288
 
289
+ #: admin/faq.php:28 releases/svn/admin/faq.php:28
290
  msgid "BackUpWordPress stores the last 10 backups by default."
291
  msgstr ""
292
 
293
+ #: admin/faq.php:30 releases/svn/admin/faq.php:30
294
  msgid "How long should a backup take?"
295
  msgstr ""
296
 
297
+ #: admin/faq.php:32 releases/svn/admin/faq.php:32
298
  msgid ""
299
  "Unless your site is very large (many gigabytes) it should only take a few "
300
  "minutes to perform a back up, if your back up has been running for longer "
303
  "support."
304
  msgstr ""
305
 
306
+ #: admin/faq.php:34 releases/svn/admin/faq.php:34
307
  msgid "What do I do if I get the wp-cron error message?"
308
  msgstr ""
309
 
310
+ #: admin/faq.php:36 releases/svn/admin/faq.php:36
311
  msgid ""
312
  "The issue is that your <code>wp-cron.php</code> is not returning a "
313
  "<code>200</code> response when hit with a HTTP request originating from "
315
  "with the server / site."
316
  msgstr ""
317
 
318
+ #: admin/faq.php:38 releases/svn/admin/faq.php:38
319
  msgid "There are some things you can test to confirm this is the issue."
320
  msgstr ""
321
 
322
+ #: admin/faq.php:40 releases/svn/admin/faq.php:40
323
+ msgid "Are scheduled posts working? (They use wp-cron as well.)"
324
  msgstr ""
325
 
326
+ #: admin/faq.php:42 releases/svn/admin/faq.php:42
327
  msgid ""
328
  "Are you hosted on Heart Internet? (wp-cron may not be supported by Heart "
329
+ "Internet, see below for work-around.)"
330
  msgstr ""
331
 
332
+ #: admin/faq.php:44 releases/svn/admin/faq.php:44
333
  msgid "If you click manual backup does it work?"
334
  msgstr ""
335
 
336
+ #: admin/faq.php:46 releases/svn/admin/faq.php:46
337
  msgid ""
338
  "Try adding <code>define( 'ALTERNATE_WP_CRON', true );</code> to your "
339
  "<code>wp-config.php</code>, do automatic backups work?"
340
  msgstr ""
341
 
342
+ #: admin/faq.php:48 releases/svn/admin/faq.php:48
343
  msgid ""
344
+ "Is your site private (i.e. is it behind some kind of authentication, "
345
+ "maintenance plugin, .htaccess)? If so wp-cron won't work until you remove "
346
+ "it. If you are and you temporarily remove the authentication, do backups "
347
  "start working?"
348
  msgstr ""
349
 
350
+ #: admin/faq.php:50 releases/svn/admin/faq.php:50
351
  msgid ""
352
  "Report the results to our support team for further help. To do this, either "
353
  "enable suport from your Admin Dashboard (recommended), or email "
354
  "backupwordpress@hmn.md"
355
  msgstr ""
356
 
357
+ #: admin/faq.php:52 releases/svn/admin/faq.php:52
358
  msgid "How to get BackUpWordPress working in Heart Internet"
359
  msgstr ""
360
 
361
+ #: admin/faq.php:54 releases/svn/admin/faq.php:54
362
  msgid ""
363
  "The script to be entered into the Heart Internet cPanel is: "
364
  "<code>/usr/bin/php5 "
367
  "<code>wp-cron.php</code> <code>chmod</code> must be set to <code>711</code>."
368
  msgstr ""
369
 
370
+ #: admin/faq.php:56 releases/svn/admin/faq.php:56
371
  msgid "My backups seem to be failing?"
372
  msgstr ""
373
 
374
+ #: admin/faq.php:58 releases/svn/admin/faq.php:58
375
  msgid ""
376
+ "If your backups are failing, it's commonly caused by a lack of available "
377
+ "resources on your server. The easiest way to establish this is to exclude "
378
+ "some of, or the entirety of your uploads folder, running a backup, and if "
379
+ "that succeeds, then you'll know it's probably a server issue. If not, "
380
+ "report the results to our support team for further help. To do this, either "
381
+ "enable support from your Admin Dashboard (recommended), or email "
382
+ "backupwordpress@hmn.md"
383
  msgstr ""
384
 
385
+ #: admin/menu.php:13 admin/menu.php:17 releases/svn/admin/menu.php:13
386
+ #: releases/svn/admin/menu.php:17
387
  msgid "Manage Backups"
388
  msgstr ""
389
 
390
  #: admin/menu.php:13 admin/menu.php:17 admin/menu.php:46
391
+ #: releases/svn/admin/menu.php:13 releases/svn/admin/menu.php:17
392
+ #: releases/svn/admin/menu.php:46
393
  msgid "Backups"
394
  msgstr ""
395
 
396
+ #: admin/menu.php:77 releases/svn/admin/menu.php:77
397
  msgid "FAQ"
398
  msgstr ""
399
 
400
+ #: admin/menu.php:95 releases/svn/admin/menu.php:95
401
  msgid "Server Info"
402
  msgstr ""
403
 
404
+ #: admin/menu.php:102 releases/svn/admin/menu.php:102
405
  msgid "For more information:"
406
  msgstr ""
407
 
408
+ #: admin/menu.php:102 releases/svn/admin/menu.php:102
409
  msgid "Support Forums"
410
  msgstr ""
411
 
412
+ #: admin/menu.php:102 releases/svn/admin/menu.php:102
413
  msgid "Help with translation"
414
  msgstr ""
415
 
416
+ #: admin/page.php:7 releases/svn/admin/page.php:7
417
+ msgid "Support"
418
+ msgstr ""
419
+
420
+ #: admin/page.php:10 releases/svn/admin/page.php:10
421
+ msgid "Enable Support"
422
+ msgstr ""
423
+
424
+ #: admin/page.php:19 releases/svn/admin/page.php:19
425
  msgid ""
426
  "If you're finding BackUpWordPress useful, please %1$s rate it on the plugin "
427
  "directory%2$s."
428
  msgstr ""
429
 
430
  #: admin/schedule-form-excludes.php:6
431
+ #: releases/svn/admin/schedule-form-excludes.php:6
432
  msgid "Currently Excluded"
433
  msgstr ""
434
 
435
  #: admin/schedule-form-excludes.php:9
436
+ #: releases/svn/admin/schedule-form-excludes.php:9
437
  msgid ""
438
  "We automatically detect and ignore common <abbr title=\"Version Control "
439
  "Systems\">VCS</abbr> folders and other backup plugin folders."
440
  msgstr ""
441
 
442
  #: admin/schedule-form-excludes.php:44
443
+ #: releases/svn/admin/schedule-form-excludes.php:44
444
  msgid "Default rule"
445
  msgstr ""
446
 
447
  #: admin/schedule-form-excludes.php:48
448
+ #: releases/svn/admin/schedule-form-excludes.php:48
449
  msgid "Defined in wp-config.php"
450
  msgstr ""
451
 
452
  #: admin/schedule-form-excludes.php:55
453
+ #: releases/svn/admin/schedule-form-excludes.php:55
454
  msgid "Stop excluding"
455
  msgstr ""
456
 
457
  #: admin/schedule-form-excludes.php:71
458
+ #: releases/svn/admin/schedule-form-excludes.php:71
459
+ msgid "Your Site"
460
  msgstr ""
461
 
462
  #: admin/schedule-form-excludes.php:73
463
+ #: releases/svn/admin/schedule-form-excludes.php:73
464
  msgid ""
465
  "Here's a directory listing of all files on your site, you can browse "
466
  "through and exclude files or folders that you don't want included in your "
467
  "backup."
468
  msgstr ""
469
 
470
+ #: admin/schedule-form-excludes.php:102
471
+ #: releases/svn/admin/schedule-form-excludes.php:102
472
  msgid "Name"
473
  msgstr ""
474
 
475
+ #: admin/schedule-form-excludes.php:104
476
+ #: releases/svn/admin/schedule-form-excludes.php:104
477
  msgid "Permissions"
478
  msgstr ""
479
 
480
+ #: admin/schedule-form-excludes.php:106
481
+ #: releases/svn/admin/schedule-form-excludes.php:106
482
  msgid "Status"
483
  msgstr ""
484
 
485
+ #: admin/schedule-form-excludes.php:166 admin/schedule-form-excludes.php:284
486
+ #: releases/svn/admin/schedule-form-excludes.php:166
487
+ #: releases/svn/admin/schedule-form-excludes.php:284
488
  msgid "Refresh"
489
  msgstr ""
490
 
491
+ #: admin/schedule-form-excludes.php:183 admin/schedule-form-excludes.php:308
492
+ #: releases/svn/admin/schedule-form-excludes.php:183
493
+ #: releases/svn/admin/schedule-form-excludes.php:308
494
  msgid "Symlink"
495
  msgstr ""
496
 
497
+ #: admin/schedule-form-excludes.php:187 admin/schedule-form-excludes.php:312
498
+ #: releases/svn/admin/schedule-form-excludes.php:187
499
+ #: releases/svn/admin/schedule-form-excludes.php:312
500
  msgid "Folder"
501
  msgstr ""
502
 
503
  #: admin/schedule-form-excludes.php:282
504
+ #: releases/svn/admin/schedule-form-excludes.php:282
505
  msgid "Recalculate the size of this directory"
506
  msgstr ""
507
 
508
  #: admin/schedule-form-excludes.php:316
509
+ #: releases/svn/admin/schedule-form-excludes.php:316
510
  msgid "File"
511
  msgstr ""
512
 
513
  #: admin/schedule-form-excludes.php:327
514
+ #: releases/svn/admin/schedule-form-excludes.php:327
515
  msgid "Unreadable files won't be backed up."
516
  msgstr ""
517
 
518
  #: admin/schedule-form-excludes.php:327
519
+ #: releases/svn/admin/schedule-form-excludes.php:327
520
  msgid "Unreadable"
521
  msgstr ""
522
 
523
  #: admin/schedule-form-excludes.php:331
524
+ #: releases/svn/admin/schedule-form-excludes.php:331
525
  msgid "Excluded"
526
  msgstr ""
527
 
528
  #: admin/schedule-form-excludes.php:347
529
+ #: releases/svn/admin/schedule-form-excludes.php:347
530
  msgid "Exclude &rarr;"
531
  msgstr ""
532
 
533
+ #: admin/schedule-form-excludes.php:360
534
+ #: releases/svn/admin/schedule-form-excludes.php:360
535
+ msgid "This folder is empty"
536
+ msgstr ""
537
+
538
+ #: admin/schedule-form-excludes.php:372 admin/schedule-form.php:195
539
  #: admin/schedule-settings.php:88
540
+ #: releases/svn/admin/schedule-form-excludes.php:372
541
+ #: releases/svn/admin/schedule-form.php:195
542
+ #: releases/svn/admin/schedule-settings.php:88
543
  msgid "Done"
544
  msgstr ""
545
 
546
  #: admin/schedule-form.php:1 admin/schedule-settings.php:9
547
+ #: releases/svn/admin/schedule-form.php:1
548
+ #: releases/svn/admin/schedule-settings.php:9
549
  msgid "Settings"
550
  msgstr ""
551
 
552
+ #: admin/schedule-form.php:36 releases/svn/admin/schedule-form.php:36
553
  msgid "Backup"
554
  msgstr ""
555
 
556
+ #: admin/schedule-form.php:43 releases/svn/admin/schedule-form.php:43
557
  msgid "Both Database &amp; files"
558
  msgstr ""
559
 
560
+ #: admin/schedule-form.php:45 releases/svn/admin/schedule-form.php:45
561
  msgid "Files only"
562
  msgstr ""
563
 
564
+ #: admin/schedule-form.php:47 releases/svn/admin/schedule-form.php:47
565
  msgid "Database only"
566
  msgstr ""
567
 
568
+ #: admin/schedule-form.php:58 releases/svn/admin/schedule-form.php:58
569
  msgid "Schedule"
570
  msgstr ""
571
 
572
+ #: admin/schedule-form.php:65 releases/svn/admin/schedule-form.php:65
573
  msgid "Manual Only"
574
  msgstr ""
575
 
576
+ #: admin/schedule-form.php:92 releases/svn/admin/schedule-form.php:92
577
  msgid "Start Day"
578
  msgstr ""
579
 
580
+ #: admin/schedule-form.php:100 releases/svn/admin/schedule-form.php:100
581
  msgid "Monday"
582
  msgstr ""
583
 
584
+ #: admin/schedule-form.php:101 releases/svn/admin/schedule-form.php:101
585
  msgid "Tuesday"
586
  msgstr ""
587
 
588
+ #: admin/schedule-form.php:102 releases/svn/admin/schedule-form.php:102
589
  msgid "Wednesday"
590
  msgstr ""
591
 
592
+ #: admin/schedule-form.php:103 releases/svn/admin/schedule-form.php:103
593
  msgid "Thursday"
594
  msgstr ""
595
 
596
+ #: admin/schedule-form.php:104 releases/svn/admin/schedule-form.php:104
597
  msgid "Friday"
598
  msgstr ""
599
 
600
+ #: admin/schedule-form.php:105 releases/svn/admin/schedule-form.php:105
601
  msgid "Saturday"
602
  msgstr ""
603
 
604
+ #: admin/schedule-form.php:106 releases/svn/admin/schedule-form.php:106
605
  msgid "Sunday"
606
  msgstr ""
607
 
608
+ #: admin/schedule-form.php:124 releases/svn/admin/schedule-form.php:124
609
  msgid "Start Day of Month"
610
  msgstr ""
611
 
612
+ #: admin/schedule-form.php:136 releases/svn/admin/schedule-form.php:136
613
  msgid "Start Time"
614
  msgstr ""
615
 
616
+ #: admin/schedule-form.php:145 releases/svn/admin/schedule-form.php:145
617
  msgid "Hours"
618
  msgstr ""
619
 
620
+ #: admin/schedule-form.php:149 releases/svn/admin/schedule-form.php:149
621
  msgid "Minutes"
622
  msgstr ""
623
 
624
+ #: admin/schedule-form.php:154 releases/svn/admin/schedule-form.php:154
625
+ msgid "24-hour format."
626
  msgstr ""
627
 
628
+ #: admin/schedule-form.php:155 releases/svn/admin/schedule-form.php:155
629
+ msgid "The second backup will run 12 hours after the first."
630
  msgstr ""
631
 
632
+ #: admin/schedule-form.php:165 releases/svn/admin/schedule-form.php:165
633
  msgid "Number of backups to store on this server"
634
  msgstr ""
635
 
636
+ #: admin/schedule-form.php:174 releases/svn/admin/schedule-form.php:174
637
  msgid "Past this limit older backups will be deleted automatically."
638
  msgstr ""
639
 
640
+ #: admin/schedule-form.php:177 releases/svn/admin/schedule-form.php:177
641
  msgid "This schedule will store a maximum of %s of backups."
642
  msgstr ""
643
 
644
+ #: admin/schedule-sentence.php:11 releases/svn/admin/schedule-sentence.php:11
645
  msgid "The next backup will be on %1$s at %2$s %3$s"
646
  msgstr ""
647
 
648
+ #: admin/schedule-sentence.php:18 releases/svn/admin/schedule-sentence.php:18
649
  msgid "hourly on the hour"
650
  msgstr ""
651
 
652
+ #: admin/schedule-sentence.php:18 releases/svn/admin/schedule-sentence.php:18
653
  msgid "hourly at %s minutes past the hour"
654
  msgstr ""
655
 
656
+ #: admin/schedule-sentence.php:24 releases/svn/admin/schedule-sentence.php:24
657
  msgid "daily at %s"
658
  msgstr ""
659
 
660
+ #: admin/schedule-sentence.php:35 releases/svn/admin/schedule-sentence.php:35
661
  msgid "every 12 hours at %1$s &amp; %2$s"
662
  msgstr ""
663
 
664
+ #: admin/schedule-sentence.php:41 releases/svn/admin/schedule-sentence.php:41
665
  msgid "weekly on %1$s at %2$s"
666
  msgstr ""
667
 
668
+ #: admin/schedule-sentence.php:47 releases/svn/admin/schedule-sentence.php:47
669
+ msgid "every two weeks on %1$s at %2$s"
670
  msgstr ""
671
 
672
+ #: admin/schedule-sentence.php:53 releases/svn/admin/schedule-sentence.php:53
673
  msgid "on the %1$s of each month at %2$s"
674
  msgstr ""
675
 
676
  #: admin/schedule-sentence.php:59 admin/schedule-sentence.php:65
677
+ #: releases/svn/admin/schedule-sentence.php:59
678
+ #: releases/svn/admin/schedule-sentence.php:65
679
  msgid "manually"
680
  msgstr ""
681
 
682
+ #: admin/schedule-sentence.php:70 releases/svn/admin/schedule-sentence.php:70
683
  msgid "this server"
684
  msgstr ""
685
 
686
+ #: admin/schedule-sentence.php:78 releases/svn/admin/schedule-sentence.php:78
687
  msgid "store the most recent backup in %s"
688
  msgstr ""
689
 
690
+ #: admin/schedule-sentence.php:84 releases/svn/admin/schedule-sentence.php:84
691
  msgid "don't store any backups in on this server"
692
  msgstr ""
693
 
694
+ #: admin/schedule-sentence.php:90 releases/svn/admin/schedule-sentence.php:90
695
  msgid "store the last %1$s backups in %2$s"
696
  msgstr ""
697
 
698
+ #: admin/schedule-sentence.php:121 releases/svn/admin/schedule-sentence.php:121
699
  msgid "%s. "
700
  msgstr ""
701
 
702
+ #: admin/schedule-sentence.php:125 releases/svn/admin/schedule-sentence.php:125
703
  msgid "Send a copy of each backup to %s."
704
  msgstr ""
705
 
706
+ #: admin/schedule-sentence.php:156 releases/svn/admin/schedule-sentence.php:156
707
  msgid "Backups will be compressed and should be smaller than this."
708
  msgstr ""
709
 
710
+ #: admin/schedule-sentence.php:160 releases/svn/admin/schedule-sentence.php:160
711
  msgid "this shouldn't take long&hellip;"
712
  msgstr ""
713
 
714
+ #: admin/schedule-sentence.php:160 releases/svn/admin/schedule-sentence.php:160
715
  msgid "calculating the size of your backup&hellip;"
716
  msgstr ""
717
 
718
+ #: admin/schedule-settings.php:7 releases/svn/admin/schedule-settings.php:7
719
  msgid "Run now"
720
  msgstr ""
721
 
722
+ #: admin/schedule-settings.php:15 releases/svn/admin/schedule-settings.php:15
723
  msgid "Excludes"
724
  msgstr ""
725
 
726
  #: admin/schedule-settings.php:27 functions/interface.php:34
727
+ #: releases/svn/admin/schedule-settings.php:27
728
+ #: releases/svn/functions/interface.php:34
729
  msgid "Delete"
730
  msgstr ""
731
 
732
+ #: admin/upsell.php:3 releases/svn/admin/upsell.php:3
 
 
 
 
733
  msgid "Backup to"
734
  msgstr ""
735
 
736
+ #: admin/upsell.php:18 releases/svn/admin/upsell.php:18
737
  msgid ""
738
  "%1$sor buy the %2$sDeveloper Bundle%3$s now for only &dollar;99 (all "
739
  "Destinations &amp; Unlimited Sites)%4$s"
740
  msgstr ""
741
 
742
+ #: backupwordpress.php:53 releases/svn/backupwordpress.php:53
743
+ msgid "BackUpWordPress will not work on this site: PHP Version %s is unsupported."
 
 
744
  msgstr ""
745
 
746
+ #: backupwordpress.php:53 releases/svn/backupwordpress.php:53
747
  msgid "BackUpWordPress Error"
748
  msgstr ""
749
 
750
+ #: classes/class-backup.php:347 releases/svn/classes/class-backup.php:347
751
+ msgid "archive filename must be a non-empty string"
752
  msgstr ""
753
 
754
+ #: classes/class-backup.php:351 releases/svn/classes/class-backup.php:351
755
  msgid "invalid file extension for archive filename <code>%s</code>"
756
  msgstr ""
757
 
758
+ #: classes/class-backup.php:392 releases/svn/classes/class-backup.php:392
759
+ msgid "database dump filename must be a non-empty string"
760
  msgstr ""
761
 
762
+ #: classes/class-backup.php:396 releases/svn/classes/class-backup.php:396
763
  msgid "invalid file extension for database dump filename <code>%s</code>"
764
  msgstr ""
765
 
766
+ #: classes/class-backup.php:430 releases/svn/classes/class-backup.php:430
767
  msgid "Invalid root path <code>%s</code> must be a valid directory path"
768
  msgstr ""
769
 
770
+ #: classes/class-backup.php:456 releases/svn/classes/class-backup.php:456
771
  msgid ""
772
+ "Invalid existing archive filepath <code>%s</code> must be a non-empty "
773
  "(string)"
774
  msgstr ""
775
 
776
+ #: classes/class-backup.php:511 releases/svn/classes/class-backup.php:511
777
  msgid ""
778
  "Invalid backup type <code>%s</code> must be one of (string) file, database "
779
  "or complete"
780
  msgstr ""
781
 
782
+ #: classes/class-backup.php:918 releases/svn/classes/class-backup.php:918
783
+ msgid "Zip command is not available."
784
+ msgstr ""
785
+
786
+ #: classes/class-backup.php:925 releases/svn/classes/class-backup.php:925
787
+ msgid "ZipArchive method is not available."
788
+ msgstr ""
789
+
790
+ #: classes/class-backup.php:929 classes/class-backup.php:942
791
+ #: releases/svn/classes/class-backup.php:929
792
+ #: releases/svn/classes/class-backup.php:942
793
+ msgid "No valid archive method found."
794
+ msgstr ""
795
+
796
+ #: classes/class-backup.php:1850 releases/svn/classes/class-backup.php:1850
797
  msgid "Could not connect to mysql"
798
  msgstr ""
799
 
800
  #: classes/class-backupwordpress-wp-cli-command.php:50
801
+ #: releases/svn/classes/class-backupwordpress-wp-cli-command.php:50
802
  msgid "Backup: Dumping database..."
803
  msgstr ""
804
 
805
  #: classes/class-backupwordpress-wp-cli-command.php:54
806
+ #: releases/svn/classes/class-backupwordpress-wp-cli-command.php:54
807
  msgid "Backup: Zipping everything up..."
808
  msgstr ""
809
 
810
  #: classes/class-backupwordpress-wp-cli-command.php:70
811
+ #: releases/svn/classes/class-backupwordpress-wp-cli-command.php:70
812
  msgid "Invalid backup path"
813
  msgstr ""
814
 
815
  #: classes/class-backupwordpress-wp-cli-command.php:75
816
+ #: releases/svn/classes/class-backupwordpress-wp-cli-command.php:75
817
  msgid "Invalid root path"
818
  msgstr ""
819
 
820
  #: classes/class-backupwordpress-wp-cli-command.php:106
821
+ #: releases/svn/classes/class-backupwordpress-wp-cli-command.php:106
822
  msgid "Backup Complete: "
823
  msgstr ""
824
 
825
  #: classes/class-backupwordpress-wp-cli-command.php:108
826
+ #: releases/svn/classes/class-backupwordpress-wp-cli-command.php:108
827
  msgid "Backup Failed"
828
  msgstr ""
829
 
830
  #: classes/class-email-service.php:28
831
+ #: releases/svn/classes/class-email-service.php:28
832
  msgid "Email notification"
833
  msgstr ""
834
 
835
  #: classes/class-email-service.php:34
836
+ #: releases/svn/classes/class-email-service.php:34
837
  msgid ""
838
+ "Receive a notification email when a backup completes. If the backup is "
839
+ "small enough (&lt; %s), then it will be attached to the email. Separate "
840
  "multiple email addresses with a comma."
841
  msgstr ""
842
 
843
  #: classes/class-email-service.php:63
844
+ #: releases/svn/classes/class-email-service.php:63
845
  msgid ""
846
  "The maximum filesize of your backup that will be attached to your "
847
  "notification emails . Defaults to %s."
848
  msgstr ""
849
 
850
  #: classes/class-email-service.php:82
851
+ #: releases/svn/classes/class-email-service.php:82
852
  msgid "Send an email notification to %s"
853
  msgstr ""
854
 
855
  #: classes/class-email-service.php:117
856
+ #: releases/svn/classes/class-email-service.php:117
857
  msgid "%s isn't a valid email"
858
  msgstr ""
859
 
860
  #: classes/class-email-service.php:179 classes/class-webhook-service.php:59
861
+ #: releases/svn/classes/class-email-service.php:179
862
+ #: releases/svn/classes/class-webhook-service.php:59
863
  msgid "Backup of %s Failed"
864
  msgstr ""
865
 
866
  #: classes/class-email-service.php:181
867
+ #: releases/svn/classes/class-email-service.php:181
868
  msgid "BackUpWordPress was unable to backup your site %1$s."
869
  msgstr ""
870
 
871
  #: classes/class-email-service.php:181
872
+ #: releases/svn/classes/class-email-service.php:181
873
  msgid "Here are the errors that we're encountered:"
874
  msgstr ""
875
 
876
  #: classes/class-email-service.php:181
877
+ #: releases/svn/classes/class-email-service.php:181
878
  msgid ""
879
  "If the errors above look like Martian, forward this email to %3$s and we'll "
880
  "take a look"
881
  msgstr ""
882
 
883
  #: classes/class-email-service.php:181
884
+ #: releases/svn/classes/class-email-service.php:181
885
  msgid ""
886
  "Kind Regards,\n"
887
  "The Apologetic BackUpWordPress Backup Emailing Robot"
888
  msgstr ""
889
 
890
  #: classes/class-email-service.php:189
891
+ #: releases/svn/classes/class-email-service.php:189
892
  msgid "Backup of %s"
893
  msgstr ""
894
 
895
  #: classes/class-email-service.php:194 classes/class-email-service.php:203
896
+ #: releases/svn/classes/class-email-service.php:194
897
+ #: releases/svn/classes/class-email-service.php:203
898
  msgid "BackUpWordPress has completed a backup of your site %1$s."
899
  msgstr ""
900
 
901
  #: classes/class-email-service.php:194
902
+ #: releases/svn/classes/class-email-service.php:194
903
  msgid "The backup file should be attached to this email."
904
  msgstr ""
905
 
906
  #: classes/class-email-service.php:194 classes/class-email-service.php:203
907
+ #: releases/svn/classes/class-email-service.php:194
908
+ #: releases/svn/classes/class-email-service.php:203
909
  msgid "You can download the backup file by clicking the link below:"
910
  msgstr ""
911
 
912
  #: classes/class-email-service.php:194 classes/class-email-service.php:203
913
+ #: releases/svn/classes/class-email-service.php:194
914
+ #: releases/svn/classes/class-email-service.php:203
915
  msgid ""
916
  "Kind Regards,\n"
917
  "The Happy BackUpWordPress Backup Emailing Robot"
918
  msgstr ""
919
 
920
  #: classes/class-email-service.php:203
921
+ #: releases/svn/classes/class-email-service.php:203
922
  msgid "Unfortunately the backup file was too large to attach to this email."
923
  msgstr ""
924
 
925
+ #: classes/class-path.php:249 releases/svn/classes/class-path.php:249
926
  msgid "This %s file ensures that other people cannot download your backup files."
927
  msgstr ""
928
 
929
+ #: classes/class-plugin.php:214 releases/svn/classes/class-plugin.php:214
930
  msgid "Update"
931
  msgstr ""
932
 
933
+ #: classes/class-plugin.php:215 releases/svn/classes/class-plugin.php:215
934
  msgid "Cancel"
935
  msgstr ""
936
 
937
+ #: classes/class-plugin.php:216 releases/svn/classes/class-plugin.php:216
938
  msgid ""
939
+ "Are you sure you want to delete this schedule? All of its backups will also "
940
+ "be deleted."
941
  msgstr ""
942
 
943
  #: classes/class-plugin.php:216 classes/class-plugin.php:217
944
  #: classes/class-plugin.php:218 classes/class-plugin.php:219
945
+ #: releases/svn/classes/class-plugin.php:216
946
+ #: releases/svn/classes/class-plugin.php:217
947
+ #: releases/svn/classes/class-plugin.php:218
948
+ #: releases/svn/classes/class-plugin.php:219
949
  msgid "'Cancel' to go back, 'OK' to delete."
950
  msgstr ""
951
 
952
+ #: classes/class-plugin.php:217 releases/svn/classes/class-plugin.php:217
953
  msgid "Are you sure you want to delete this backup?"
954
  msgstr ""
955
 
956
+ #: classes/class-plugin.php:218 releases/svn/classes/class-plugin.php:218
957
  msgid "Are you sure you want to remove this exclude rule?"
958
  msgstr ""
959
 
960
+ #: classes/class-plugin.php:219 releases/svn/classes/class-plugin.php:219
961
  msgid ""
962
  "Reducing the number of backups that are stored on this server will cause "
963
+ "some of your existing backups to be deleted. Are you sure that's what you "
964
  "want?"
965
  msgstr ""
966
 
967
+ #: classes/class-schedule.php:150 releases/svn/classes/class-schedule.php:150
968
  msgid "Invalid Option Name"
969
  msgstr ""
970
 
971
+ #: classes/class-schedule.php:261 releases/svn/classes/class-schedule.php:261
972
  msgid "Argument 1 for %s must be a valid integer"
973
  msgstr ""
974
 
975
+ #: classes/class-schedule.php:613 releases/svn/classes/class-schedule.php:613
976
  msgid "Argument 1 for %s must be a valid future timestamp"
977
  msgstr ""
978
 
979
+ #: classes/class-schedule.php:650 releases/svn/classes/class-schedule.php:650
980
  msgid "Argument 1 for %s must be a valid cron reoccurrence or \"manually\""
981
  msgstr ""
982
 
983
+ #: classes/class-schedule.php:769 functions/interface.php:293
984
+ #: releases/svn/classes/class-schedule.php:769
985
+ #: releases/svn/functions/interface.php:293
986
  msgid "Starting Backup"
987
  msgstr ""
988
 
989
+ #: classes/class-schedule.php:856 releases/svn/classes/class-schedule.php:856
990
  msgid "Error writing to file. (%s)"
991
  msgstr ""
992
 
993
+ #: classes/class-schedule.php:907 releases/svn/classes/class-schedule.php:907
994
  msgid "Dumping Database %s"
995
  msgstr ""
996
 
997
+ #: classes/class-schedule.php:912 releases/svn/classes/class-schedule.php:912
998
  msgid "Verifying Database Dump %s"
999
  msgstr ""
1000
 
1001
+ #: classes/class-schedule.php:917 releases/svn/classes/class-schedule.php:917
1002
  msgid "Creating zip archive %s"
1003
  msgstr ""
1004
 
1005
+ #: classes/class-schedule.php:922 releases/svn/classes/class-schedule.php:922
1006
  msgid "Verifying Zip Archive %s"
1007
  msgstr ""
1008
 
1009
+ #: classes/class-schedule.php:927 releases/svn/classes/class-schedule.php:927
1010
  msgid "Finishing Backup"
1011
  msgstr ""
1012
 
1013
+ #: classes/class-schedule.php:978 releases/svn/classes/class-schedule.php:978
1014
  msgid "An unexpected error occured"
1015
  msgstr ""
1016
 
1017
+ #: classes/class-schedule.php:1041 releases/svn/classes/class-schedule.php:1041
1018
  #. translators: min=minute
1019
  msgid "%s min"
1020
  msgid_plural "%s mins"
1021
  msgstr[0] ""
1022
  msgstr[1] ""
1023
 
1024
+ #: classes/class-schedule.php:1051 releases/svn/classes/class-schedule.php:1051
1025
  msgid "%s hour"
1026
  msgid_plural "%s hours"
1027
  msgstr[0] ""
1028
  msgstr[1] ""
1029
 
1030
+ #: classes/class-schedule.php:1113 releases/svn/classes/class-schedule.php:1113
1031
+ msgid "Argument 1 for %s must be a non-empty string"
1032
  msgstr ""
1033
 
1034
+ #: classes/class-schedule.php:1118 releases/svn/classes/class-schedule.php:1118
1035
  msgid "%s doesn't exist"
1036
  msgstr ""
1037
 
1038
+ #: classes/class-schedule.php:1123 releases/svn/classes/class-schedule.php:1123
1039
  msgid "That backup wasn't created by this schedule"
1040
  msgstr ""
1041
 
1042
+ #: classes/class-services.php:80 releases/svn/classes/class-services.php:80
1043
  msgid "Argument 1 for %s must be a valid filepath"
1044
  msgstr ""
1045
 
1046
+ #: classes/class-services.php:96 releases/svn/classes/class-services.php:96
1047
  msgid "Argument 1 for %s must be a registered service"
1048
  msgstr ""
1049
 
1050
  #: classes/class-services.php:114 classes/deprecated.php:81
1051
+ #: releases/svn/classes/class-services.php:114
1052
+ #: releases/svn/classes/deprecated.php:81
1053
  msgid "Argument 1 for %s must be a valid class"
1054
  msgstr ""
1055
 
1057
  msgid "BackUpWordPress"
1058
  msgstr ""
1059
 
1060
+ #: classes/class-setup.php:170 releases/svn/classes/class-setup.php:170
1061
  msgid ""
1062
  "BackUpWordPress requires PHP version %1$s or later and WordPress version "
1063
  "%2$s or later to run. It has not been activated. %3$s%4$s%5$sLearn more%6$s"
1064
  msgstr ""
1065
 
1066
  #: classes/class-webhook-service.php:103
1067
+ #: releases/svn/classes/class-webhook-service.php:103
1068
  msgid "Error: %s"
1069
  msgstr ""
1070
 
1071
+ #: functions/core.php:326 releases/svn/functions/core.php:326
1072
+ msgid "BackUpWordPress has set up your default schedules."
1073
  msgstr ""
1074
 
1075
+ #: functions/core.php:326 releases/svn/functions/core.php:326
1076
  msgid ""
1077
  "By default BackUpWordPress performs a daily backup of your database and a "
1078
  "weekly backup of your database &amp; files. You can modify these schedules."
1079
  msgstr ""
1080
 
1081
+ #: functions/core.php:342 releases/svn/functions/core.php:342
1082
  msgid "Once Hourly"
1083
  msgstr ""
1084
 
1085
+ #: functions/core.php:343 releases/svn/functions/core.php:343
1086
  msgid "Twice Daily"
1087
  msgstr ""
1088
 
1089
+ #: functions/core.php:344 releases/svn/functions/core.php:344
1090
  msgid "Once Daily"
1091
  msgstr ""
1092
 
1093
+ #: functions/core.php:345 releases/svn/functions/core.php:345
1094
  msgid "Once Weekly"
1095
  msgstr ""
1096
 
1097
+ #: functions/core.php:346 releases/svn/functions/core.php:346
1098
+ msgid "Once Every Two Weeks"
1099
  msgstr ""
1100
 
1101
+ #: functions/core.php:347 releases/svn/functions/core.php:347
1102
  msgid "Once Monthly"
1103
  msgstr ""
1104
 
1105
+ #: functions/core.php:366 releases/svn/functions/core.php:366
1106
  msgid "You can only delete directories inside your WordPress installation"
1107
  msgstr ""
1108
 
1109
+ #: functions/interface.php:31 releases/svn/functions/interface.php:31
1110
  msgid "Download"
1111
  msgstr ""
1112
 
1113
+ #: functions/interface.php:73 releases/svn/functions/interface.php:73
1114
  msgid "BackUpWordPress detected issues with your last backup."
1115
  msgstr ""
1116
 
1117
+ #: functions/interface.php:75 releases/svn/functions/interface.php:75
1118
  msgid "Dismiss"
1119
  msgstr ""
1120
 
1121
+ #: functions/interface.php:89 functions/interface.php:109
1122
+ #: functions/interface.php:129 releases/svn/functions/interface.php:89
1123
+ #: releases/svn/functions/interface.php:109
1124
+ #: releases/svn/functions/interface.php:129
1125
+ msgid "Dismiss this notice."
1126
+ msgstr ""
1127
+
1128
+ #: functions/interface.php:162 releases/svn/functions/interface.php:162
1129
  msgid ""
1130
  "The backups directory can't be created because your %1$s directory isn't "
1131
+ "writable. Run %2$s or %3$s or create the folder yourself."
1132
  msgstr ""
1133
 
1134
+ #: functions/interface.php:166 releases/svn/functions/interface.php:166
1135
  msgid ""
1136
+ "Your backups directory isn't writable. Run %1$s or %2$s or set the "
1137
  "permissions yourself."
1138
  msgstr ""
1139
 
1140
+ #: functions/interface.php:170 releases/svn/functions/interface.php:170
1141
  msgid ""
1142
  "%1$s is running in %2$s, please contact your host and ask them to disable "
1143
  "it. BackUpWordPress may not work correctly whilst %3$s is on."
1144
  msgstr ""
1145
 
1146
+ #: functions/interface.php:170 releases/svn/functions/interface.php:170
1147
  msgid "http://php.net/manual/en/features.safe-mode.php"
1148
  msgstr ""
1149
 
1150
+ #: functions/interface.php:170 releases/svn/functions/interface.php:170
1151
  msgid "Safe Mode"
1152
  msgstr ""
1153
 
1154
+ #: functions/interface.php:178 releases/svn/functions/interface.php:178
1155
  msgid "Your custom path does not exist"
1156
  msgstr ""
1157
 
1158
+ #: functions/interface.php:182 releases/svn/functions/interface.php:182
1159
  msgid ""
1160
  "Your custom path is unreachable due to a restriction set in your PHP "
1161
  "configuration (open_basedir)"
1162
  msgstr ""
1163
 
1164
+ #: functions/interface.php:187 releases/svn/functions/interface.php:187
1165
  msgid ""
1166
  "Your custom backups directory %1$s doesn't exist and can't be created, your "
1167
  "backups will be saved to %2$s instead."
1168
  msgstr ""
1169
 
1170
+ #: functions/interface.php:191 releases/svn/functions/interface.php:191
1171
  msgid ""
1172
  "Your custom backups directory %1$s isn't writable, new backups will be "
1173
  "saved to %2$s instead."
1174
  msgstr ""
1175
 
1176
+ #: functions/interface.php:200 releases/svn/functions/interface.php:200
1177
  msgid "Your site root path %s isn't readable."
1178
  msgstr ""
1179
 
1180
+ #: functions/interface.php:262 releases/svn/functions/interface.php:262
1181
  msgid "Database and Files"
1182
  msgstr ""
1183
 
1184
+ #: functions/interface.php:266 releases/svn/functions/interface.php:266
1185
  msgid "Files"
1186
  msgstr ""
1187
 
1188
+ #: functions/interface.php:270 releases/svn/functions/interface.php:270
1189
  msgid "Database"
1190
  msgstr ""
1191
 
1192
+ #: functions/interface.php:277 releases/svn/functions/interface.php:277
1193
  msgid "Legacy"
1194
  msgstr ""
1195
 
1196
+ #: functions/interface.php:292 releases/svn/functions/interface.php:292
1197
  msgid "Started %s ago"
1198
  msgstr ""
1199
 
1200
+ #: functions/interface.php:294 releases/svn/functions/interface.php:294
1201
  msgid "cancel"
1202
  msgstr ""
1203
 
1204
+ #: functions/interface.php:342 releases/svn/functions/interface.php:342
1205
  msgid "No backups completed"
1206
  msgstr ""
1207
 
1208
+ #: functions/interface.php:353 releases/svn/functions/interface.php:353
1209
  msgid "Complete Hourly"
1210
  msgstr ""
1211
 
1212
+ #: functions/interface.php:354 releases/svn/functions/interface.php:354
1213
  msgid "File Hourly"
1214
  msgstr ""
1215
 
1216
+ #: functions/interface.php:355 releases/svn/functions/interface.php:355
1217
  msgid "Database Hourly"
1218
  msgstr ""
1219
 
1220
+ #: functions/interface.php:356 releases/svn/functions/interface.php:356
1221
+ msgid "Complete Twice Daily"
1222
  msgstr ""
1223
 
1224
+ #: functions/interface.php:357 releases/svn/functions/interface.php:357
1225
  msgid "File Twicedaily"
1226
  msgstr ""
1227
 
1228
+ #: functions/interface.php:358 releases/svn/functions/interface.php:358
1229
+ msgid "Database Twice Daily"
1230
  msgstr ""
1231
 
1232
+ #: functions/interface.php:359 releases/svn/functions/interface.php:359
1233
  msgid "Complete Daily"
1234
  msgstr ""
1235
 
1236
+ #: functions/interface.php:360 releases/svn/functions/interface.php:360
1237
  msgid "File Daily"
1238
  msgstr ""
1239
 
1240
+ #: functions/interface.php:361 releases/svn/functions/interface.php:361
1241
  msgid "Database Daily"
1242
  msgstr ""
1243
 
1244
+ #: functions/interface.php:362 releases/svn/functions/interface.php:362
1245
  msgid "Complete Weekly"
1246
  msgstr ""
1247
 
1248
+ #: functions/interface.php:363 releases/svn/functions/interface.php:363
1249
  msgid "File Weekly"
1250
  msgstr ""
1251
 
1252
+ #: functions/interface.php:364 releases/svn/functions/interface.php:364
1253
  msgid "Database Weekly"
1254
  msgstr ""
1255
 
1256
+ #: functions/interface.php:365 releases/svn/functions/interface.php:365
1257
+ msgid "Complete Every Two Weeks"
1258
  msgstr ""
1259
 
1260
+ #: functions/interface.php:366 releases/svn/functions/interface.php:366
1261
+ msgid "File Every Two Weeks"
1262
  msgstr ""
1263
 
1264
+ #: functions/interface.php:367 releases/svn/functions/interface.php:367
1265
+ msgid "Database Every Two Weeks"
1266
  msgstr ""
1267
 
1268
+ #: functions/interface.php:368 releases/svn/functions/interface.php:368
1269
  msgid "Complete Monthly"
1270
  msgstr ""
1271
 
1272
+ #: functions/interface.php:369 releases/svn/functions/interface.php:369
1273
  msgid "File Monthly"
1274
  msgstr ""
1275
 
1276
+ #: functions/interface.php:370 releases/svn/functions/interface.php:370
1277
  msgid "Database Monthly"
1278
  msgstr ""
1279
 
1280
+ #: functions/interface.php:371 releases/svn/functions/interface.php:371
1281
  msgid "Complete Manually"
1282
  msgstr ""
1283
 
1284
+ #: functions/interface.php:372 releases/svn/functions/interface.php:372
1285
  msgid "File Manually"
1286
  msgstr ""
1287
 
1288
+ #: functions/interface.php:373 releases/svn/functions/interface.php:373
1289
  msgid "Database Manually"
1290
  msgstr ""
1291
 
1292
+ #: releases/svn/backdrop/server.php:6
1293
+ msgid "No key supplied"
1294
+ msgstr ""
1295
+
1296
+ #: releases/svn/backdrop/server.php:11
1297
+ msgid "Supplied key was not valid"
1298
+ msgstr ""
1299
+
1300
+ #: releases/svn/backdrop/task.php:22
1301
+ msgid "Task is already scheduled to run"
1302
+ msgstr ""
1303
+
1304
+ #: releases/svn/backdrop/task.php:41
1305
+ msgid "Task is not scheduled to run"
1306
+ msgstr ""
1307
+
1308
  #. Plugin URI of the plugin/theme
1309
  msgid "http://bwp.hmn.md/"
1310
  msgstr ""
1324
  msgid "http://hmn.md/"
1325
  msgstr ""
1326
 
1327
+ #: admin/schedule-sentence.php:118 releases/svn/admin/schedule-sentence.php:118
1328
  msgctxt ""
1329
  "1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to "
1330
  "store"
1331
  msgid "Backup my %1$s %2$s %3$s, %4$s."
1332
  msgstr ""
1333
 
1334
+ #: functions/interface.php:344 releases/svn/functions/interface.php:344
1335
  msgctxt "backups count"
1336
  msgid "One backup completed"
1337
  msgid_plural "%1$s backups completed"
phpunit.xml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <phpunit
2
+ bootstrap="tests/bootstrap.php"
3
+ backupGlobals="false"
4
+ colors="true"
5
+ convertErrorsToExceptions="true"
6
+ convertNoticesToExceptions="true"
7
+ convertWarningsToExceptions="true"
8
+ >
9
+ <testsuites>
10
+ <testsuite name="backup">
11
+ <directory prefix="test" suffix=".php">tests/backup</directory>
12
+ </testsuite>
13
+ <testsuite name="schedule">
14
+ <directory prefix="test" suffix=".php">tests/schedule</directory>
15
+ </testsuite>
16
+ <testsuite name="other">
17
+ <directory prefix="test" suffix=".php">tests/other</directory>
18
+ </testsuite>
19
+ </testsuites>
20
+ <groups>
21
+ <exclude>
22
+ <group>full-backup</group>
23
+ </exclude>
24
+ </groups>
25
+ </phpunit>
readme.md ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <table width="100%">
2
+ <tr>
3
+ <td align="left" width="70">
4
+ <strong><a href="https://bwp.hmn.md/">BackUpWordPress</a></strong><br />
5
+ Simple automated backups of your WordPress powered website.
6
+ </td>
7
+ <td align="right" width="20%">
8
+ <a href="https://travis-ci.org/humanmade/backupwordpress">
9
+ <img src="https://travis-ci.org/humanmade/backupwordpress.svg?branch=master" alt="Build status">
10
+ </a>
11
+ <a href="https://scrutinizer-ci.com/g/humanmade/backupwordpress/">
12
+ <img src="https://scrutinizer-ci.com/g/humanmade/backupwordpress/badges/coverage.png?b=master" alt="Coverage via Scrutiniser" />
13
+ </a>
14
+ </td>
15
+ </tr>
16
+ <tr>
17
+ <td>
18
+ A <strong><a href="https://hmn.md/">Human Made</a></strong> project. Maintained by @pdewouters.
19
+ </td>
20
+ <td align="center">
21
+ <img src="https://hmn.md/content/themes/hmnmd/assets/images/hm-logo.svg" width="100" />
22
+ </td>
23
+ </tr>
24
+ </table>
25
+
26
+ BackUpWordPress is a well tested, onsite backup plugin for WordPress. It's supports sending backups to cloud services through premium extensions
27
+
28
+ Stop using outdated practices, and start making sense.
29
+
30
+ ## Requirements
31
+ BackUpWordPress requires WordPress 3.9 or newer and requires PHP 5.3+ due to the use of namespaced code.
32
+
33
+ ## Installation
34
+ Just install like any other plugin
35
+
36
+ ## Contributing
37
+ Read our [contributing.md](https://github.com/humanmade/backupwordpress/blob/master/CONTRIBUTING.md) file
38
+
39
+
40
+ ## License
41
+ BackUpWordPress is licensed under the GPLv2 or later.
42
+
43
+ ## Credits
44
+ Created by Human Made for high volume and large-scale sites. BackUpWordPress is used on over 200,000 sites worldwide.
45
+
46
+ Written and maintained by [Tom Willmot](https://github.com/willmot) & [Paul De Wouters](https://github.com/pdwouters). Thanks to all our [contributors](https://github.com/humanmade/backupwordpress/graphs/contributors).
47
+
48
+ BackUpWordPress was originally developed by [wpdprx](http://profiles.wordpress.org/users/wpdprx/) before being taken over by Human Made.
49
+
50
+ ---
51
+
52
+ Interested in joining in on the fun? [Join us, and become human!](https://hmn.md/is/hiring/)
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: humanmade, willmot, pauldewouters, joehoyle, mattheu, tcrsavage, c
3
  Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, humanmade
4
  Requires at least: 3.9
5
  Tested up to: 4.2
6
- Stable tag: 3.2.7
7
 
8
- Simple automated backups of your WordPress powered website.
9
 
10
  == Description ==
11
 
@@ -31,7 +31,7 @@ The BackUpWordPress plugin is hosted on GitHub, if you want to help out with dev
31
 
32
  = Translations =
33
 
34
- We'd also love help translating the plugin into more languages, if you can help then please contact backupwordpress@hmn.md or visit http://translate.hmn.md/.
35
 
36
  == Installation ==
37
 
@@ -64,7 +64,7 @@ See this guide for more details - [How to restore from backup](https://bwp.hmn.m
64
 
65
  No.
66
 
67
- **I'm not receiving my backups by email?**
68
 
69
  Most servers have a filesize limit on email attachments, it's generally about 10mb. If your backup file is over that limit it won't be sent attached to the email, instead you should receive an email with a link to download the backup, if you aren't even receiving that then you likely have a mail issue on your server that you'll need to contact your host about.
70
 
@@ -82,15 +82,15 @@ The issue is that your `wp-cron.php` is not returning a `200` response when hit
82
 
83
  There are some things you can test to confirm this is the issue.
84
 
85
- * Are scheduled posts working? (They use wp-cron as well ).
86
 
87
- * Are you hosted on Heart Internet? (wp-cron may not be supported by Heart Internet, see below for work-around).
88
 
89
  * If you click manual backup does it work?
90
 
91
  * Try adding `define( 'ALTERNATE_WP_CRON', true );` to your `wp-config.php`, do automatic backups work?
92
 
93
- * Is your site private (I.E. is it behind some kind of authentication, maintenance plugin, .htaccess) if so wp-cron won't work until you remove it, if you are and you temporarily remove the authentication, do backups start working?
94
 
95
  Report the results to our support team for further help. To do this, either enable suport from your Admin Dashboard (recommended), or email backupwordpress@hmn.md
96
 
@@ -100,7 +100,7 @@ The script to be entered into the Heart Internet cPanel is: `/usr/bin/php5 /home
100
 
101
  **My backups seem to be failing?**
102
 
103
- If your backups are failing - it's commonly caused by lack of available resources on your server. The easiest way to establish this to exclude some [of] or your entire uploades folder, running a backup an if that succeeds. If so, we know it's probably a server issue. If not, report the results to our support team for further help. To do this, either enable suport from your Admin Dashboard (recommended), or email backupwordpress@hmn.md
104
 
105
  **Further Support & Feedback**
106
 
@@ -144,6 +144,18 @@ You can also tweet <a href="http://twitter.com/humanmadeltd">@humanmadeltd</a> o
144
 
145
  == Changelog ==
146
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  #### 3.2.7 / 2015-07-27
148
 
149
  * Pass schedule type instead of schedule id as context for the calculated sizes, it's more useful
3
  Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, humanmade
4
  Requires at least: 3.9
5
  Tested up to: 4.2
6
+ Stable tag: 3.3.0
7
 
8
+ Simple automated backups of your WordPress-powered website.
9
 
10
  == Description ==
11
 
31
 
32
  = Translations =
33
 
34
+ We'd also love help translating the plugin into more languages, if you can help then please visit https://translate.wordpress.org/projects/wp-plugins/backupwordpress/dev/ to start translating.
35
 
36
  == Installation ==
37
 
64
 
65
  No.
66
 
67
+ **I'm not receiving my backups by email**
68
 
69
  Most servers have a filesize limit on email attachments, it's generally about 10mb. If your backup file is over that limit it won't be sent attached to the email, instead you should receive an email with a link to download the backup, if you aren't even receiving that then you likely have a mail issue on your server that you'll need to contact your host about.
70
 
82
 
83
  There are some things you can test to confirm this is the issue.
84
 
85
+ * Are scheduled posts working? (They use wp-cron as well.)
86
 
87
+ * Are you hosted on Heart Internet? (wp-cron may not be supported by Heart Internet, see below for work-around.)
88
 
89
  * If you click manual backup does it work?
90
 
91
  * Try adding `define( 'ALTERNATE_WP_CRON', true );` to your `wp-config.php`, do automatic backups work?
92
 
93
+ * Is your site private (i.e. is it behind some kind of authentication, maintenance plugin, .htaccess)? If so wp-cron won't work until you remove it. If you are and you temporarily remove the authentication, do backups start working?
94
 
95
  Report the results to our support team for further help. To do this, either enable suport from your Admin Dashboard (recommended), or email backupwordpress@hmn.md
96
 
100
 
101
  **My backups seem to be failing?**
102
 
103
+ If your backups are failing, it's commonly caused by a lack of available resources on your server. The easiest way to establish this is to exclude some of, or the entirety of your uploads folder, running a backup, and if that succeeds, then you'll know it's probably a server issue. If not, report the results to our support team for further help. To do this, either enable support from your Admin Dashboard (recommended), or email backupwordpress@hmn.md
104
 
105
  **Further Support & Feedback**
106
 
144
 
145
  == Changelog ==
146
 
147
+ ### 3.3.0 / 2015-10-09
148
+
149
+ * Dropped support for PclZip
150
+ * Fixed duplicate cron schedule interval names ( props ucavus )
151
+ * Corrected some typos, grammar and punctuation ( props ucavus )
152
+ * Fixed a bug in the WP CLI command ( props duritong )
153
+ * Better message for wp-cron related errors
154
+ * Replace 'bi-weekly' with less confusing wording
155
+ * Fixed a few errors misc reported by code quality tool
156
+ * Total site size display now subtracts excludes
157
+ * Many general improvements and bug fixes
158
+
159
  #### 3.2.7 / 2015-07-27
160
 
161
  * Pass schedule type instead of schedule id as context for the calculated sizes, it's more useful
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit87894e4f092cead45686fe634307188f::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit135e0a5f58d891c6badc700fa8c4a730::getLoader();
vendor/composer/ClassLoader.php CHANGED
@@ -54,9 +54,15 @@ class ClassLoader
54
  private $useIncludePath = false;
55
  private $classMap = array();
56
 
 
 
57
  public function getPrefixes()
58
  {
59
- return call_user_func_array('array_merge', $this->prefixesPsr0);
 
 
 
 
60
  }
61
 
62
  public function getPrefixesPsr4()
@@ -143,6 +149,8 @@ class ClassLoader
143
  * @param string $prefix The prefix/namespace, with trailing '\\'
144
  * @param array|string $paths The PSR-0 base directories
145
  * @param bool $prepend Whether to prepend the directories
 
 
146
  */
147
  public function addPsr4($prefix, $paths, $prepend = false)
148
  {
@@ -204,6 +212,8 @@ class ClassLoader
204
  *
205
  * @param string $prefix The prefix/namespace, with trailing '\\'
206
  * @param array|string $paths The PSR-4 base directories
 
 
207
  */
208
  public function setPsr4($prefix, $paths)
209
  {
@@ -240,6 +250,27 @@ class ClassLoader
240
  return $this->useIncludePath;
241
  }
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  /**
244
  * Registers this instance as an autoloader.
245
  *
@@ -291,6 +322,9 @@ class ClassLoader
291
  if (isset($this->classMap[$class])) {
292
  return $this->classMap[$class];
293
  }
 
 
 
294
 
295
  $file = $this->findFileWithExtension($class, '.php');
296
 
54
  private $useIncludePath = false;
55
  private $classMap = array();
56
 
57
+ private $classMapAuthoritative = false;
58
+
59
  public function getPrefixes()
60
  {
61
+ if (!empty($this->prefixesPsr0)) {
62
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
63
+ }
64
+
65
+ return array();
66
  }
67
 
68
  public function getPrefixesPsr4()
149
  * @param string $prefix The prefix/namespace, with trailing '\\'
150
  * @param array|string $paths The PSR-0 base directories
151
  * @param bool $prepend Whether to prepend the directories
152
+ *
153
+ * @throws \InvalidArgumentException
154
  */
155
  public function addPsr4($prefix, $paths, $prepend = false)
156
  {
212
  *
213
  * @param string $prefix The prefix/namespace, with trailing '\\'
214
  * @param array|string $paths The PSR-4 base directories
215
+ *
216
+ * @throws \InvalidArgumentException
217
  */
218
  public function setPsr4($prefix, $paths)
219
  {
250
  return $this->useIncludePath;
251
  }
252
 
253
+ /**
254
+ * Turns off searching the prefix and fallback directories for classes
255
+ * that have not been registered with the class map.
256
+ *
257
+ * @param bool $classMapAuthoritative
258
+ */
259
+ public function setClassMapAuthoritative($classMapAuthoritative)
260
+ {
261
+ $this->classMapAuthoritative = $classMapAuthoritative;
262
+ }
263
+
264
+ /**
265
+ * Should class lookup fail if not found in the current class map?
266
+ *
267
+ * @return bool
268
+ */
269
+ public function isClassMapAuthoritative()
270
+ {
271
+ return $this->classMapAuthoritative;
272
+ }
273
+
274
  /**
275
  * Registers this instance as an autoloader.
276
  *
322
  if (isset($this->classMap[$class])) {
323
  return $this->classMap[$class];
324
  }
325
+ if ($this->classMapAuthoritative) {
326
+ return false;
327
+ }
328
 
329
  $file = $this->findFileWithExtension($class, '.php');
330
 
vendor/composer/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Copyright (c) 2015 Nils Adermann, Jordi Boggiano
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished
9
+ to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
vendor/composer/autoload_namespaces.php CHANGED
@@ -6,5 +6,4 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
- 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
10
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
9
  );
vendor/composer/autoload_psr4.php CHANGED
@@ -6,4 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
9
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
10
  );
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit87894e4f092cead45686fe634307188f
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit87894e4f092cead45686fe634307188f
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit87894e4f092cead45686fe634307188f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit87894e4f092cead45686fe634307188f', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
@@ -44,7 +44,7 @@ class ComposerAutoloaderInit87894e4f092cead45686fe634307188f
44
  }
45
  }
46
 
47
- function composerRequire87894e4f092cead45686fe634307188f($file)
48
  {
49
  require $file;
50
  }
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit135e0a5f58d891c6badc700fa8c4a730
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit135e0a5f58d891c6badc700fa8c4a730', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit135e0a5f58d891c6badc700fa8c4a730', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
44
  }
45
  }
46
 
47
+ function composerRequire135e0a5f58d891c6badc700fa8c4a730($file)
48
  {
49
  require $file;
50
  }
vendor/composer/installed.json CHANGED
@@ -1,33 +1,35 @@
1
  [
2
  {
3
  "name": "symfony/finder",
4
- "version": "v2.6.4",
5
- "version_normalized": "2.6.4.0",
6
- "target-dir": "Symfony/Component/Finder",
7
  "source": {
8
  "type": "git",
9
  "url": "https://github.com/symfony/Finder.git",
10
- "reference": "16513333bca64186c01609961a2bb1b95b5e1355"
11
  },
12
  "dist": {
13
  "type": "zip",
14
- "url": "https://api.github.com/repos/symfony/Finder/zipball/16513333bca64186c01609961a2bb1b95b5e1355",
15
- "reference": "16513333bca64186c01609961a2bb1b95b5e1355",
16
  "shasum": ""
17
  },
18
  "require": {
19
- "php": ">=5.3.3"
20
  },
21
- "time": "2015-01-03 08:01:59",
 
 
 
22
  "type": "library",
23
  "extra": {
24
  "branch-alias": {
25
- "dev-master": "2.6-dev"
26
  }
27
  },
28
  "installation-source": "dist",
29
  "autoload": {
30
- "psr-0": {
31
  "Symfony\\Component\\Finder\\": ""
32
  }
33
  },
@@ -36,16 +38,16 @@
36
  "MIT"
37
  ],
38
  "authors": [
39
- {
40
- "name": "Symfony Community",
41
- "homepage": "http://symfony.com/contributors"
42
- },
43
  {
44
  "name": "Fabien Potencier",
45
  "email": "fabien@symfony.com"
 
 
 
 
46
  }
47
  ],
48
  "description": "Symfony Finder Component",
49
- "homepage": "http://symfony.com"
50
  }
51
  ]
1
  [
2
  {
3
  "name": "symfony/finder",
4
+ "version": "v2.7.3",
5
+ "version_normalized": "2.7.3.0",
 
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/symfony/Finder.git",
9
+ "reference": "ae0f363277485094edc04c9f3cbe595b183b78e4"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/ae0f363277485094edc04c9f3cbe595b183b78e4",
14
+ "reference": "ae0f363277485094edc04c9f3cbe595b183b78e4",
15
  "shasum": ""
16
  },
17
  "require": {
18
+ "php": ">=5.3.9"
19
  },
20
+ "require-dev": {
21
+ "symfony/phpunit-bridge": "~2.7"
22
+ },
23
+ "time": "2015-07-09 16:07:40",
24
  "type": "library",
25
  "extra": {
26
  "branch-alias": {
27
+ "dev-master": "2.7-dev"
28
  }
29
  },
30
  "installation-source": "dist",
31
  "autoload": {
32
+ "psr-4": {
33
  "Symfony\\Component\\Finder\\": ""
34
  }
35
  },
38
  "MIT"
39
  ],
40
  "authors": [
 
 
 
 
41
  {
42
  "name": "Fabien Potencier",
43
  "email": "fabien@symfony.com"
44
+ },
45
+ {
46
+ "name": "Symfony Community",
47
+ "homepage": "https://symfony.com/contributors"
48
  }
49
  ],
50
  "description": "Symfony Finder Component",
51
+ "homepage": "https://symfony.com"
52
  }
53
  ]
vendor/symfony/finder/Adapter/AbstractAdapter.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Adapter;
13
+
14
+ /**
15
+ * Interface for finder engine implementations.
16
+ *
17
+ * @author Jean-François Simon <contact@jfsimon.fr>
18
+ */
19
+ abstract class AbstractAdapter implements AdapterInterface
20
+ {
21
+ protected $followLinks = false;
22
+ protected $mode = 0;
23
+ protected $minDepth = 0;
24
+ protected $maxDepth = PHP_INT_MAX;
25
+ protected $exclude = array();
26
+ protected $names = array();
27
+ protected $notNames = array();
28
+ protected $contains = array();
29
+ protected $notContains = array();
30
+ protected $sizes = array();
31
+ protected $dates = array();
32
+ protected $filters = array();
33
+ protected $sort = false;
34
+ protected $paths = array();
35
+ protected $notPaths = array();
36
+ protected $ignoreUnreadableDirs = false;
37
+
38
+ private static $areSupported = array();
39
+
40
+ /**
41
+ * {@inheritdoc}
42
+ */
43
+ public function isSupported()
44
+ {
45
+ $name = $this->getName();
46
+
47
+ if (!array_key_exists($name, self::$areSupported)) {
48
+ self::$areSupported[$name] = $this->canBeUsed();
49
+ }
50
+
51
+ return self::$areSupported[$name];
52
+ }
53
+
54
+ /**
55
+ * {@inheritdoc}
56
+ */
57
+ public function setFollowLinks($followLinks)
58
+ {
59
+ $this->followLinks = $followLinks;
60
+
61
+ return $this;
62
+ }
63
+
64
+ /**
65
+ * {@inheritdoc}
66
+ */
67
+ public function setMode($mode)
68
+ {
69
+ $this->mode = $mode;
70
+
71
+ return $this;
72
+ }
73
+
74
+ /**
75
+ * {@inheritdoc}
76
+ */
77
+ public function setDepths(array $depths)
78
+ {
79
+ $this->minDepth = 0;
80
+ $this->maxDepth = PHP_INT_MAX;
81
+
82
+ foreach ($depths as $comparator) {
83
+ switch ($comparator->getOperator()) {
84
+ case '>':
85
+ $this->minDepth = $comparator->getTarget() + 1;
86
+ break;
87
+ case '>=':
88
+ $this->minDepth = $comparator->getTarget();
89
+ break;
90
+ case '<':
91
+ $this->maxDepth = $comparator->getTarget() - 1;
92
+ break;
93
+ case '<=':
94
+ $this->maxDepth = $comparator->getTarget();
95
+ break;
96
+ default:
97
+ $this->minDepth = $this->maxDepth = $comparator->getTarget();
98
+ }
99
+ }
100
+
101
+ return $this;
102
+ }
103
+
104
+ /**
105
+ * {@inheritdoc}
106
+ */
107
+ public function setExclude(array $exclude)
108
+ {
109
+ $this->exclude = $exclude;
110
+
111
+ return $this;
112
+ }
113
+
114
+ /**
115
+ * {@inheritdoc}
116
+ */
117
+ public function setNames(array $names)
118
+ {
119
+ $this->names = $names;
120
+
121
+ return $this;
122
+ }
123
+
124
+ /**
125
+ * {@inheritdoc}
126
+ */
127
+ public function setNotNames(array $notNames)
128
+ {
129
+ $this->notNames = $notNames;
130
+
131
+ return $this;
132
+ }
133
+
134
+ /**
135
+ * {@inheritdoc}
136
+ */
137
+ public function setContains(array $contains)
138
+ {
139
+ $this->contains = $contains;
140
+
141
+ return $this;
142
+ }
143
+
144
+ /**
145
+ * {@inheritdoc}
146
+ */
147
+ public function setNotContains(array $notContains)
148
+ {
149
+ $this->notContains = $notContains;
150
+
151
+ return $this;
152
+ }
153
+
154
+ /**
155
+ * {@inheritdoc}
156
+ */
157
+ public function setSizes(array $sizes)
158
+ {
159
+ $this->sizes = $sizes;
160
+
161
+ return $this;
162
+ }
163
+
164
+ /**
165
+ * {@inheritdoc}
166
+ */
167
+ public function setDates(array $dates)
168
+ {
169
+ $this->dates = $dates;
170
+
171
+ return $this;
172
+ }
173
+
174
+ /**
175
+ * {@inheritdoc}
176
+ */
177
+ public function setFilters(array $filters)
178
+ {
179
+ $this->filters = $filters;
180
+
181
+ return $this;
182
+ }
183
+
184
+ /**
185
+ * {@inheritdoc}
186
+ */
187
+ public function setSort($sort)
188
+ {
189
+ $this->sort = $sort;
190
+
191
+ return $this;
192
+ }
193
+
194
+ /**
195
+ * {@inheritdoc}
196
+ */
197
+ public function setPath(array $paths)
198
+ {
199
+ $this->paths = $paths;
200
+
201
+ return $this;
202
+ }
203
+
204
+ /**
205
+ * {@inheritdoc}
206
+ */
207
+ public function setNotPath(array $notPaths)
208
+ {
209
+ $this->notPaths = $notPaths;
210
+
211
+ return $this;
212
+ }
213
+
214
+ /**
215
+ * {@inheritdoc}
216
+ */
217
+ public function ignoreUnreadableDirs($ignore = true)
218
+ {
219
+ $this->ignoreUnreadableDirs = (bool) $ignore;
220
+
221
+ return $this;
222
+ }
223
+
224
+ /**
225
+ * Returns whether the adapter is supported in the current environment.
226
+ *
227
+ * This method should be implemented in all adapters. Do not implement
228
+ * isSupported in the adapters as the generic implementation provides a cache
229
+ * layer.
230
+ *
231
+ * @see isSupported()
232
+ *
233
+ * @return bool Whether the adapter is supported
234
+ */
235
+ abstract protected function canBeUsed();
236
+ }
vendor/symfony/finder/Adapter/AbstractFindAdapter.php ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Adapter;
13
+
14
+ use Symfony\Component\Finder\Exception\AccessDeniedException;
15
+ use Symfony\Component\Finder\Iterator;
16
+ use Symfony\Component\Finder\Shell\Shell;
17
+ use Symfony\Component\Finder\Expression\Expression;
18
+ use Symfony\Component\Finder\Shell\Command;
19
+ use Symfony\Component\Finder\Comparator\NumberComparator;
20
+ use Symfony\Component\Finder\Comparator\DateComparator;
21
+
22
+ /**
23
+ * Shell engine implementation using GNU find command.
24
+ *
25
+ * @author Jean-François Simon <contact@jfsimon.fr>
26
+ */
27
+ abstract class AbstractFindAdapter extends AbstractAdapter
28
+ {
29
+ /**
30
+ * @var Shell
31
+ */
32
+ protected $shell;
33
+
34
+ /**
35
+ * Constructor.
36
+ */
37
+ public function __construct()
38
+ {
39
+ $this->shell = new Shell();
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ public function searchInDirectory($dir)
46
+ {
47
+ // having "/../" in path make find fail
48
+ $dir = realpath($dir);
49
+
50
+ // searching directories containing or not containing strings leads to no result
51
+ if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
52
+ return new Iterator\FilePathsIterator(array(), $dir);
53
+ }
54
+
55
+ $command = Command::create();
56
+ $find = $this->buildFindCommand($command, $dir);
57
+
58
+ if ($this->followLinks) {
59
+ $find->add('-follow');
60
+ }
61
+
62
+ $find->add('-mindepth')->add($this->minDepth + 1);
63
+
64
+ if (PHP_INT_MAX !== $this->maxDepth) {
65
+ $find->add('-maxdepth')->add($this->maxDepth + 1);
66
+ }
67
+
68
+ if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
69
+ $find->add('-type d');
70
+ } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
71
+ $find->add('-type f');
72
+ }
73
+
74
+ $this->buildNamesFiltering($find, $this->names);
75
+ $this->buildNamesFiltering($find, $this->notNames, true);
76
+ $this->buildPathsFiltering($find, $dir, $this->paths);
77
+ $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
78
+ $this->buildSizesFiltering($find, $this->sizes);
79
+ $this->buildDatesFiltering($find, $this->dates);
80
+
81
+ $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
82
+ $useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
83
+
84
+ if ($useGrep && ($this->contains || $this->notContains)) {
85
+ $grep = $command->ins('grep');
86
+ $this->buildContentFiltering($grep, $this->contains);
87
+ $this->buildContentFiltering($grep, $this->notContains, true);
88
+ }
89
+
90
+ if ($useSort) {
91
+ $this->buildSorting($command, $this->sort);
92
+ }
93
+
94
+ $command->setErrorHandler(
95
+ $this->ignoreUnreadableDirs
96
+ // If directory is unreadable and finder is set to ignore it, `stderr` is ignored.
97
+ ? function ($stderr) { return; }
98
+ : function ($stderr) { throw new AccessDeniedException($stderr); }
99
+ );
100
+
101
+ $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
102
+ $iterator = new Iterator\FilePathsIterator($paths, $dir);
103
+
104
+ if ($this->exclude) {
105
+ $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
106
+ }
107
+
108
+ if (!$useGrep && ($this->contains || $this->notContains)) {
109
+ $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
110
+ }
111
+
112
+ if ($this->filters) {
113
+ $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
114
+ }
115
+
116
+ if (!$useSort && $this->sort) {
117
+ $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
118
+ $iterator = $iteratorAggregate->getIterator();
119
+ }
120
+
121
+ return $iterator;
122
+ }
123
+
124
+ /**
125
+ * {@inheritdoc}
126
+ */
127
+ protected function canBeUsed()
128
+ {
129
+ return $this->shell->testCommand('find');
130
+ }
131
+
132
+ /**
133
+ * @param Command $command
134
+ * @param string $dir
135
+ *
136
+ * @return Command
137
+ */
138
+ protected function buildFindCommand(Command $command, $dir)
139
+ {
140
+ return $command
141
+ ->ins('find')
142
+ ->add('find ')
143
+ ->arg($dir)
144
+ ->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions
145
+ }
146
+
147
+ /**
148
+ * @param Command $command
149
+ * @param string[] $names
150
+ * @param bool $not
151
+ */
152
+ private function buildNamesFiltering(Command $command, array $names, $not = false)
153
+ {
154
+ if (0 === count($names)) {
155
+ return;
156
+ }
157
+
158
+ $command->add($not ? '-not' : null)->cmd('(');
159
+
160
+ foreach ($names as $i => $name) {
161
+ $expr = Expression::create($name);
162
+
163
+ // Find does not support expandable globs ("*.{a,b}" syntax).
164
+ if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
165
+ $expr = Expression::create($expr->getGlob()->toRegex(false));
166
+ }
167
+
168
+ // Fixes 'not search' and 'full path matching' regex problems.
169
+ // - Jokers '.' are replaced by [^/].
170
+ // - We add '[^/]*' before and after regex (if no ^|$ flags are present).
171
+ if ($expr->isRegex()) {
172
+ $regex = $expr->getRegex();
173
+ $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
174
+ ->setStartFlag(false)
175
+ ->setStartJoker(true)
176
+ ->replaceJokers('[^/]');
177
+ if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
178
+ $regex->setEndJoker(false)->append('[^/]*');
179
+ }
180
+ }
181
+
182
+ $command
183
+ ->add($i > 0 ? '-or' : null)
184
+ ->add($expr->isRegex()
185
+ ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
186
+ : ($expr->isCaseSensitive() ? '-name' : '-iname')
187
+ )
188
+ ->arg($expr->renderPattern());
189
+ }
190
+
191
+ $command->cmd(')');
192
+ }
193
+
194
+ /**
195
+ * @param Command $command
196
+ * @param string $dir
197
+ * @param string[] $paths
198
+ * @param bool $not
199
+ */
200
+ private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
201
+ {
202
+ if (0 === count($paths)) {
203
+ return;
204
+ }
205
+
206
+ $command->add($not ? '-not' : null)->cmd('(');
207
+
208
+ foreach ($paths as $i => $path) {
209
+ $expr = Expression::create($path);
210
+
211
+ // Find does not support expandable globs ("*.{a,b}" syntax).
212
+ if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
213
+ $expr = Expression::create($expr->getGlob()->toRegex(false));
214
+ }
215
+
216
+ // Fixes 'not search' regex problems.
217
+ if ($expr->isRegex()) {
218
+ $regex = $expr->getRegex();
219
+ $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
220
+ } else {
221
+ $expr->prepend('*')->append('*');
222
+ }
223
+
224
+ $command
225
+ ->add($i > 0 ? '-or' : null)
226
+ ->add($expr->isRegex()
227
+ ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
228
+ : ($expr->isCaseSensitive() ? '-path' : '-ipath')
229
+ )
230
+ ->arg($expr->renderPattern());
231
+ }
232
+
233
+ $command->cmd(')');
234
+ }
235
+
236
+ /**
237
+ * @param Command $command
238
+ * @param NumberComparator[] $sizes
239
+ */
240
+ private function buildSizesFiltering(Command $command, array $sizes)
241
+ {
242
+ foreach ($sizes as $i => $size) {
243
+ $command->add($i > 0 ? '-and' : null);
244
+
245
+ switch ($size->getOperator()) {
246
+ case '<=':
247
+ $command->add('-size -'.($size->getTarget() + 1).'c');
248
+ break;
249
+ case '>=':
250
+ $command->add('-size +'.($size->getTarget() - 1).'c');
251
+ break;
252
+ case '>':
253
+ $command->add('-size +'.$size->getTarget().'c');
254
+ break;
255
+ case '!=':
256
+ $command->add('-size -'.$size->getTarget().'c');
257
+ $command->add('-size +'.$size->getTarget().'c');
258
+ break;
259
+ case '<':
260
+ default:
261
+ $command->add('-size -'.$size->getTarget().'c');
262
+ }
263
+ }
264
+ }
265
+
266
+ /**
267
+ * @param Command $command
268
+ * @param DateComparator[] $dates
269
+ */
270
+ private function buildDatesFiltering(Command $command, array $dates)
271
+ {
272
+ foreach ($dates as $i => $date) {
273
+ $command->add($i > 0 ? '-and' : null);
274
+
275
+ $mins = (int) round((time() - $date->getTarget()) / 60);
276
+
277
+ if (0 > $mins) {
278
+ // mtime is in the future
279
+ $command->add(' -mmin -0');
280
+ // we will have no result so we don't need to continue
281
+ return;
282
+ }
283
+
284
+ switch ($date->getOperator()) {
285
+ case '<=':
286
+ $command->add('-mmin +'.($mins - 1));
287
+ break;
288
+ case '>=':
289
+ $command->add('-mmin -'.($mins + 1));
290
+ break;
291
+ case '>':
292
+ $command->add('-mmin -'.$mins);
293
+ break;
294
+ case '!=':
295
+ $command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
296
+ break;
297
+ case '<':
298
+ default:
299
+ $command->add('-mmin +'.$mins);
300
+ }
301
+ }
302
+ }
303
+
304
+ /**
305
+ * @param Command $command
306
+ * @param string $sort
307
+ *
308
+ * @throws \InvalidArgumentException
309
+ */
310
+ private function buildSorting(Command $command, $sort)
311
+ {
312
+ $this->buildFormatSorting($command, $sort);
313
+ }
314
+
315
+ /**
316
+ * @param Command $command
317
+ * @param string $sort
318
+ */
319
+ abstract protected function buildFormatSorting(Command $command, $sort);
320
+
321
+ /**
322
+ * @param Command $command
323
+ * @param array $contains
324
+ * @param bool $not
325
+ */
326
+ abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
327
+ }
vendor/symfony/finder/Adapter/AdapterInterface.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Adapter;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ interface AdapterInterface
18
+ {
19
+ /**
20
+ * @param bool $followLinks
21
+ *
22
+ * @return AdapterInterface Current instance
23
+ */
24
+ public function setFollowLinks($followLinks);
25
+
26
+ /**
27
+ * @param int $mode
28
+ *
29
+ * @return AdapterInterface Current instance
30
+ */
31
+ public function setMode($mode);
32
+
33
+ /**
34
+ * @param array $exclude
35
+ *
36
+ * @return AdapterInterface Current instance
37
+ */
38
+ public function setExclude(array $exclude);
39
+
40
+ /**
41
+ * @param array $depths
42
+ *
43
+ * @return AdapterInterface Current instance
44
+ */
45
+ public function setDepths(array $depths);
46
+
47
+ /**
48
+ * @param array $names
49
+ *
50
+ * @return AdapterInterface Current instance
51
+ */
52
+ public function setNames(array $names);
53
+
54
+ /**
55
+ * @param array $notNames
56
+ *
57
+ * @return AdapterInterface Current instance
58
+ */
59
+ public function setNotNames(array $notNames);
60
+
61
+ /**
62
+ * @param array $contains
63
+ *
64
+ * @return AdapterInterface Current instance
65
+ */
66
+ public function setContains(array $contains);
67
+
68
+ /**
69
+ * @param array $notContains
70
+ *
71
+ * @return AdapterInterface Current instance
72
+ */
73
+ public function setNotContains(array $notContains);
74
+
75
+ /**
76
+ * @param array $sizes
77
+ *
78
+ * @return AdapterInterface Current instance
79
+ */
80
+ public function setSizes(array $sizes);
81
+
82
+ /**
83
+ * @param array $dates
84
+ *
85
+ * @return AdapterInterface Current instance
86
+ */
87
+ public function setDates(array $dates);
88
+
89
+ /**
90
+ * @param array $filters
91
+ *
92
+ * @return AdapterInterface Current instance
93
+ */
94
+ public function setFilters(array $filters);
95
+
96
+ /**
97
+ * @param \Closure|int $sort
98
+ *
99
+ * @return AdapterInterface Current instance
100
+ */
101
+ public function setSort($sort);
102
+
103
+ /**
104
+ * @param array $paths
105
+ *
106
+ * @return AdapterInterface Current instance
107
+ */
108
+ public function setPath(array $paths);
109
+
110
+ /**
111
+ * @param array $notPaths
112
+ *
113
+ * @return AdapterInterface Current instance
114
+ */
115
+ public function setNotPath(array $notPaths);
116
+
117
+ /**
118
+ * @param bool $ignore
119
+ *
120
+ * @return AdapterInterface Current instance
121
+ */
122
+ public function ignoreUnreadableDirs($ignore = true);
123
+
124
+ /**
125
+ * @param string $dir
126
+ *
127
+ * @return \Iterator Result iterator
128
+ */
129
+ public function searchInDirectory($dir);
130
+
131
+ /**
132
+ * Tests adapter support for current platform.
133
+ *
134
+ * @return bool
135
+ */
136
+ public function isSupported();
137
+
138
+ /**
139
+ * Returns adapter name.
140
+ *
141
+ * @return string
142
+ */
143
+ public function getName();
144
+ }
vendor/symfony/finder/Adapter/BsdFindAdapter.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Adapter;
13
+
14
+ use Symfony\Component\Finder\Shell\Shell;
15
+ use Symfony\Component\Finder\Shell\Command;
16
+ use Symfony\Component\Finder\Iterator\SortableIterator;
17
+ use Symfony\Component\Finder\Expression\Expression;
18
+
19
+ /**
20
+ * Shell engine implementation using BSD find command.
21
+ *
22
+ * @author Jean-François Simon <contact@jfsimon.fr>
23
+ */
24
+ class BsdFindAdapter extends AbstractFindAdapter
25
+ {
26
+ /**
27
+ * {@inheritdoc}
28
+ */
29
+ public function getName()
30
+ {
31
+ return 'bsd_find';
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ protected function canBeUsed()
38
+ {
39
+ return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ protected function buildFormatSorting(Command $command, $sort)
46
+ {
47
+ switch ($sort) {
48
+ case SortableIterator::SORT_BY_NAME:
49
+ $command->ins('sort')->add('| sort');
50
+
51
+ return;
52
+ case SortableIterator::SORT_BY_TYPE:
53
+ $format = '%HT';
54
+ break;
55
+ case SortableIterator::SORT_BY_ACCESSED_TIME:
56
+ $format = '%a';
57
+ break;
58
+ case SortableIterator::SORT_BY_CHANGED_TIME:
59
+ $format = '%c';
60
+ break;
61
+ case SortableIterator::SORT_BY_MODIFIED_TIME:
62
+ $format = '%m';
63
+ break;
64
+ default:
65
+ throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
66
+ }
67
+
68
+ $command
69
+ ->add('-print0 | xargs -0 stat -f')
70
+ ->arg($format.'%t%N')
71
+ ->add('| sort | cut -f 2');
72
+ }
73
+
74
+ /**
75
+ * {@inheritdoc}
76
+ */
77
+ protected function buildFindCommand(Command $command, $dir)
78
+ {
79
+ parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
80
+
81
+ return $command;
82
+ }
83
+
84
+ /**
85
+ * {@inheritdoc}
86
+ */
87
+ protected function buildContentFiltering(Command $command, array $contains, $not = false)
88
+ {
89
+ foreach ($contains as $contain) {
90
+ $expr = Expression::create($contain);
91
+
92
+ // todo: avoid forking process for each $pattern by using multiple -e options
93
+ $command
94
+ ->add('| grep -v \'^$\'')
95
+ ->add('| xargs -I{} grep -I')
96
+ ->add($expr->isCaseSensitive() ? null : '-i')
97
+ ->add($not ? '-L' : '-l')
98
+ ->add('-Ee')->arg($expr->renderPattern())
99
+ ->add('{}')
100
+ ;
101
+ }
102
+ }
103
+ }
vendor/symfony/finder/Adapter/GnuFindAdapter.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Adapter;
13
+
14
+ use Symfony\Component\Finder\Shell\Shell;
15
+ use Symfony\Component\Finder\Shell\Command;
16
+ use Symfony\Component\Finder\Iterator\SortableIterator;
17
+ use Symfony\Component\Finder\Expression\Expression;
18
+
19
+ /**
20
+ * Shell engine implementation using GNU find command.
21
+ *
22
+ * @author Jean-François Simon <contact@jfsimon.fr>
23
+ */
24
+ class GnuFindAdapter extends AbstractFindAdapter
25
+ {
26
+ /**
27
+ * {@inheritdoc}
28
+ */
29
+ public function getName()
30
+ {
31
+ return 'gnu_find';
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ protected function buildFormatSorting(Command $command, $sort)
38
+ {
39
+ switch ($sort) {
40
+ case SortableIterator::SORT_BY_NAME:
41
+ $command->ins('sort')->add('| sort');
42
+
43
+ return;
44
+ case SortableIterator::SORT_BY_TYPE:
45
+ $format = '%y';
46
+ break;
47
+ case SortableIterator::SORT_BY_ACCESSED_TIME:
48
+ $format = '%A@';
49
+ break;
50
+ case SortableIterator::SORT_BY_CHANGED_TIME:
51
+ $format = '%C@';
52
+ break;
53
+ case SortableIterator::SORT_BY_MODIFIED_TIME:
54
+ $format = '%T@';
55
+ break;
56
+ default:
57
+ throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
58
+ }
59
+
60
+ $command
61
+ ->get('find')
62
+ ->add('-printf')
63
+ ->arg($format.' %h/%f\\n')
64
+ ->add('| sort | cut')
65
+ ->arg('-d ')
66
+ ->arg('-f2-')
67
+ ;
68
+ }
69
+
70
+ /**
71
+ * {@inheritdoc}
72
+ */
73
+ protected function canBeUsed()
74
+ {
75
+ return $this->shell->getType() === Shell::TYPE_UNIX && parent::canBeUsed();
76
+ }
77
+
78
+ /**
79
+ * {@inheritdoc}
80
+ */
81
+ protected function buildFindCommand(Command $command, $dir)
82
+ {
83
+ return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
84
+ }
85
+
86
+ /**
87
+ * {@inheritdoc}
88
+ */
89
+ protected function buildContentFiltering(Command $command, array $contains, $not = false)
90
+ {
91
+ foreach ($contains as $contain) {
92
+ $expr = Expression::create($contain);
93
+
94
+ // todo: avoid forking process for each $pattern by using multiple -e options
95
+ $command
96
+ ->add('| xargs -I{} -r grep -I')
97
+ ->add($expr->isCaseSensitive() ? null : '-i')
98
+ ->add($not ? '-L' : '-l')
99
+ ->add('-Ee')->arg($expr->renderPattern())
100
+ ->add('{}')
101
+ ;
102
+ }
103
+ }
104
+ }
vendor/symfony/finder/Adapter/PhpAdapter.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Adapter;
13
+
14
+ use Symfony\Component\Finder\Iterator;
15
+
16
+ /**
17
+ * PHP finder engine implementation.
18
+ *
19
+ * @author Jean-François Simon <contact@jfsimon.fr>
20
+ */
21
+ class PhpAdapter extends AbstractAdapter
22
+ {
23
+ /**
24
+ * {@inheritdoc}
25
+ */
26
+ public function searchInDirectory($dir)
27
+ {
28
+ $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
29
+
30
+ if ($this->followLinks) {
31
+ $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
32
+ }
33
+
34
+ $iterator = new \RecursiveIteratorIterator(
35
+ new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
36
+ \RecursiveIteratorIterator::SELF_FIRST
37
+ );
38
+
39
+ if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
40
+ $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
41
+ }
42
+
43
+ if ($this->mode) {
44
+ $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
45
+ }
46
+
47
+ if ($this->exclude) {
48
+ $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
49
+ }
50
+
51
+ if ($this->names || $this->notNames) {
52
+ $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
53
+ }
54
+
55
+ if ($this->contains || $this->notContains) {
56
+ $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
57
+ }
58
+
59
+ if ($this->sizes) {
60
+ $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
61
+ }
62
+
63
+ if ($this->dates) {
64
+ $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
65
+ }
66
+
67
+ if ($this->filters) {
68
+ $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
69
+ }
70
+
71
+ if ($this->sort) {
72
+ $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
73
+ $iterator = $iteratorAggregate->getIterator();
74
+ }
75
+
76
+ if ($this->paths || $this->notPaths) {
77
+ $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
78
+ }
79
+
80
+ return $iterator;
81
+ }
82
+
83
+ /**
84
+ * {@inheritdoc}
85
+ */
86
+ public function getName()
87
+ {
88
+ return 'php';
89
+ }
90
+
91
+ /**
92
+ * {@inheritdoc}
93
+ */
94
+ protected function canBeUsed()
95
+ {
96
+ return true;
97
+ }
98
+ }
vendor/symfony/finder/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CHANGELOG
2
+ =========
3
+
4
+ 2.5.0
5
+ -----
6
+ * added support for GLOB_BRACE in the paths passed to Finder::in()
7
+
8
+ 2.3.0
9
+ -----
10
+
11
+ * added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())
12
+ * unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception
13
+
14
+ 2.2.0
15
+ -----
16
+
17
+ * added Finder::path() and Finder::notPath() methods
18
+ * added finder adapters to improve performance on specific platforms
19
+ * added support for wildcard characters (glob patterns) in the paths passed
20
+ to Finder::in()
21
+
22
+ 2.1.0
23
+ -----
24
+
25
+ * added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and
26
+ Finder::sortByModifiedTime()
27
+ * added Countable to Finder
28
+ * added support for an array of directories as an argument to
29
+ Finder::exclude()
30
+ * added searching based on the file content via Finder::contains() and
31
+ Finder::notContains()
32
+ * added support for the != operator in the Comparator
33
+ * [BC BREAK] filter expressions (used for file name and content) are no more
34
+ considered as regexps but glob patterns when they are enclosed in '*' or '?'
vendor/symfony/finder/Comparator/Comparator.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Comparator;
13
+
14
+ /**
15
+ * Comparator.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Comparator
20
+ {
21
+ private $target;
22
+ private $operator = '==';
23
+
24
+ /**
25
+ * Gets the target value.
26
+ *
27
+ * @return string The target value
28
+ */
29
+ public function getTarget()
30
+ {
31
+ return $this->target;
32
+ }
33
+
34
+ /**
35
+ * Sets the target value.
36
+ *
37
+ * @param string $target The target value
38
+ */
39
+ public function setTarget($target)
40
+ {
41
+ $this->target = $target;
42
+ }
43
+
44
+ /**
45
+ * Gets the comparison operator.
46
+ *
47
+ * @return string The operator
48
+ */
49
+ public function getOperator()
50
+ {
51
+ return $this->operator;
52
+ }
53
+
54
+ /**
55
+ * Sets the comparison operator.
56
+ *
57
+ * @param string $operator A valid operator
58
+ *
59
+ * @throws \InvalidArgumentException
60
+ */
61
+ public function setOperator($operator)
62
+ {
63
+ if (!$operator) {
64
+ $operator = '==';
65
+ }
66
+
67
+ if (!in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
68
+ throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
69
+ }
70
+
71
+ $this->operator = $operator;
72
+ }
73
+
74
+ /**
75
+ * Tests against the target.
76
+ *
77
+ * @param mixed $test A test value
78
+ *
79
+ * @return bool
80
+ */
81
+ public function test($test)
82
+ {
83
+ switch ($this->operator) {
84
+ case '>':
85
+ return $test > $this->target;
86
+ case '>=':
87
+ return $test >= $this->target;
88
+ case '<':
89
+ return $test < $this->target;
90
+ case '<=':
91
+ return $test <= $this->target;
92
+ case '!=':
93
+ return $test != $this->target;
94
+ }
95
+
96
+ return $test == $this->target;
97
+ }
98
+ }
vendor/symfony/finder/Comparator/DateComparator.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Comparator;
13
+
14
+ /**
15
+ * DateCompare compiles date comparisons.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class DateComparator extends Comparator
20
+ {
21
+ /**
22
+ * Constructor.
23
+ *
24
+ * @param string $test A comparison string
25
+ *
26
+ * @throws \InvalidArgumentException If the test is not understood
27
+ */
28
+ public function __construct($test)
29
+ {
30
+ if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
31
+ throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
32
+ }
33
+
34
+ try {
35
+ $date = new \DateTime($matches[2]);
36
+ $target = $date->format('U');
37
+ } catch (\Exception $e) {
38
+ throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
39
+ }
40
+
41
+ $operator = isset($matches[1]) ? $matches[1] : '==';
42
+ if ('since' === $operator || 'after' === $operator) {
43
+ $operator = '>';
44
+ }
45
+
46
+ if ('until' === $operator || 'before' === $operator) {
47
+ $operator = '<';
48
+ }
49
+
50
+ $this->setOperator($operator);
51
+ $this->setTarget($target);
52
+ }
53
+ }
vendor/symfony/finder/Comparator/NumberComparator.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Comparator;
13
+
14
+ /**
15
+ * NumberComparator compiles a simple comparison to an anonymous
16
+ * subroutine, which you can call with a value to be tested again.
17
+ *
18
+ * Now this would be very pointless, if NumberCompare didn't understand
19
+ * magnitudes.
20
+ *
21
+ * The target value may use magnitudes of kilobytes (k, ki),
22
+ * megabytes (m, mi), or gigabytes (g, gi). Those suffixed
23
+ * with an i use the appropriate 2**n version in accordance with the
24
+ * IEC standard: http://physics.nist.gov/cuu/Units/binary.html
25
+ *
26
+ * Based on the Perl Number::Compare module.
27
+ *
28
+ * @author Fabien Potencier <fabien@symfony.com> PHP port
29
+ * @author Richard Clamp <richardc@unixbeard.net> Perl version
30
+ * @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
31
+ * @copyright 2002 Richard Clamp <richardc@unixbeard.net>
32
+ *
33
+ * @see http://physics.nist.gov/cuu/Units/binary.html
34
+ */
35
+ class NumberComparator extends Comparator
36
+ {
37
+ /**
38
+ * Constructor.
39
+ *
40
+ * @param string $test A comparison string
41
+ *
42
+ * @throws \InvalidArgumentException If the test is not understood
43
+ */
44
+ public function __construct($test)
45
+ {
46
+ if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
47
+ throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
48
+ }
49
+
50
+ $target = $matches[2];
51
+ if (!is_numeric($target)) {
52
+ throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
53
+ }
54
+ if (isset($matches[3])) {
55
+ // magnitude
56
+ switch (strtolower($matches[3])) {
57
+ case 'k':
58
+ $target *= 1000;
59
+ break;
60
+ case 'ki':
61
+ $target *= 1024;
62
+ break;
63
+ case 'm':
64
+ $target *= 1000000;
65
+ break;
66
+ case 'mi':
67
+ $target *= 1024 * 1024;
68
+ break;
69
+ case 'g':
70
+ $target *= 1000000000;
71
+ break;
72
+ case 'gi':
73
+ $target *= 1024 * 1024 * 1024;
74
+ break;
75
+ }
76
+ }
77
+
78
+ $this->setTarget($target);
79
+ $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
80
+ }
81
+ }
vendor/symfony/finder/Exception/AccessDeniedException.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Exception;
13
+
14
+ /**
15
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
16
+ */
17
+ class AccessDeniedException extends \UnexpectedValueException
18
+ {
19
+ }
vendor/symfony/finder/Exception/AdapterFailureException.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Exception;
13
+
14
+ use Symfony\Component\Finder\Adapter\AdapterInterface;
15
+
16
+ /**
17
+ * Base exception for all adapter failures.
18
+ *
19
+ * @author Jean-François Simon <contact@jfsimon.fr>
20
+ */
21
+ class AdapterFailureException extends \RuntimeException implements ExceptionInterface
22
+ {
23
+ /**
24
+ * @var \Symfony\Component\Finder\Adapter\AdapterInterface
25
+ */
26
+ private $adapter;
27
+
28
+ /**
29
+ * @param AdapterInterface $adapter
30
+ * @param string|null $message
31
+ * @param \Exception|null $previous
32
+ */
33
+ public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
34
+ {
35
+ $this->adapter = $adapter;
36
+ parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
37
+ }
38
+
39
+ /**
40
+ * {@inheritdoc}
41
+ */
42
+ public function getAdapter()
43
+ {
44
+ return $this->adapter;
45
+ }
46
+ }
vendor/symfony/finder/Exception/ExceptionInterface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Exception;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ interface ExceptionInterface
18
+ {
19
+ /**
20
+ * @return \Symfony\Component\Finder\Adapter\AdapterInterface
21
+ */
22
+ public function getAdapter();
23
+ }
vendor/symfony/finder/Exception/OperationNotPermitedException.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Exception;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ class OperationNotPermitedException extends AdapterFailureException
18
+ {
19
+ }
vendor/symfony/finder/Exception/ShellCommandFailureException.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Exception;
13
+
14
+ use Symfony\Component\Finder\Adapter\AdapterInterface;
15
+ use Symfony\Component\Finder\Shell\Command;
16
+
17
+ /**
18
+ * @author Jean-François Simon <contact@jfsimon.fr>
19
+ */
20
+ class ShellCommandFailureException extends AdapterFailureException
21
+ {
22
+ /**
23
+ * @var Command
24
+ */
25
+ private $command;
26
+
27
+ /**
28
+ * @param AdapterInterface $adapter
29
+ * @param Command $command
30
+ * @param \Exception|null $previous
31
+ */
32
+ public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
33
+ {
34
+ $this->command = $command;
35
+ parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
36
+ }
37
+
38
+ /**
39
+ * @return Command
40
+ */
41
+ public function getCommand()
42
+ {
43
+ return $this->command;
44
+ }
45
+ }
vendor/symfony/finder/Expression/Expression.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Expression;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ class Expression implements ValueInterface
18
+ {
19
+ const TYPE_REGEX = 1;
20
+ const TYPE_GLOB = 2;
21
+
22
+ /**
23
+ * @var ValueInterface
24
+ */
25
+ private $value;
26
+
27
+ /**
28
+ * @param string $expr
29
+ *
30
+ * @return Expression
31
+ */
32
+ public static function create($expr)
33
+ {
34
+ return new self($expr);
35
+ }
36
+
37
+ /**
38
+ * @param string $expr
39
+ */
40
+ public function __construct($expr)
41
+ {
42
+ try {
43
+ $this->value = Regex::create($expr);
44
+ } catch (\InvalidArgumentException $e) {
45
+ $this->value = new Glob($expr);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @return string
51
+ */
52
+ public function __toString()
53
+ {
54
+ return $this->render();
55
+ }
56
+
57
+ /**
58
+ * {@inheritdoc}
59
+ */
60
+ public function render()
61
+ {
62
+ return $this->value->render();
63
+ }
64
+
65
+ /**
66
+ * {@inheritdoc}
67
+ */
68
+ public function renderPattern()
69
+ {
70
+ return $this->value->renderPattern();
71
+ }
72
+
73
+ /**
74
+ * @return bool
75
+ */
76
+ public function isCaseSensitive()
77
+ {
78
+ return $this->value->isCaseSensitive();
79
+ }
80
+
81
+ /**
82
+ * @return int
83
+ */
84
+ public function getType()
85
+ {
86
+ return $this->value->getType();
87
+ }
88
+
89
+ /**
90
+ * {@inheritdoc}
91
+ */
92
+ public function prepend($expr)
93
+ {
94
+ $this->value->prepend($expr);
95
+
96
+ return $this;
97
+ }
98
+
99
+ /**
100
+ * {@inheritdoc}
101
+ */
102
+ public function append($expr)
103
+ {
104
+ $this->value->append($expr);
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * @return bool
111
+ */
112
+ public function isRegex()
113
+ {
114
+ return self::TYPE_REGEX === $this->value->getType();
115
+ }
116
+
117
+ /**
118
+ * @return bool
119
+ */
120
+ public function isGlob()
121
+ {
122
+ return self::TYPE_GLOB === $this->value->getType();
123
+ }
124
+
125
+ /**
126
+ * @throws \LogicException
127
+ *
128
+ * @return Glob
129
+ */
130
+ public function getGlob()
131
+ {
132
+ if (self::TYPE_GLOB !== $this->value->getType()) {
133
+ throw new \LogicException('Regex can\'t be transformed to glob.');
134
+ }
135
+
136
+ return $this->value;
137
+ }
138
+
139
+ /**
140
+ * @return Regex
141
+ */
142
+ public function getRegex()
143
+ {
144
+ return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
145
+ }
146
+ }
vendor/symfony/finder/Expression/Glob.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Expression;
13
+
14
+ use Symfony\Component\Finder\Glob as FinderGlob;
15
+
16
+ /**
17
+ * @author Jean-François Simon <contact@jfsimon.fr>
18
+ */
19
+ class Glob implements ValueInterface
20
+ {
21
+ /**
22
+ * @var string
23
+ */
24
+ private $pattern;
25
+
26
+ /**
27
+ * @param string $pattern
28
+ */
29
+ public function __construct($pattern)
30
+ {
31
+ $this->pattern = $pattern;
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ public function render()
38
+ {
39
+ return $this->pattern;
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ public function renderPattern()
46
+ {
47
+ return $this->pattern;
48
+ }
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ public function getType()
54
+ {
55
+ return Expression::TYPE_GLOB;
56
+ }
57
+
58
+ /**
59
+ * {@inheritdoc}
60
+ */
61
+ public function isCaseSensitive()
62
+ {
63
+ return true;
64
+ }
65
+
66
+ /**
67
+ * {@inheritdoc}
68
+ */
69
+ public function prepend($expr)
70
+ {
71
+ $this->pattern = $expr.$this->pattern;
72
+
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * {@inheritdoc}
78
+ */
79
+ public function append($expr)
80
+ {
81
+ $this->pattern .= $expr;
82
+
83
+ return $this;
84
+ }
85
+
86
+ /**
87
+ * Tests if glob is expandable ("*.{a,b}" syntax).
88
+ *
89
+ * @return bool
90
+ */
91
+ public function isExpandable()
92
+ {
93
+ return false !== strpos($this->pattern, '{')
94
+ && false !== strpos($this->pattern, '}');
95
+ }
96
+
97
+ /**
98
+ * @param bool $strictLeadingDot
99
+ * @param bool $strictWildcardSlash
100
+ *
101
+ * @return Regex
102
+ */
103
+ public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
104
+ {
105
+ $regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, '');
106
+
107
+ return new Regex($regex);
108
+ }
109
+ }
vendor/symfony/finder/Expression/Regex.php ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Expression;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ class Regex implements ValueInterface
18
+ {
19
+ const START_FLAG = '^';
20
+ const END_FLAG = '$';
21
+ const BOUNDARY = '~';
22
+ const JOKER = '.*';
23
+ const ESCAPING = '\\';
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $pattern;
29
+
30
+ /**
31
+ * @var array
32
+ */
33
+ private $options;
34
+
35
+ /**
36
+ * @var bool
37
+ */
38
+ private $startFlag;
39
+
40
+ /**
41
+ * @var bool
42
+ */
43
+ private $endFlag;
44
+
45
+ /**
46
+ * @var bool
47
+ */
48
+ private $startJoker;
49
+
50
+ /**
51
+ * @var bool
52
+ */
53
+ private $endJoker;
54
+
55
+ /**
56
+ * @param string $expr
57
+ *
58
+ * @return Regex
59
+ *
60
+ * @throws \InvalidArgumentException
61
+ */
62
+ public static function create($expr)
63
+ {
64
+ if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
65
+ $start = substr($m[1], 0, 1);
66
+ $end = substr($m[1], -1);
67
+
68
+ if (
69
+ ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
70
+ || ($start === '{' && $end === '}')
71
+ || ($start === '(' && $end === ')')
72
+ ) {
73
+ return new self(substr($m[1], 1, -1), $m[2], $end);
74
+ }
75
+ }
76
+
77
+ throw new \InvalidArgumentException('Given expression is not a regex.');
78
+ }
79
+
80
+ /**
81
+ * @param string $pattern
82
+ * @param string $options
83
+ * @param string $delimiter
84
+ */
85
+ public function __construct($pattern, $options = '', $delimiter = null)
86
+ {
87
+ if (null !== $delimiter) {
88
+ // removes delimiter escaping
89
+ $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
90
+ }
91
+
92
+ $this->parsePattern($pattern);
93
+ $this->options = $options;
94
+ }
95
+
96
+ /**
97
+ * @return string
98
+ */
99
+ public function __toString()
100
+ {
101
+ return $this->render();
102
+ }
103
+
104
+ /**
105
+ * {@inheritdoc}
106
+ */
107
+ public function render()
108
+ {
109
+ return self::BOUNDARY
110
+ .$this->renderPattern()
111
+ .self::BOUNDARY
112
+ .$this->options;
113
+ }
114
+
115
+ /**
116
+ * {@inheritdoc}
117
+ */
118
+ public function renderPattern()
119
+ {
120
+ return ($this->startFlag ? self::START_FLAG : '')
121
+ .($this->startJoker ? self::JOKER : '')
122
+ .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
123
+ .($this->endJoker ? self::JOKER : '')
124
+ .($this->endFlag ? self::END_FLAG : '');
125
+ }
126
+
127
+ /**
128
+ * {@inheritdoc}
129
+ */
130
+ public function isCaseSensitive()
131
+ {
132
+ return !$this->hasOption('i');
133
+ }
134
+
135
+ /**
136
+ * {@inheritdoc}
137
+ */
138
+ public function getType()
139
+ {
140
+ return Expression::TYPE_REGEX;
141
+ }
142
+
143
+ /**
144
+ * {@inheritdoc}
145
+ */
146
+ public function prepend($expr)
147
+ {
148
+ $this->pattern = $expr.$this->pattern;
149
+
150
+ return $this;
151
+ }
152
+
153
+ /**
154
+ * {@inheritdoc}
155
+ */
156
+ public function append($expr)
157
+ {
158
+ $this->pattern .= $expr;
159
+
160
+ return $this;
161
+ }
162
+
163
+ /**
164
+ * @param string $option
165
+ *
166
+ * @return bool
167
+ */
168
+ public function hasOption($option)
169
+ {
170
+ return false !== strpos($this->options, $option);
171
+ }
172
+
173
+ /**
174
+ * @param string $option
175
+ *
176
+ * @return Regex
177
+ */
178
+ public function addOption($option)
179
+ {
180
+ if (!$this->hasOption($option)) {
181
+ $this->options .= $option;
182
+ }
183
+
184
+ return $this;
185
+ }
186
+
187
+ /**
188
+ * @param string $option
189
+ *
190
+ * @return Regex
191
+ */
192
+ public function removeOption($option)
193
+ {
194
+ $this->options = str_replace($option, '', $this->options);
195
+
196
+ return $this;
197
+ }
198
+
199
+ /**
200
+ * @param bool $startFlag
201
+ *
202
+ * @return Regex
203
+ */
204
+ public function setStartFlag($startFlag)
205
+ {
206
+ $this->startFlag = $startFlag;
207
+
208
+ return $this;
209
+ }
210
+
211
+ /**
212
+ * @return bool
213
+ */
214
+ public function hasStartFlag()
215
+ {
216
+ return $this->startFlag;
217
+ }
218
+
219
+ /**
220
+ * @param bool $endFlag
221
+ *
222
+ * @return Regex
223
+ */
224
+ public function setEndFlag($endFlag)
225
+ {
226
+ $this->endFlag = (bool) $endFlag;
227
+
228
+ return $this;
229
+ }
230
+
231
+ /**
232
+ * @return bool
233
+ */
234
+ public function hasEndFlag()
235
+ {
236
+ return $this->endFlag;
237
+ }
238
+
239
+ /**
240
+ * @param bool $startJoker
241
+ *
242
+ * @return Regex
243
+ */
244
+ public function setStartJoker($startJoker)
245
+ {
246
+ $this->startJoker = $startJoker;
247
+
248
+ return $this;
249
+ }
250
+
251
+ /**
252
+ * @return bool
253
+ */
254
+ public function hasStartJoker()
255
+ {
256
+ return $this->startJoker;
257
+ }
258
+
259
+ /**
260
+ * @param bool $endJoker
261
+ *
262
+ * @return Regex
263
+ */
264
+ public function setEndJoker($endJoker)
265
+ {
266
+ $this->endJoker = (bool) $endJoker;
267
+
268
+ return $this;
269
+ }
270
+
271
+ /**
272
+ * @return bool
273
+ */
274
+ public function hasEndJoker()
275
+ {
276
+ return $this->endJoker;
277
+ }
278
+
279
+ /**
280
+ * @param array $replacement
281
+ *
282
+ * @return Regex
283
+ */
284
+ public function replaceJokers($replacement)
285
+ {
286
+ $replace = function ($subject) use ($replacement) {
287
+ $subject = $subject[0];
288
+ $replace = 0 === substr_count($subject, '\\') % 2;
289
+
290
+ return $replace ? str_replace('.', $replacement, $subject) : $subject;
291
+ };
292
+
293
+ $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
294
+
295
+ return $this;
296
+ }
297
+
298
+ /**
299
+ * @param string $pattern
300
+ */
301
+ private function parsePattern($pattern)
302
+ {
303
+ if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
304
+ $pattern = substr($pattern, 1);
305
+ }
306
+
307
+ if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
308
+ $pattern = substr($pattern, 2);
309
+ }
310
+
311
+ if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
312
+ $pattern = substr($pattern, 0, -1);
313
+ }
314
+
315
+ if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
316
+ $pattern = substr($pattern, 0, -2);
317
+ }
318
+
319
+ $this->pattern = $pattern;
320
+ }
321
+ }
vendor/symfony/finder/Expression/ValueInterface.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Expression;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ interface ValueInterface
18
+ {
19
+ /**
20
+ * Renders string representation of expression.
21
+ *
22
+ * @return string
23
+ */
24
+ public function render();
25
+
26
+ /**
27
+ * Renders string representation of pattern.
28
+ *
29
+ * @return string
30
+ */
31
+ public function renderPattern();
32
+
33
+ /**
34
+ * Returns value case sensitivity.
35
+ *
36
+ * @return bool
37
+ */
38
+ public function isCaseSensitive();
39
+
40
+ /**
41
+ * Returns expression type.
42
+ *
43
+ * @return int
44
+ */
45
+ public function getType();
46
+
47
+ /**
48
+ * @param string $expr
49
+ *
50
+ * @return ValueInterface
51
+ */
52
+ public function prepend($expr);
53
+
54
+ /**
55
+ * @param string $expr
56
+ *
57
+ * @return ValueInterface
58
+ */
59
+ public function append($expr);
60
+ }
vendor/symfony/finder/Finder.php ADDED
@@ -0,0 +1,840 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder;
13
+
14
+ use Symfony\Component\Finder\Adapter\AdapterInterface;
15
+ use Symfony\Component\Finder\Adapter\GnuFindAdapter;
16
+ use Symfony\Component\Finder\Adapter\BsdFindAdapter;
17
+ use Symfony\Component\Finder\Adapter\PhpAdapter;
18
+ use Symfony\Component\Finder\Comparator\DateComparator;
19
+ use Symfony\Component\Finder\Comparator\NumberComparator;
20
+ use Symfony\Component\Finder\Exception\ExceptionInterface;
21
+ use Symfony\Component\Finder\Iterator\CustomFilterIterator;
22
+ use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
23
+ use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
24
+ use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
25
+ use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
26
+ use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
27
+ use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
28
+ use Symfony\Component\Finder\Iterator\SortableIterator;
29
+
30
+ /**
31
+ * Finder allows to build rules to find files and directories.
32
+ *
33
+ * It is a thin wrapper around several specialized iterator classes.
34
+ *
35
+ * All rules may be invoked several times.
36
+ *
37
+ * All methods return the current Finder object to allow easy chaining:
38
+ *
39
+ * $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
40
+ *
41
+ * @author Fabien Potencier <fabien@symfony.com>
42
+ *
43
+ * @api
44
+ */
45
+ class Finder implements \IteratorAggregate, \Countable
46
+ {
47
+ const IGNORE_VCS_FILES = 1;
48
+ const IGNORE_DOT_FILES = 2;
49
+
50
+ private $mode = 0;
51
+ private $names = array();
52
+ private $notNames = array();
53
+ private $exclude = array();
54
+ private $filters = array();
55
+ private $depths = array();
56
+ private $sizes = array();
57
+ private $followLinks = false;
58
+ private $sort = false;
59
+ private $ignore = 0;
60
+ private $dirs = array();
61
+ private $dates = array();
62
+ private $iterators = array();
63
+ private $contains = array();
64
+ private $notContains = array();
65
+ private $adapters = array();
66
+ private $paths = array();
67
+ private $notPaths = array();
68
+ private $ignoreUnreadableDirs = false;
69
+
70
+ private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
71
+
72
+ /**
73
+ * Constructor.
74
+ */
75
+ public function __construct()
76
+ {
77
+ $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
78
+
79
+ $this
80
+ ->addAdapter(new GnuFindAdapter())
81
+ ->addAdapter(new BsdFindAdapter())
82
+ ->addAdapter(new PhpAdapter(), -50)
83
+ ->setAdapter('php')
84
+ ;
85
+ }
86
+
87
+ /**
88
+ * Creates a new Finder.
89
+ *
90
+ * @return Finder A new Finder instance
91
+ *
92
+ * @api
93
+ */
94
+ public static function create()
95
+ {
96
+ return new static();
97
+ }
98
+
99
+ /**
100
+ * Registers a finder engine implementation.
101
+ *
102
+ * @param AdapterInterface $adapter An adapter instance
103
+ * @param int $priority Highest is selected first
104
+ *
105
+ * @return Finder The current Finder instance
106
+ */
107
+ public function addAdapter(AdapterInterface $adapter, $priority = 0)
108
+ {
109
+ $this->adapters[$adapter->getName()] = array(
110
+ 'adapter' => $adapter,
111
+ 'priority' => $priority,
112
+ 'selected' => false,
113
+ );
114
+
115
+ return $this->sortAdapters();
116
+ }
117
+
118
+ /**
119
+ * Sets the selected adapter to the best one according to the current platform the code is run on.
120
+ *
121
+ * @return Finder The current Finder instance
122
+ */
123
+ public function useBestAdapter()
124
+ {
125
+ $this->resetAdapterSelection();
126
+
127
+ return $this->sortAdapters();
128
+ }
129
+
130
+ /**
131
+ * Selects the adapter to use.
132
+ *
133
+ * @param string $name
134
+ *
135
+ * @throws \InvalidArgumentException
136
+ *
137
+ * @return Finder The current Finder instance
138
+ */
139
+ public function setAdapter($name)
140
+ {
141
+ if (!isset($this->adapters[$name])) {
142
+ throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
143
+ }
144
+
145
+ $this->resetAdapterSelection();
146
+ $this->adapters[$name]['selected'] = true;
147
+
148
+ return $this->sortAdapters();
149
+ }
150
+
151
+ /**
152
+ * Removes all adapters registered in the finder.
153
+ *
154
+ * @return Finder The current Finder instance
155
+ */
156
+ public function removeAdapters()
157
+ {
158
+ $this->adapters = array();
159
+
160
+ return $this;
161
+ }
162
+
163
+ /**
164
+ * Returns registered adapters ordered by priority without extra information.
165
+ *
166
+ * @return AdapterInterface[]
167
+ */
168
+ public function getAdapters()
169
+ {
170
+ return array_values(array_map(function (array $adapter) {
171
+ return $adapter['adapter'];
172
+ }, $this->adapters));
173
+ }
174
+
175
+ /**
176
+ * Restricts the matching to directories only.
177
+ *
178
+ * @return Finder The current Finder instance
179
+ *
180
+ * @api
181
+ */
182
+ public function directories()
183
+ {
184
+ $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
185
+
186
+ return $this;
187
+ }
188
+
189
+ /**
190
+ * Restricts the matching to files only.
191
+ *
192
+ * @return Finder The current Finder instance
193
+ *
194
+ * @api
195
+ */
196
+ public function files()
197
+ {
198
+ $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
199
+
200
+ return $this;
201
+ }
202
+
203
+ /**
204
+ * Adds tests for the directory depth.
205
+ *
206
+ * Usage:
207
+ *
208
+ * $finder->depth('> 1') // the Finder will start matching at level 1.
209
+ * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
210
+ *
211
+ * @param int $level The depth level expression
212
+ *
213
+ * @return Finder The current Finder instance
214
+ *
215
+ * @see DepthRangeFilterIterator
216
+ * @see NumberComparator
217
+ *
218
+ * @api
219
+ */
220
+ public function depth($level)
221
+ {
222
+ $this->depths[] = new Comparator\NumberComparator($level);
223
+
224
+ return $this;
225
+ }
226
+
227
+ /**
228
+ * Adds tests for file dates (last modified).
229
+ *
230
+ * The date must be something that strtotime() is able to parse:
231
+ *
232
+ * $finder->date('since yesterday');
233
+ * $finder->date('until 2 days ago');
234
+ * $finder->date('> now - 2 hours');
235
+ * $finder->date('>= 2005-10-15');
236
+ *
237
+ * @param string $date A date range string
238
+ *
239
+ * @return Finder The current Finder instance
240
+ *
241
+ * @see strtotime
242
+ * @see DateRangeFilterIterator
243
+ * @see DateComparator
244
+ *
245
+ * @api
246
+ */
247
+ public function date($date)
248
+ {
249
+ $this->dates[] = new Comparator\DateComparator($date);
250
+
251
+ return $this;
252
+ }
253
+
254
+ /**
255
+ * Adds rules that files must match.
256
+ *
257
+ * You can use patterns (delimited with / sign), globs or simple strings.
258
+ *
259
+ * $finder->name('*.php')
260
+ * $finder->name('/\.php$/') // same as above
261
+ * $finder->name('test.php')
262
+ *
263
+ * @param string $pattern A pattern (a regexp, a glob, or a string)
264
+ *
265
+ * @return Finder The current Finder instance
266
+ *
267
+ * @see FilenameFilterIterator
268
+ *
269
+ * @api
270
+ */
271
+ public function name($pattern)
272
+ {
273
+ $this->names[] = $pattern;
274
+
275
+ return $this;
276
+ }
277
+
278
+ /**
279
+ * Adds rules that files must not match.
280
+ *
281
+ * @param string $pattern A pattern (a regexp, a glob, or a string)
282
+ *
283
+ * @return Finder The current Finder instance
284
+ *
285
+ * @see FilenameFilterIterator
286
+ *
287
+ * @api
288
+ */
289
+ public function notName($pattern)
290
+ {
291
+ $this->notNames[] = $pattern;
292
+
293
+ return $this;
294
+ }
295
+
296
+ /**
297
+ * Adds tests that file contents must match.
298
+ *
299
+ * Strings or PCRE patterns can be used:
300
+ *
301
+ * $finder->contains('Lorem ipsum')
302
+ * $finder->contains('/Lorem ipsum/i')
303
+ *
304
+ * @param string $pattern A pattern (string or regexp)
305
+ *
306
+ * @return Finder The current Finder instance
307
+ *
308
+ * @see FilecontentFilterIterator
309
+ */
310
+ public function contains($pattern)
311
+ {
312
+ $this->contains[] = $pattern;
313
+
314
+ return $this;
315
+ }
316
+
317
+ /**
318
+ * Adds tests that file contents must not match.
319
+ *
320
+ * Strings or PCRE patterns can be used:
321
+ *
322
+ * $finder->notContains('Lorem ipsum')
323
+ * $finder->notContains('/Lorem ipsum/i')
324
+ *
325
+ * @param string $pattern A pattern (string or regexp)
326
+ *
327
+ * @return Finder The current Finder instance
328
+ *
329
+ * @see FilecontentFilterIterator
330
+ */
331
+ public function notContains($pattern)
332
+ {
333
+ $this->notContains[] = $pattern;
334
+
335
+ return $this;
336
+ }
337
+
338
+ /**
339
+ * Adds rules that filenames must match.
340
+ *
341
+ * You can use patterns (delimited with / sign) or simple strings.
342
+ *
343
+ * $finder->path('some/special/dir')
344
+ * $finder->path('/some\/special\/dir/') // same as above
345
+ *
346
+ * Use only / as dirname separator.
347
+ *
348
+ * @param string $pattern A pattern (a regexp or a string)
349
+ *
350
+ * @return Finder The current Finder instance
351
+ *
352
+ * @see FilenameFilterIterator
353
+ */
354
+ public function path($pattern)
355
+ {
356
+ $this->paths[] = $pattern;
357
+
358
+ return $this;
359
+ }
360
+
361
+ /**
362
+ * Adds rules that filenames must not match.
363
+ *
364
+ * You can use patterns (delimited with / sign) or simple strings.
365
+ *
366
+ * $finder->notPath('some/special/dir')
367
+ * $finder->notPath('/some\/special\/dir/') // same as above
368
+ *
369
+ * Use only / as dirname separator.
370
+ *
371
+ * @param string $pattern A pattern (a regexp or a string)
372
+ *
373
+ * @return Finder The current Finder instance
374
+ *
375
+ * @see FilenameFilterIterator
376
+ */
377
+ public function notPath($pattern)
378
+ {
379
+ $this->notPaths[] = $pattern;
380
+
381
+ return $this;
382
+ }
383
+
384
+ /**
385
+ * Adds tests for file sizes.
386
+ *
387
+ * $finder->size('> 10K');
388
+ * $finder->size('<= 1Ki');
389
+ * $finder->size(4);
390
+ *
391
+ * @param string $size A size range string
392
+ *
393
+ * @return Finder The current Finder instance
394
+ *
395
+ * @see SizeRangeFilterIterator
396
+ * @see NumberComparator
397
+ *
398
+ * @api
399
+ */
400
+ public function size($size)
401
+ {
402
+ $this->sizes[] = new Comparator\NumberComparator($size);
403
+
404
+ return $this;
405
+ }
406
+
407
+ /**
408
+ * Excludes directories.
409
+ *
410
+ * @param string|array $dirs A directory path or an array of directories
411
+ *
412
+ * @return Finder The current Finder instance
413
+ *
414
+ * @see ExcludeDirectoryFilterIterator
415
+ *
416
+ * @api
417
+ */
418
+ public function exclude($dirs)
419
+ {
420
+ $this->exclude = array_merge($this->exclude, (array) $dirs);
421
+
422
+ return $this;
423
+ }
424
+
425
+ /**
426
+ * Excludes "hidden" directories and files (starting with a dot).
427
+ *
428
+ * @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
429
+ *
430
+ * @return Finder The current Finder instance
431
+ *
432
+ * @see ExcludeDirectoryFilterIterator
433
+ *
434
+ * @api
435
+ */
436
+ public function ignoreDotFiles($ignoreDotFiles)
437
+ {
438
+ if ($ignoreDotFiles) {
439
+ $this->ignore |= static::IGNORE_DOT_FILES;
440
+ } else {
441
+ $this->ignore &= ~static::IGNORE_DOT_FILES;
442
+ }
443
+
444
+ return $this;
445
+ }
446
+
447
+ /**
448
+ * Forces the finder to ignore version control directories.
449
+ *
450
+ * @param bool $ignoreVCS Whether to exclude VCS files or not
451
+ *
452
+ * @return Finder The current Finder instance
453
+ *
454
+ * @see ExcludeDirectoryFilterIterator
455
+ *
456
+ * @api
457
+ */
458
+ public function ignoreVCS($ignoreVCS)
459
+ {
460
+ if ($ignoreVCS) {
461
+ $this->ignore |= static::IGNORE_VCS_FILES;
462
+ } else {
463
+ $this->ignore &= ~static::IGNORE_VCS_FILES;
464
+ }
465
+
466
+ return $this;
467
+ }
468
+
469
+ /**
470
+ * Adds VCS patterns.
471
+ *
472
+ * @see ignoreVCS()
473
+ *
474
+ * @param string|string[] $pattern VCS patterns to ignore
475
+ */
476
+ public static function addVCSPattern($pattern)
477
+ {
478
+ foreach ((array) $pattern as $p) {
479
+ self::$vcsPatterns[] = $p;
480
+ }
481
+
482
+ self::$vcsPatterns = array_unique(self::$vcsPatterns);
483
+ }
484
+
485
+ /**
486
+ * Sorts files and directories by an anonymous function.
487
+ *
488
+ * The anonymous function receives two \SplFileInfo instances to compare.
489
+ *
490
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
491
+ *
492
+ * @param \Closure $closure An anonymous function
493
+ *
494
+ * @return Finder The current Finder instance
495
+ *
496
+ * @see SortableIterator
497
+ *
498
+ * @api
499
+ */
500
+ public function sort(\Closure $closure)
501
+ {
502
+ $this->sort = $closure;
503
+
504
+ return $this;
505
+ }
506
+
507
+ /**
508
+ * Sorts files and directories by name.
509
+ *
510
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
511
+ *
512
+ * @return Finder The current Finder instance
513
+ *
514
+ * @see SortableIterator
515
+ *
516
+ * @api
517
+ */
518
+ public function sortByName()
519
+ {
520
+ $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
521
+
522
+ return $this;
523
+ }
524
+
525
+ /**
526
+ * Sorts files and directories by type (directories before files), then by name.
527
+ *
528
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
529
+ *
530
+ * @return Finder The current Finder instance
531
+ *
532
+ * @see SortableIterator
533
+ *
534
+ * @api
535
+ */
536
+ public function sortByType()
537
+ {
538
+ $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
539
+
540
+ return $this;
541
+ }
542
+
543
+ /**
544
+ * Sorts files and directories by the last accessed time.
545
+ *
546
+ * This is the time that the file was last accessed, read or written to.
547
+ *
548
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
549
+ *
550
+ * @return Finder The current Finder instance
551
+ *
552
+ * @see SortableIterator
553
+ *
554
+ * @api
555
+ */
556
+ public function sortByAccessedTime()
557
+ {
558
+ $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
559
+
560
+ return $this;
561
+ }
562
+
563
+ /**
564
+ * Sorts files and directories by the last inode changed time.
565
+ *
566
+ * This is the time that the inode information was last modified (permissions, owner, group or other metadata).
567
+ *
568
+ * On Windows, since inode is not available, changed time is actually the file creation time.
569
+ *
570
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
571
+ *
572
+ * @return Finder The current Finder instance
573
+ *
574
+ * @see SortableIterator
575
+ *
576
+ * @api
577
+ */
578
+ public function sortByChangedTime()
579
+ {
580
+ $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
581
+
582
+ return $this;
583
+ }
584
+
585
+ /**
586
+ * Sorts files and directories by the last modified time.
587
+ *
588
+ * This is the last time the actual contents of the file were last modified.
589
+ *
590
+ * This can be slow as all the matching files and directories must be retrieved for comparison.
591
+ *
592
+ * @return Finder The current Finder instance
593
+ *
594
+ * @see SortableIterator
595
+ *
596
+ * @api
597
+ */
598
+ public function sortByModifiedTime()
599
+ {
600
+ $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
601
+
602
+ return $this;
603
+ }
604
+
605
+ /**
606
+ * Filters the iterator with an anonymous function.
607
+ *
608
+ * The anonymous function receives a \SplFileInfo and must return false
609
+ * to remove files.
610
+ *
611
+ * @param \Closure $closure An anonymous function
612
+ *
613
+ * @return Finder The current Finder instance
614
+ *
615
+ * @see CustomFilterIterator
616
+ *
617
+ * @api
618
+ */
619
+ public function filter(\Closure $closure)
620
+ {
621
+ $this->filters[] = $closure;
622
+
623
+ return $this;
624
+ }
625
+
626
+ /**
627
+ * Forces the following of symlinks.
628
+ *
629
+ * @return Finder The current Finder instance
630
+ *
631
+ * @api
632
+ */
633
+ public function followLinks()
634
+ {
635
+ $this->followLinks = true;
636
+
637
+ return $this;
638
+ }
639
+
640
+ /**
641
+ * Tells finder to ignore unreadable directories.
642
+ *
643
+ * By default, scanning unreadable directories content throws an AccessDeniedException.
644
+ *
645
+ * @param bool $ignore
646
+ *
647
+ * @return Finder The current Finder instance
648
+ */
649
+ public function ignoreUnreadableDirs($ignore = true)
650
+ {
651
+ $this->ignoreUnreadableDirs = (bool) $ignore;
652
+
653
+ return $this;
654
+ }
655
+
656
+ /**
657
+ * Searches files and directories which match defined rules.
658
+ *
659
+ * @param string|array $dirs A directory path or an array of directories
660
+ *
661
+ * @return Finder The current Finder instance
662
+ *
663
+ * @throws \InvalidArgumentException if one of the directories does not exist
664
+ *
665
+ * @api
666
+ */
667
+ public function in($dirs)
668
+ {
669
+ $resolvedDirs = array();
670
+
671
+ foreach ((array) $dirs as $dir) {
672
+ if (is_dir($dir)) {
673
+ $resolvedDirs[] = $dir;
674
+ } elseif ($glob = glob($dir, (defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
675
+ $resolvedDirs = array_merge($resolvedDirs, $glob);
676
+ } else {
677
+ throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
678
+ }
679
+ }
680
+
681
+ $this->dirs = array_merge($this->dirs, $resolvedDirs);
682
+
683
+ return $this;
684
+ }
685
+
686
+ /**
687
+ * Returns an Iterator for the current Finder configuration.
688
+ *
689
+ * This method implements the IteratorAggregate interface.
690
+ *
691
+ * @return \Iterator An iterator
692
+ *
693
+ * @throws \LogicException if the in() method has not been called
694
+ */
695
+ public function getIterator()
696
+ {
697
+ if (0 === count($this->dirs) && 0 === count($this->iterators)) {
698
+ throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
699
+ }
700
+
701
+ if (1 === count($this->dirs) && 0 === count($this->iterators)) {
702
+ return $this->searchInDirectory($this->dirs[0]);
703
+ }
704
+
705
+ $iterator = new \AppendIterator();
706
+ foreach ($this->dirs as $dir) {
707
+ $iterator->append($this->searchInDirectory($dir));
708
+ }
709
+
710
+ foreach ($this->iterators as $it) {
711
+ $iterator->append($it);
712
+ }
713
+
714
+ return $iterator;
715
+ }
716
+
717
+ /**
718
+ * Appends an existing set of files/directories to the finder.
719
+ *
720
+ * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
721
+ *
722
+ * @param mixed $iterator
723
+ *
724
+ * @return Finder The finder
725
+ *
726
+ * @throws \InvalidArgumentException When the given argument is not iterable.
727
+ */
728
+ public function append($iterator)
729
+ {
730
+ if ($iterator instanceof \IteratorAggregate) {
731
+ $this->iterators[] = $iterator->getIterator();
732
+ } elseif ($iterator instanceof \Iterator) {
733
+ $this->iterators[] = $iterator;
734
+ } elseif ($iterator instanceof \Traversable || is_array($iterator)) {
735
+ $it = new \ArrayIterator();
736
+ foreach ($iterator as $file) {
737
+ $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
738
+ }
739
+ $this->iterators[] = $it;
740
+ } else {
741
+ throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
742
+ }
743
+
744
+ return $this;
745
+ }
746
+
747
+ /**
748
+ * Counts all the results collected by the iterators.
749
+ *
750
+ * @return int
751
+ */
752
+ public function count()
753
+ {
754
+ return iterator_count($this->getIterator());
755
+ }
756
+
757
+ /**
758
+ * @return Finder The current Finder instance
759
+ */
760
+ private function sortAdapters()
761
+ {
762
+ uasort($this->adapters, function (array $a, array $b) {
763
+ if ($a['selected'] || $b['selected']) {
764
+ return $a['selected'] ? -1 : 1;
765
+ }
766
+
767
+ return $a['priority'] > $b['priority'] ? -1 : 1;
768
+ });
769
+
770
+ return $this;
771
+ }
772
+
773
+ /**
774
+ * @param $dir
775
+ *
776
+ * @return \Iterator
777
+ *
778
+ * @throws \RuntimeException When none of the adapters are supported
779
+ */
780
+ private function searchInDirectory($dir)
781
+ {
782
+ if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
783
+ $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
784
+ }
785
+
786
+ if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
787
+ $this->notPaths[] = '#(^|/)\..+(/|$)#';
788
+ }
789
+
790
+ foreach ($this->adapters as $adapter) {
791
+ if ($adapter['adapter']->isSupported()) {
792
+ try {
793
+ return $this
794
+ ->buildAdapter($adapter['adapter'])
795
+ ->searchInDirectory($dir);
796
+ } catch (ExceptionInterface $e) {
797
+ }
798
+ }
799
+ }
800
+
801
+ throw new \RuntimeException('No supported adapter found.');
802
+ }
803
+
804
+ /**
805
+ * @param AdapterInterface $adapter
806
+ *
807
+ * @return AdapterInterface
808
+ */
809
+ private function buildAdapter(AdapterInterface $adapter)
810
+ {
811
+ return $adapter
812
+ ->setFollowLinks($this->followLinks)
813
+ ->setDepths($this->depths)
814
+ ->setMode($this->mode)
815
+ ->setExclude($this->exclude)
816
+ ->setNames($this->names)
817
+ ->setNotNames($this->notNames)
818
+ ->setContains($this->contains)
819
+ ->setNotContains($this->notContains)
820
+ ->setSizes($this->sizes)
821
+ ->setDates($this->dates)
822
+ ->setFilters($this->filters)
823
+ ->setSort($this->sort)
824
+ ->setPath($this->paths)
825
+ ->setNotPath($this->notPaths)
826
+ ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
827
+ }
828
+
829
+ /**
830
+ * Unselects all adapters.
831
+ */
832
+ private function resetAdapterSelection()
833
+ {
834
+ $this->adapters = array_map(function (array $properties) {
835
+ $properties['selected'] = false;
836
+
837
+ return $properties;
838
+ }, $this->adapters);
839
+ }
840
+ }
vendor/symfony/finder/Glob.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder;
13
+
14
+ /**
15
+ * Glob matches globbing patterns against text.
16
+ *
17
+ * if match_glob("foo.*", "foo.bar") echo "matched\n";
18
+ *
19
+ * // prints foo.bar and foo.baz
20
+ * $regex = glob_to_regex("foo.*");
21
+ * for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t)
22
+ * {
23
+ * if (/$regex/) echo "matched: $car\n";
24
+ * }
25
+ *
26
+ * Glob implements glob(3) style matching that can be used to match
27
+ * against text, rather than fetching names from a filesystem.
28
+ *
29
+ * Based on the Perl Text::Glob module.
30
+ *
31
+ * @author Fabien Potencier <fabien@symfony.com> PHP port
32
+ * @author Richard Clamp <richardc@unixbeard.net> Perl version
33
+ * @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
34
+ * @copyright 2002 Richard Clamp <richardc@unixbeard.net>
35
+ */
36
+ class Glob
37
+ {
38
+ /**
39
+ * Returns a regexp which is the equivalent of the glob pattern.
40
+ *
41
+ * @param string $glob The glob pattern
42
+ * @param bool $strictLeadingDot
43
+ * @param bool $strictWildcardSlash
44
+ * @param string $delimiter Optional delimiter
45
+ *
46
+ * @return string regex The regexp
47
+ */
48
+ public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true, $delimiter = '#')
49
+ {
50
+ $firstByte = true;
51
+ $escaping = false;
52
+ $inCurlies = 0;
53
+ $regex = '';
54
+ $sizeGlob = strlen($glob);
55
+ for ($i = 0; $i < $sizeGlob; ++$i) {
56
+ $car = $glob[$i];
57
+ if ($firstByte) {
58
+ if ($strictLeadingDot && '.' !== $car) {
59
+ $regex .= '(?=[^\.])';
60
+ }
61
+
62
+ $firstByte = false;
63
+ }
64
+
65
+ if ('/' === $car) {
66
+ $firstByte = true;
67
+ }
68
+
69
+ if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
70
+ $regex .= "\\$car";
71
+ } elseif ('*' === $car) {
72
+ $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
73
+ } elseif ('?' === $car) {
74
+ $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
75
+ } elseif ('{' === $car) {
76
+ $regex .= $escaping ? '\\{' : '(';
77
+ if (!$escaping) {
78
+ ++$inCurlies;
79
+ }
80
+ } elseif ('}' === $car && $inCurlies) {
81
+ $regex .= $escaping ? '}' : ')';
82
+ if (!$escaping) {
83
+ --$inCurlies;
84
+ }
85
+ } elseif (',' === $car && $inCurlies) {
86
+ $regex .= $escaping ? ',' : '|';
87
+ } elseif ('\\' === $car) {
88
+ if ($escaping) {
89
+ $regex .= '\\\\';
90
+ $escaping = false;
91
+ } else {
92
+ $escaping = true;
93
+ }
94
+
95
+ continue;
96
+ } else {
97
+ $regex .= $car;
98
+ }
99
+ $escaping = false;
100
+ }
101
+
102
+ return $delimiter.'^'.$regex.'$'.$delimiter;
103
+ }
104
+ }
vendor/symfony/finder/Iterator/CustomFilterIterator.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * CustomFilterIterator filters files by applying anonymous functions.
16
+ *
17
+ * The anonymous function receives a \SplFileInfo and must return false
18
+ * to remove files.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class CustomFilterIterator extends FilterIterator
23
+ {
24
+ private $filters = array();
25
+
26
+ /**
27
+ * Constructor.
28
+ *
29
+ * @param \Iterator $iterator The Iterator to filter
30
+ * @param array $filters An array of PHP callbacks
31
+ *
32
+ * @throws \InvalidArgumentException
33
+ */
34
+ public function __construct(\Iterator $iterator, array $filters)
35
+ {
36
+ foreach ($filters as $filter) {
37
+ if (!is_callable($filter)) {
38
+ throw new \InvalidArgumentException('Invalid PHP callback.');
39
+ }
40
+ }
41
+ $this->filters = $filters;
42
+
43
+ parent::__construct($iterator);
44
+ }
45
+
46
+ /**
47
+ * Filters the iterator values.
48
+ *
49
+ * @return bool true if the value should be kept, false otherwise
50
+ */
51
+ public function accept()
52
+ {
53
+ $fileinfo = $this->current();
54
+
55
+ foreach ($this->filters as $filter) {
56
+ if (false === call_user_func($filter, $fileinfo)) {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ return true;
62
+ }
63
+ }
vendor/symfony/finder/Iterator/DateRangeFilterIterator.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ use Symfony\Component\Finder\Comparator\DateComparator;
15
+
16
+ /**
17
+ * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class DateRangeFilterIterator extends FilterIterator
22
+ {
23
+ private $comparators = array();
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * @param \Iterator $iterator The Iterator to filter
29
+ * @param DateComparator[] $comparators An array of DateComparator instances
30
+ */
31
+ public function __construct(\Iterator $iterator, array $comparators)
32
+ {
33
+ $this->comparators = $comparators;
34
+
35
+ parent::__construct($iterator);
36
+ }
37
+
38
+ /**
39
+ * Filters the iterator values.
40
+ *
41
+ * @return bool true if the value should be kept, false otherwise
42
+ */
43
+ public function accept()
44
+ {
45
+ $fileinfo = $this->current();
46
+
47
+ if (!file_exists($fileinfo->getRealPath())) {
48
+ return false;
49
+ }
50
+
51
+ $filedate = $fileinfo->getMTime();
52
+ foreach ($this->comparators as $compare) {
53
+ if (!$compare->test($filedate)) {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ return true;
59
+ }
60
+ }
vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * DepthRangeFilterIterator limits the directory depth.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class DepthRangeFilterIterator extends FilterIterator
20
+ {
21
+ private $minDepth = 0;
22
+
23
+ /**
24
+ * Constructor.
25
+ *
26
+ * @param \RecursiveIteratorIterator $iterator The Iterator to filter
27
+ * @param int $minDepth The min depth
28
+ * @param int $maxDepth The max depth
29
+ */
30
+ public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
31
+ {
32
+ $this->minDepth = $minDepth;
33
+ $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
34
+
35
+ parent::__construct($iterator);
36
+ }
37
+
38
+ /**
39
+ * Filters the iterator values.
40
+ *
41
+ * @return bool true if the value should be kept, false otherwise
42
+ */
43
+ public function accept()
44
+ {
45
+ return $this->getInnerIterator()->getDepth() >= $this->minDepth;
46
+ }
47
+ }
vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * ExcludeDirectoryFilterIterator filters out directories.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class ExcludeDirectoryFilterIterator extends FilterIterator
20
+ {
21
+ private $patterns = array();
22
+
23
+ /**
24
+ * Constructor.
25
+ *
26
+ * @param \Iterator $iterator The Iterator to filter
27
+ * @param array $directories An array of directories to exclude
28
+ */
29
+ public function __construct(\Iterator $iterator, array $directories)
30
+ {
31
+ foreach ($directories as $directory) {
32
+ $this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
33
+ }
34
+
35
+ parent::__construct($iterator);
36
+ }
37
+
38
+ /**
39
+ * Filters the iterator values.
40
+ *
41
+ * @return bool true if the value should be kept, false otherwise
42
+ */
43
+ public function accept()
44
+ {
45
+ $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
46
+ $path = strtr($path, '\\', '/');
47
+ foreach ($this->patterns as $pattern) {
48
+ if (preg_match($pattern, $path)) {
49
+ return false;
50
+ }
51
+ }
52
+
53
+ return true;
54
+ }
55
+ }
vendor/symfony/finder/Iterator/FilePathsIterator.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ use Symfony\Component\Finder\SplFileInfo;
15
+
16
+ /**
17
+ * Iterate over shell command result.
18
+ *
19
+ * @author Jean-François Simon <contact@jfsimon.fr>
20
+ */
21
+ class FilePathsIterator extends \ArrayIterator
22
+ {
23
+ /**
24
+ * @var string
25
+ */
26
+ private $baseDir;
27
+
28
+ /**
29
+ * @var int
30
+ */
31
+ private $baseDirLength;
32
+
33
+ /**
34
+ * @var string
35
+ */
36
+ private $subPath;
37
+
38
+ /**
39
+ * @var string
40
+ */
41
+ private $subPathname;
42
+
43
+ /**
44
+ * @var SplFileInfo
45
+ */
46
+ private $current;
47
+
48
+ /**
49
+ * @param array $paths List of paths returned by shell command
50
+ * @param string $baseDir Base dir for relative path building
51
+ */
52
+ public function __construct(array $paths, $baseDir)
53
+ {
54
+ $this->baseDir = $baseDir;
55
+ $this->baseDirLength = strlen($baseDir);
56
+
57
+ parent::__construct($paths);
58
+ }
59
+
60
+ /**
61
+ * @param string $name
62
+ * @param array $arguments
63
+ *
64
+ * @return mixed
65
+ */
66
+ public function __call($name, array $arguments)
67
+ {
68
+ return call_user_func_array(array($this->current(), $name), $arguments);
69
+ }
70
+
71
+ /**
72
+ * Return an instance of SplFileInfo with support for relative paths.
73
+ *
74
+ * @return SplFileInfo File information
75
+ */
76
+ public function current()
77
+ {
78
+ return $this->current;
79
+ }
80
+
81
+ /**
82
+ * @return string
83
+ */
84
+ public function key()
85
+ {
86
+ return $this->current->getPathname();
87
+ }
88
+
89
+ public function next()
90
+ {
91
+ parent::next();
92
+ $this->buildProperties();
93
+ }
94
+
95
+ public function rewind()
96
+ {
97
+ parent::rewind();
98
+ $this->buildProperties();
99
+ }
100
+
101
+ /**
102
+ * @return string
103
+ */
104
+ public function getSubPath()
105
+ {
106
+ return $this->subPath;
107
+ }
108
+
109
+ /**
110
+ * @return string
111
+ */
112
+ public function getSubPathname()
113
+ {
114
+ return $this->subPathname;
115
+ }
116
+
117
+ private function buildProperties()
118
+ {
119
+ $absolutePath = parent::current();
120
+
121
+ if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
122
+ $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
123
+ $dir = dirname($this->subPathname);
124
+ $this->subPath = '.' === $dir ? '' : $dir;
125
+ } else {
126
+ $this->subPath = $this->subPathname = '';
127
+ }
128
+
129
+ $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
130
+ }
131
+ }
vendor/symfony/finder/Iterator/FileTypeFilterIterator.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * FileTypeFilterIterator only keeps files, directories, or both.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class FileTypeFilterIterator extends FilterIterator
20
+ {
21
+ const ONLY_FILES = 1;
22
+ const ONLY_DIRECTORIES = 2;
23
+
24
+ private $mode;
25
+
26
+ /**
27
+ * Constructor.
28
+ *
29
+ * @param \Iterator $iterator The Iterator to filter
30
+ * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
31
+ */
32
+ public function __construct(\Iterator $iterator, $mode)
33
+ {
34
+ $this->mode = $mode;
35
+
36
+ parent::__construct($iterator);
37
+ }
38
+
39
+ /**
40
+ * Filters the iterator values.
41
+ *
42
+ * @return bool true if the value should be kept, false otherwise
43
+ */
44
+ public function accept()
45
+ {
46
+ $fileinfo = $this->current();
47
+ if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
48
+ return false;
49
+ } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
50
+ return false;
51
+ }
52
+
53
+ return true;
54
+ }
55
+ }
vendor/symfony/finder/Iterator/FilecontentFilterIterator.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
19
+ */
20
+ class FilecontentFilterIterator extends MultiplePcreFilterIterator
21
+ {
22
+ /**
23
+ * Filters the iterator values.
24
+ *
25
+ * @return bool true if the value should be kept, false otherwise
26
+ */
27
+ public function accept()
28
+ {
29
+ if (!$this->matchRegexps && !$this->noMatchRegexps) {
30
+ return true;
31
+ }
32
+
33
+ $fileinfo = $this->current();
34
+
35
+ if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
36
+ return false;
37
+ }
38
+
39
+ $content = $fileinfo->getContents();
40
+ if (!$content) {
41
+ return false;
42
+ }
43
+
44
+ // should at least not match one rule to exclude
45
+ foreach ($this->noMatchRegexps as $regex) {
46
+ if (preg_match($regex, $content)) {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ // should at least match one rule
52
+ $match = true;
53
+ if ($this->matchRegexps) {
54
+ $match = false;
55
+ foreach ($this->matchRegexps as $regex) {
56
+ if (preg_match($regex, $content)) {
57
+ return true;
58
+ }
59
+ }
60
+ }
61
+
62
+ return $match;
63
+ }
64
+
65
+ /**
66
+ * Converts string to regexp if necessary.
67
+ *
68
+ * @param string $str Pattern: string or regexp
69
+ *
70
+ * @return string regexp corresponding to a given string or regexp
71
+ */
72
+ protected function toRegex($str)
73
+ {
74
+ return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
75
+ }
76
+ }
vendor/symfony/finder/Iterator/FilenameFilterIterator.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ use Symfony\Component\Finder\Expression\Expression;
15
+
16
+ /**
17
+ * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class FilenameFilterIterator extends MultiplePcreFilterIterator
22
+ {
23
+ /**
24
+ * Filters the iterator values.
25
+ *
26
+ * @return bool true if the value should be kept, false otherwise
27
+ */
28
+ public function accept()
29
+ {
30
+ $filename = $this->current()->getFilename();
31
+
32
+ // should at least not match one rule to exclude
33
+ foreach ($this->noMatchRegexps as $regex) {
34
+ if (preg_match($regex, $filename)) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ // should at least match one rule
40
+ $match = true;
41
+ if ($this->matchRegexps) {
42
+ $match = false;
43
+ foreach ($this->matchRegexps as $regex) {
44
+ if (preg_match($regex, $filename)) {
45
+ return true;
46
+ }
47
+ }
48
+ }
49
+
50
+ return $match;
51
+ }
52
+
53
+ /**
54
+ * Converts glob to regexp.
55
+ *
56
+ * PCRE patterns are left unchanged.
57
+ * Glob strings are transformed with Glob::toRegex().
58
+ *
59
+ * @param string $str Pattern: glob or regexp
60
+ *
61
+ * @return string regexp corresponding to a given glob or regexp
62
+ */
63
+ protected function toRegex($str)
64
+ {
65
+ return Expression::create($str)->getRegex()->render();
66
+ }
67
+ }
vendor/symfony/finder/Iterator/FilterIterator.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * This iterator just overrides the rewind method in order to correct a PHP bug.
16
+ *
17
+ * @see https://bugs.php.net/bug.php?id=49104
18
+ *
19
+ * @author Alex Bogomazov
20
+ */
21
+ abstract class FilterIterator extends \FilterIterator
22
+ {
23
+ /**
24
+ * This is a workaround for the problem with \FilterIterator leaving inner \FilesystemIterator in wrong state after
25
+ * rewind in some cases.
26
+ *
27
+ * @see FilterIterator::rewind()
28
+ */
29
+ public function rewind()
30
+ {
31
+ $iterator = $this;
32
+ while ($iterator instanceof \OuterIterator) {
33
+ $innerIterator = $iterator->getInnerIterator();
34
+
35
+ if ($innerIterator instanceof RecursiveDirectoryIterator) {
36
+ if ($innerIterator->isRewindable()) {
37
+ $innerIterator->next();
38
+ $innerIterator->rewind();
39
+ }
40
+ } elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
41
+ $iterator->getInnerIterator()->next();
42
+ $iterator->getInnerIterator()->rewind();
43
+ }
44
+ $iterator = $iterator->getInnerIterator();
45
+ }
46
+
47
+ parent::rewind();
48
+ }
49
+ }
vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ use Symfony\Component\Finder\Expression\Expression;
15
+
16
+ /**
17
+ * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ abstract class MultiplePcreFilterIterator extends FilterIterator
22
+ {
23
+ protected $matchRegexps = array();
24
+ protected $noMatchRegexps = array();
25
+
26
+ /**
27
+ * Constructor.
28
+ *
29
+ * @param \Iterator $iterator The Iterator to filter
30
+ * @param array $matchPatterns An array of patterns that need to match
31
+ * @param array $noMatchPatterns An array of patterns that need to not match
32
+ */
33
+ public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
34
+ {
35
+ foreach ($matchPatterns as $pattern) {
36
+ $this->matchRegexps[] = $this->toRegex($pattern);
37
+ }
38
+
39
+ foreach ($noMatchPatterns as $pattern) {
40
+ $this->noMatchRegexps[] = $this->toRegex($pattern);
41
+ }
42
+
43
+ parent::__construct($iterator);
44
+ }
45
+
46
+ /**
47
+ * Checks whether the string is a regex.
48
+ *
49
+ * @param string $str
50
+ *
51
+ * @return bool Whether the given string is a regex
52
+ */
53
+ protected function isRegex($str)
54
+ {
55
+ return Expression::create($str)->isRegex();
56
+ }
57
+
58
+ /**
59
+ * Converts string into regexp.
60
+ *
61
+ * @param string $str Pattern
62
+ *
63
+ * @return string regexp corresponding to a given string
64
+ */
65
+ abstract protected function toRegex($str);
66
+ }
vendor/symfony/finder/Iterator/PathFilterIterator.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * PathFilterIterator filters files by path patterns (e.g. some/special/dir).
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
19
+ */
20
+ class PathFilterIterator extends MultiplePcreFilterIterator
21
+ {
22
+ /**
23
+ * Filters the iterator values.
24
+ *
25
+ * @return bool true if the value should be kept, false otherwise
26
+ */
27
+ public function accept()
28
+ {
29
+ $filename = $this->current()->getRelativePathname();
30
+
31
+ if ('\\' === DIRECTORY_SEPARATOR) {
32
+ $filename = strtr($filename, '\\', '/');
33
+ }
34
+
35
+ // should at least not match one rule to exclude
36
+ foreach ($this->noMatchRegexps as $regex) {
37
+ if (preg_match($regex, $filename)) {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ // should at least match one rule
43
+ $match = true;
44
+ if ($this->matchRegexps) {
45
+ $match = false;
46
+ foreach ($this->matchRegexps as $regex) {
47
+ if (preg_match($regex, $filename)) {
48
+ return true;
49
+ }
50
+ }
51
+ }
52
+
53
+ return $match;
54
+ }
55
+
56
+ /**
57
+ * Converts strings to regexp.
58
+ *
59
+ * PCRE patterns are left unchanged.
60
+ *
61
+ * Default conversion:
62
+ * 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/'
63
+ *
64
+ * Use only / as directory separator (on Windows also).
65
+ *
66
+ * @param string $str Pattern: regexp or dirname.
67
+ *
68
+ * @return string regexp corresponding to a given string or regexp
69
+ */
70
+ protected function toRegex($str)
71
+ {
72
+ return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
73
+ }
74
+ }
vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ use Symfony\Component\Finder\Exception\AccessDeniedException;
15
+ use Symfony\Component\Finder\SplFileInfo;
16
+
17
+ /**
18
+ * Extends the \RecursiveDirectoryIterator to support relative paths.
19
+ *
20
+ * @author Victor Berchet <victor@suumit.com>
21
+ */
22
+ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
23
+ {
24
+ /**
25
+ * @var bool
26
+ */
27
+ private $ignoreUnreadableDirs;
28
+
29
+ /**
30
+ * @var bool
31
+ */
32
+ private $rewindable;
33
+
34
+ /**
35
+ * Constructor.
36
+ *
37
+ * @param string $path
38
+ * @param int $flags
39
+ * @param bool $ignoreUnreadableDirs
40
+ *
41
+ * @throws \RuntimeException
42
+ */
43
+ public function __construct($path, $flags, $ignoreUnreadableDirs = false)
44
+ {
45
+ if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
46
+ throw new \RuntimeException('This iterator only support returning current as fileinfo.');
47
+ }
48
+
49
+ parent::__construct($path, $flags);
50
+ $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
51
+ }
52
+
53
+ /**
54
+ * Return an instance of SplFileInfo with support for relative paths.
55
+ *
56
+ * @return SplFileInfo File information
57
+ */
58
+ public function current()
59
+ {
60
+ return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
61
+ }
62
+
63
+ /**
64
+ * @return \RecursiveIterator
65
+ *
66
+ * @throws AccessDeniedException
67
+ */
68
+ public function getChildren()
69
+ {
70
+ try {
71
+ $children = parent::getChildren();
72
+
73
+ if ($children instanceof self) {
74
+ // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
75
+ $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
76
+ }
77
+
78
+ return $children;
79
+ } catch (\UnexpectedValueException $e) {
80
+ if ($this->ignoreUnreadableDirs) {
81
+ // If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
82
+ return new \RecursiveArrayIterator(array());
83
+ } else {
84
+ throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
85
+ }
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Do nothing for non rewindable stream.
91
+ */
92
+ public function rewind()
93
+ {
94
+ if (false === $this->isRewindable()) {
95
+ return;
96
+ }
97
+
98
+ // @see https://bugs.php.net/bug.php?id=49104
99
+ parent::next();
100
+
101
+ parent::rewind();
102
+ }
103
+
104
+ /**
105
+ * Checks if the stream is rewindable.
106
+ *
107
+ * @return bool true when the stream is rewindable, false otherwise
108
+ */
109
+ public function isRewindable()
110
+ {
111
+ if (null !== $this->rewindable) {
112
+ return $this->rewindable;
113
+ }
114
+
115
+ if (false !== $stream = @opendir($this->getPath())) {
116
+ $infos = stream_get_meta_data($stream);
117
+ closedir($stream);
118
+
119
+ if ($infos['seekable']) {
120
+ return $this->rewindable = true;
121
+ }
122
+ }
123
+
124
+ return $this->rewindable = false;
125
+ }
126
+ }
vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ use Symfony\Component\Finder\Comparator\NumberComparator;
15
+
16
+ /**
17
+ * SizeRangeFilterIterator filters out files that are not in the given size range.
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class SizeRangeFilterIterator extends FilterIterator
22
+ {
23
+ private $comparators = array();
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * @param \Iterator $iterator The Iterator to filter
29
+ * @param NumberComparator[] $comparators An array of NumberComparator instances
30
+ */
31
+ public function __construct(\Iterator $iterator, array $comparators)
32
+ {
33
+ $this->comparators = $comparators;
34
+
35
+ parent::__construct($iterator);
36
+ }
37
+
38
+ /**
39
+ * Filters the iterator values.
40
+ *
41
+ * @return bool true if the value should be kept, false otherwise
42
+ */
43
+ public function accept()
44
+ {
45
+ $fileinfo = $this->current();
46
+ if (!$fileinfo->isFile()) {
47
+ return true;
48
+ }
49
+
50
+ $filesize = $fileinfo->getSize();
51
+ foreach ($this->comparators as $compare) {
52
+ if (!$compare->test($filesize)) {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ return true;
58
+ }
59
+ }
vendor/symfony/finder/Iterator/SortableIterator.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Iterator;
13
+
14
+ /**
15
+ * SortableIterator applies a sort on a given Iterator.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class SortableIterator implements \IteratorAggregate
20
+ {
21
+ const SORT_BY_NAME = 1;
22
+ const SORT_BY_TYPE = 2;
23
+ const SORT_BY_ACCESSED_TIME = 3;
24
+ const SORT_BY_CHANGED_TIME = 4;
25
+ const SORT_BY_MODIFIED_TIME = 5;
26
+
27
+ private $iterator;
28
+ private $sort;
29
+
30
+ /**
31
+ * Constructor.
32
+ *
33
+ * @param \Traversable $iterator The Iterator to filter
34
+ * @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
35
+ *
36
+ * @throws \InvalidArgumentException
37
+ */
38
+ public function __construct(\Traversable $iterator, $sort)
39
+ {
40
+ $this->iterator = $iterator;
41
+
42
+ if (self::SORT_BY_NAME === $sort) {
43
+ $this->sort = function ($a, $b) {
44
+ return strcmp($a->getRealpath(), $b->getRealpath());
45
+ };
46
+ } elseif (self::SORT_BY_TYPE === $sort) {
47
+ $this->sort = function ($a, $b) {
48
+ if ($a->isDir() && $b->isFile()) {
49
+ return -1;
50
+ } elseif ($a->isFile() && $b->isDir()) {
51
+ return 1;
52
+ }
53
+
54
+ return strcmp($a->getRealpath(), $b->getRealpath());
55
+ };
56
+ } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
57
+ $this->sort = function ($a, $b) {
58
+ return ($a->getATime() - $b->getATime());
59
+ };
60
+ } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
61
+ $this->sort = function ($a, $b) {
62
+ return ($a->getCTime() - $b->getCTime());
63
+ };
64
+ } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
65
+ $this->sort = function ($a, $b) {
66
+ return ($a->getMTime() - $b->getMTime());
67
+ };
68
+ } elseif (is_callable($sort)) {
69
+ $this->sort = $sort;
70
+ } else {
71
+ throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
72
+ }
73
+ }
74
+
75
+ public function getIterator()
76
+ {
77
+ $array = iterator_to_array($this->iterator, true);
78
+ uasort($array, $this->sort);
79
+
80
+ return new \ArrayIterator($array);
81
+ }
82
+ }
vendor/symfony/finder/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2004-2015 Fabien Potencier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
vendor/symfony/finder/Shell/Command.php ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Shell;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ class Command
18
+ {
19
+ /**
20
+ * @var Command|null
21
+ */
22
+ private $parent;
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ private $bits = array();
28
+
29
+ /**
30
+ * @var array
31
+ */
32
+ private $labels = array();
33
+
34
+ /**
35
+ * @var \Closure|null
36
+ */
37
+ private $errorHandler;
38
+
39
+ /**
40
+ * Constructor.
41
+ *
42
+ * @param Command|null $parent Parent command
43
+ */
44
+ public function __construct(Command $parent = null)
45
+ {
46
+ $this->parent = $parent;
47
+ }
48
+
49
+ /**
50
+ * Returns command as string.
51
+ *
52
+ * @return string
53
+ */
54
+ public function __toString()
55
+ {
56
+ return $this->join();
57
+ }
58
+
59
+ /**
60
+ * Creates a new Command instance.
61
+ *
62
+ * @param Command|null $parent Parent command
63
+ *
64
+ * @return Command New Command instance
65
+ */
66
+ public static function create(Command $parent = null)
67
+ {
68
+ return new self($parent);
69
+ }
70
+
71
+ /**
72
+ * Escapes special chars from input.
73
+ *
74
+ * @param string $input A string to escape
75
+ *
76
+ * @return string The escaped string
77
+ */
78
+ public static function escape($input)
79
+ {
80
+ return escapeshellcmd($input);
81
+ }
82
+
83
+ /**
84
+ * Quotes input.
85
+ *
86
+ * @param string $input An argument string
87
+ *
88
+ * @return string The quoted string
89
+ */
90
+ public static function quote($input)
91
+ {
92
+ return escapeshellarg($input);
93
+ }
94
+
95
+ /**
96
+ * Appends a string or a Command instance.
97
+ *
98
+ * @param string|Command $bit
99
+ *
100
+ * @return Command The current Command instance
101
+ */
102
+ public function add($bit)
103
+ {
104
+ $this->bits[] = $bit;
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Prepends a string or a command instance.
111
+ *
112
+ * @param string|Command $bit
113
+ *
114
+ * @return Command The current Command instance
115
+ */
116
+ public function top($bit)
117
+ {
118
+ array_unshift($this->bits, $bit);
119
+
120
+ foreach ($this->labels as $label => $index) {
121
+ $this->labels[$label] += 1;
122
+ }
123
+
124
+ return $this;
125
+ }
126
+
127
+ /**
128
+ * Appends an argument, will be quoted.
129
+ *
130
+ * @param string $arg
131
+ *
132
+ * @return Command The current Command instance
133
+ */
134
+ public function arg($arg)
135
+ {
136
+ $this->bits[] = self::quote($arg);
137
+
138
+ return $this;
139
+ }
140
+
141
+ /**
142
+ * Appends escaped special command chars.
143
+ *
144
+ * @param string $esc
145
+ *
146
+ * @return Command The current Command instance
147
+ */
148
+ public function cmd($esc)
149
+ {
150
+ $this->bits[] = self::escape($esc);
151
+
152
+ return $this;
153
+ }
154
+
155
+ /**
156
+ * Inserts a labeled command to feed later.
157
+ *
158
+ * @param string $label The unique label
159
+ *
160
+ * @return Command The current Command instance
161
+ *
162
+ * @throws \RuntimeException If label already exists
163
+ */
164
+ public function ins($label)
165
+ {
166
+ if (isset($this->labels[$label])) {
167
+ throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
168
+ }
169
+
170
+ $this->bits[] = self::create($this);
171
+ $this->labels[$label] = count($this->bits) - 1;
172
+
173
+ return $this->bits[$this->labels[$label]];
174
+ }
175
+
176
+ /**
177
+ * Retrieves a previously labeled command.
178
+ *
179
+ * @param string $label
180
+ *
181
+ * @return Command The labeled command
182
+ *
183
+ * @throws \RuntimeException
184
+ */
185
+ public function get($label)
186
+ {
187
+ if (!isset($this->labels[$label])) {
188
+ throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
189
+ }
190
+
191
+ return $this->bits[$this->labels[$label]];
192
+ }
193
+
194
+ /**
195
+ * Returns parent command (if any).
196
+ *
197
+ * @return Command Parent command
198
+ *
199
+ * @throws \RuntimeException If command has no parent
200
+ */
201
+ public function end()
202
+ {
203
+ if (null === $this->parent) {
204
+ throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
205
+ }
206
+
207
+ return $this->parent;
208
+ }
209
+
210
+ /**
211
+ * Counts bits stored in command.
212
+ *
213
+ * @return int The bits count
214
+ */
215
+ public function length()
216
+ {
217
+ return count($this->bits);
218
+ }
219
+
220
+ /**
221
+ * @param \Closure $errorHandler
222
+ *
223
+ * @return Command
224
+ */
225
+ public function setErrorHandler(\Closure $errorHandler)
226
+ {
227
+ $this->errorHandler = $errorHandler;
228
+
229
+ return $this;
230
+ }
231
+
232
+ /**
233
+ * @return \Closure|null
234
+ */
235
+ public function getErrorHandler()
236
+ {
237
+ return $this->errorHandler;
238
+ }
239
+
240
+ /**
241
+ * Executes current command.
242
+ *
243
+ * @return array The command result
244
+ *
245
+ * @throws \RuntimeException
246
+ */
247
+ public function execute()
248
+ {
249
+ if (null === $errorHandler = $this->errorHandler) {
250
+ exec($this->join(), $output);
251
+ } else {
252
+ $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
253
+ $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
254
+
255
+ if ($error = stream_get_contents($pipes[2])) {
256
+ $errorHandler($error);
257
+ }
258
+
259
+ proc_close($process);
260
+ }
261
+
262
+ return $output ?: array();
263
+ }
264
+
265
+ /**
266
+ * Joins bits.
267
+ *
268
+ * @return string
269
+ */
270
+ public function join()
271
+ {
272
+ return implode(' ', array_filter(
273
+ array_map(function ($bit) {
274
+ return $bit instanceof Command ? $bit->join() : ($bit ?: null);
275
+ }, $this->bits),
276
+ function ($bit) { return null !== $bit; }
277
+ ));
278
+ }
279
+
280
+ /**
281
+ * Insert a string or a Command instance before the bit at given position $index (index starts from 0).
282
+ *
283
+ * @param string|Command $bit
284
+ * @param int $index
285
+ *
286
+ * @return Command The current Command instance
287
+ */
288
+ public function addAtIndex($bit, $index)
289
+ {
290
+ array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit);
291
+
292
+ return $this;
293
+ }
294
+ }
vendor/symfony/finder/Shell/Shell.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Shell;
13
+
14
+ /**
15
+ * @author Jean-François Simon <contact@jfsimon.fr>
16
+ */
17
+ class Shell
18
+ {
19
+ const TYPE_UNIX = 1;
20
+ const TYPE_DARWIN = 2;
21
+ const TYPE_CYGWIN = 3;
22
+ const TYPE_WINDOWS = 4;
23
+ const TYPE_BSD = 5;
24
+
25
+ /**
26
+ * @var string|null
27
+ */
28
+ private $type;
29
+
30
+ /**
31
+ * Returns guessed OS type.
32
+ *
33
+ * @return int
34
+ */
35
+ public function getType()
36
+ {
37
+ if (null === $this->type) {
38
+ $this->type = $this->guessType();
39
+ }
40
+
41
+ return $this->type;
42
+ }
43
+
44
+ /**
45
+ * Tests if a command is available.
46
+ *
47
+ * @param string $command
48
+ *
49
+ * @return bool
50
+ */
51
+ public function testCommand($command)
52
+ {
53
+ if (!function_exists('exec')) {
54
+ return false;
55
+ }
56
+
57
+ // todo: find a better way (command could not be available)
58
+ $testCommand = 'which ';
59
+ if (self::TYPE_WINDOWS === $this->type) {
60
+ $testCommand = 'where ';
61
+ }
62
+
63
+ $command = escapeshellcmd($command);
64
+
65
+ exec($testCommand.$command, $output, $code);
66
+
67
+ return 0 === $code && count($output) > 0;
68
+ }
69
+
70
+ /**
71
+ * Guesses OS type.
72
+ *
73
+ * @return int
74
+ */
75
+ private function guessType()
76
+ {
77
+ $os = strtolower(PHP_OS);
78
+
79
+ if (false !== strpos($os, 'cygwin')) {
80
+ return self::TYPE_CYGWIN;
81
+ }
82
+
83
+ if (false !== strpos($os, 'darwin')) {
84
+ return self::TYPE_DARWIN;
85
+ }
86
+
87
+ if (false !== strpos($os, 'bsd')) {
88
+ return self::TYPE_BSD;
89
+ }
90
+
91
+ if (0 === strpos($os, 'win')) {
92
+ return self::TYPE_WINDOWS;
93
+ }
94
+
95
+ return self::TYPE_UNIX;
96
+ }
97
+ }
vendor/symfony/finder/SplFileInfo.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder;
13
+
14
+ /**
15
+ * Extends \SplFileInfo to support relative paths.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class SplFileInfo extends \SplFileInfo
20
+ {
21
+ private $relativePath;
22
+ private $relativePathname;
23
+
24
+ /**
25
+ * Constructor.
26
+ *
27
+ * @param string $file The file name
28
+ * @param string $relativePath The relative path
29
+ * @param string $relativePathname The relative path name
30
+ */
31
+ public function __construct($file, $relativePath, $relativePathname)
32
+ {
33
+ parent::__construct($file);
34
+ $this->relativePath = $relativePath;
35
+ $this->relativePathname = $relativePathname;
36
+ }
37
+
38
+ /**
39
+ * Returns the relative path.
40
+ *
41
+ * @return string the relative path
42
+ */
43
+ public function getRelativePath()
44
+ {
45
+ return $this->relativePath;
46
+ }
47
+
48
+ /**
49
+ * Returns the relative path name.
50
+ *
51
+ * @return string the relative path name
52
+ */
53
+ public function getRelativePathname()
54
+ {
55
+ return $this->relativePathname;
56
+ }
57
+
58
+ /**
59
+ * Returns the contents of the file.
60
+ *
61
+ * @return string the contents of the file
62
+ *
63
+ * @throws \RuntimeException
64
+ */
65
+ public function getContents()
66
+ {
67
+ $level = error_reporting(0);
68
+ $content = file_get_contents($this->getPathname());
69
+ error_reporting($level);
70
+ if (false === $content) {
71
+ $error = error_get_last();
72
+ throw new \RuntimeException($error['message']);
73
+ }
74
+
75
+ return $content;
76
+ }
77
+ }
vendor/symfony/finder/Tests/Comparator/ComparatorTest.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Comparator;
13
+
14
+ use Symfony\Component\Finder\Comparator\Comparator;
15
+
16
+ class ComparatorTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testGetSetOperator()
19
+ {
20
+ $comparator = new Comparator();
21
+ try {
22
+ $comparator->setOperator('foo');
23
+ $this->fail('->setOperator() throws an \InvalidArgumentException if the operator is not valid.');
24
+ } catch (\Exception $e) {
25
+ $this->assertInstanceOf('InvalidArgumentException', $e, '->setOperator() throws an \InvalidArgumentException if the operator is not valid.');
26
+ }
27
+
28
+ $comparator = new Comparator();
29
+ $comparator->setOperator('>');
30
+ $this->assertEquals('>', $comparator->getOperator(), '->getOperator() returns the current operator');
31
+ }
32
+
33
+ public function testGetSetTarget()
34
+ {
35
+ $comparator = new Comparator();
36
+ $comparator->setTarget(8);
37
+ $this->assertEquals(8, $comparator->getTarget(), '->getTarget() returns the target');
38
+ }
39
+
40
+ /**
41
+ * @dataProvider getTestData
42
+ */
43
+ public function testTest($operator, $target, $match, $noMatch)
44
+ {
45
+ $c = new Comparator();
46
+ $c->setOperator($operator);
47
+ $c->setTarget($target);
48
+
49
+ foreach ($match as $m) {
50
+ $this->assertTrue($c->test($m), '->test() tests a string against the expression');
51
+ }
52
+
53
+ foreach ($noMatch as $m) {
54
+ $this->assertFalse($c->test($m), '->test() tests a string against the expression');
55
+ }
56
+ }
57
+
58
+ public function getTestData()
59
+ {
60
+ return array(
61
+ array('<', '1000', array('500', '999'), array('1000', '1500')),
62
+ );
63
+ }
64
+ }
vendor/symfony/finder/Tests/Comparator/DateComparatorTest.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Comparator;
13
+
14
+ use Symfony\Component\Finder\Comparator\DateComparator;
15
+
16
+ class DateComparatorTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testConstructor()
19
+ {
20
+ try {
21
+ new DateComparator('foobar');
22
+ $this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
23
+ } catch (\Exception $e) {
24
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
25
+ }
26
+
27
+ try {
28
+ new DateComparator('');
29
+ $this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
30
+ } catch (\Exception $e) {
31
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @dataProvider getTestData
37
+ */
38
+ public function testTest($test, $match, $noMatch)
39
+ {
40
+ $c = new DateComparator($test);
41
+
42
+ foreach ($match as $m) {
43
+ $this->assertTrue($c->test($m), '->test() tests a string against the expression');
44
+ }
45
+
46
+ foreach ($noMatch as $m) {
47
+ $this->assertFalse($c->test($m), '->test() tests a string against the expression');
48
+ }
49
+ }
50
+
51
+ public function getTestData()
52
+ {
53
+ return array(
54
+ array('< 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
55
+ array('until 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
56
+ array('before 2005-10-10', array(strtotime('2005-10-09')), array(strtotime('2005-10-15'))),
57
+ array('> 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
58
+ array('after 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
59
+ array('since 2005-10-10', array(strtotime('2005-10-15')), array(strtotime('2005-10-09'))),
60
+ array('!= 2005-10-10', array(strtotime('2005-10-11')), array(strtotime('2005-10-10'))),
61
+ );
62
+ }
63
+ }
vendor/symfony/finder/Tests/Comparator/NumberComparatorTest.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Comparator;
13
+
14
+ use Symfony\Component\Finder\Comparator\NumberComparator;
15
+
16
+ class NumberComparatorTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ /**
19
+ * @dataProvider getConstructorTestData
20
+ */
21
+ public function testConstructor($successes, $failures)
22
+ {
23
+ foreach ($successes as $s) {
24
+ new NumberComparator($s);
25
+ }
26
+
27
+ foreach ($failures as $f) {
28
+ try {
29
+ new NumberComparator($f);
30
+ $this->fail('__construct() throws an \InvalidArgumentException if the test expression is not valid.');
31
+ } catch (\Exception $e) {
32
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException if the test expression is not valid.');
33
+ }
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @dataProvider getTestData
39
+ */
40
+ public function testTest($test, $match, $noMatch)
41
+ {
42
+ $c = new NumberComparator($test);
43
+
44
+ foreach ($match as $m) {
45
+ $this->assertTrue($c->test($m), '->test() tests a string against the expression');
46
+ }
47
+
48
+ foreach ($noMatch as $m) {
49
+ $this->assertFalse($c->test($m), '->test() tests a string against the expression');
50
+ }
51
+ }
52
+
53
+ public function getTestData()
54
+ {
55
+ return array(
56
+ array('< 1000', array('500', '999'), array('1000', '1500')),
57
+
58
+ array('< 1K', array('500', '999'), array('1000', '1500')),
59
+ array('<1k', array('500', '999'), array('1000', '1500')),
60
+ array(' < 1 K ', array('500', '999'), array('1000', '1500')),
61
+ array('<= 1K', array('1000'), array('1001')),
62
+ array('> 1K', array('1001'), array('1000')),
63
+ array('>= 1K', array('1000'), array('999')),
64
+
65
+ array('< 1KI', array('500', '1023'), array('1024', '1500')),
66
+ array('<= 1KI', array('1024'), array('1025')),
67
+ array('> 1KI', array('1025'), array('1024')),
68
+ array('>= 1KI', array('1024'), array('1023')),
69
+
70
+ array('1KI', array('1024'), array('1023', '1025')),
71
+ array('==1KI', array('1024'), array('1023', '1025')),
72
+
73
+ array('==1m', array('1000000'), array('999999', '1000001')),
74
+ array('==1mi', array(1024 * 1024), array(1024 * 1024 - 1, 1024 * 1024 + 1)),
75
+
76
+ array('==1g', array('1000000000'), array('999999999', '1000000001')),
77
+ array('==1gi', array(1024 * 1024 * 1024), array(1024 * 1024 * 1024 - 1, 1024 * 1024 * 1024 + 1)),
78
+
79
+ array('!= 1000', array('500', '999'), array('1000')),
80
+ );
81
+ }
82
+
83
+ public function getConstructorTestData()
84
+ {
85
+ return array(
86
+ array(
87
+ array(
88
+ '1', '0',
89
+ '3.5', '33.55', '123.456', '123456.78',
90
+ '.1', '.123',
91
+ '.0', '0.0',
92
+ '1.', '0.', '123.',
93
+ '==1', '!=1', '<1', '>1', '<=1', '>=1',
94
+ '==1k', '==1ki', '==1m', '==1mi', '==1g', '==1gi',
95
+ '1k', '1ki', '1m', '1mi', '1g', '1gi',
96
+ ),
97
+ array(
98
+ false, null, '',
99
+ ' ', 'foobar',
100
+ '=1', '===1',
101
+ '0 . 1', '123 .45', '234. 567',
102
+ '..', '.0.', '0.1.2',
103
+ ),
104
+ ),
105
+ );
106
+ }
107
+ }
vendor/symfony/finder/Tests/Expression/ExpressionTest.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Expression;
13
+
14
+ use Symfony\Component\Finder\Expression\Expression;
15
+
16
+ class ExpressionTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ /**
19
+ * @dataProvider getTypeGuesserData
20
+ */
21
+ public function testTypeGuesser($expr, $type)
22
+ {
23
+ $this->assertEquals($type, Expression::create($expr)->getType());
24
+ }
25
+
26
+ /**
27
+ * @dataProvider getCaseSensitiveData
28
+ */
29
+ public function testCaseSensitive($expr, $isCaseSensitive)
30
+ {
31
+ $this->assertEquals($isCaseSensitive, Expression::create($expr)->isCaseSensitive());
32
+ }
33
+
34
+ /**
35
+ * @dataProvider getRegexRenderingData
36
+ */
37
+ public function testRegexRendering($expr, $body)
38
+ {
39
+ $this->assertEquals($body, Expression::create($expr)->renderPattern());
40
+ }
41
+
42
+ public function getTypeGuesserData()
43
+ {
44
+ return array(
45
+ array('{foo}', Expression::TYPE_REGEX),
46
+ array('/foo/', Expression::TYPE_REGEX),
47
+ array('foo', Expression::TYPE_GLOB),
48
+ array('foo*', Expression::TYPE_GLOB),
49
+ );
50
+ }
51
+
52
+ public function getCaseSensitiveData()
53
+ {
54
+ return array(
55
+ array('{foo}m', true),
56
+ array('/foo/i', false),
57
+ array('foo*', true),
58
+ );
59
+ }
60
+
61
+ public function getRegexRenderingData()
62
+ {
63
+ return array(
64
+ array('{foo}m', 'foo'),
65
+ array('/foo/i', 'foo'),
66
+ );
67
+ }
68
+ }
vendor/symfony/finder/Tests/Expression/GlobTest.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Expression;
13
+
14
+ use Symfony\Component\Finder\Expression\Expression;
15
+
16
+ class GlobTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ /**
19
+ * @dataProvider getToRegexData
20
+ */
21
+ public function testGlobToRegex($glob, $match, $noMatch)
22
+ {
23
+ foreach ($match as $m) {
24
+ $this->assertRegExp(Expression::create($glob)->getRegex()->render(), $m, '::toRegex() converts a glob to a regexp');
25
+ }
26
+
27
+ foreach ($noMatch as $m) {
28
+ $this->assertNotRegExp(Expression::create($glob)->getRegex()->render(), $m, '::toRegex() converts a glob to a regexp');
29
+ }
30
+ }
31
+
32
+ public function getToRegexData()
33
+ {
34
+ return array(
35
+ array('', array(''), array('f', '/')),
36
+ array('*', array('foo'), array('foo/', '/foo')),
37
+ array('foo.*', array('foo.php', 'foo.a', 'foo.'), array('fooo.php', 'foo.php/foo')),
38
+ array('fo?', array('foo', 'fot'), array('fooo', 'ffoo', 'fo/')),
39
+ array('fo{o,t}', array('foo', 'fot'), array('fob', 'fo/')),
40
+ array('foo(bar|foo)', array('foo(bar|foo)'), array('foobar', 'foofoo')),
41
+ array('foo,bar', array('foo,bar'), array('foo', 'bar')),
42
+ array('fo{o,\\,}', array('foo', 'fo,'), array()),
43
+ array('fo{o,\\\\}', array('foo', 'fo\\'), array()),
44
+ array('/foo', array('/foo'), array('foo')),
45
+ );
46
+ }
47
+ }
vendor/symfony/finder/Tests/Expression/RegexTest.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Expression;
13
+
14
+ use Symfony\Component\Finder\Expression\Expression;
15
+
16
+ class RegexTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ /**
19
+ * @dataProvider getHasFlagsData
20
+ */
21
+ public function testHasFlags($regex, $start, $end)
22
+ {
23
+ $expr = new Expression($regex);
24
+
25
+ $this->assertEquals($start, $expr->getRegex()->hasStartFlag());
26
+ $this->assertEquals($end, $expr->getRegex()->hasEndFlag());
27
+ }
28
+
29
+ /**
30
+ * @dataProvider getHasJokersData
31
+ */
32
+ public function testHasJokers($regex, $start, $end)
33
+ {
34
+ $expr = new Expression($regex);
35
+
36
+ $this->assertEquals($start, $expr->getRegex()->hasStartJoker());
37
+ $this->assertEquals($end, $expr->getRegex()->hasEndJoker());
38
+ }
39
+
40
+ /**
41
+ * @dataProvider getSetFlagsData
42
+ */
43
+ public function testSetFlags($regex, $start, $end, $expected)
44
+ {
45
+ $expr = new Expression($regex);
46
+ $expr->getRegex()->setStartFlag($start)->setEndFlag($end);
47
+
48
+ $this->assertEquals($expected, $expr->render());
49
+ }
50
+
51
+ /**
52
+ * @dataProvider getSetJokersData
53
+ */
54
+ public function testSetJokers($regex, $start, $end, $expected)
55
+ {
56
+ $expr = new Expression($regex);
57
+ $expr->getRegex()->setStartJoker($start)->setEndJoker($end);
58
+
59
+ $this->assertEquals($expected, $expr->render());
60
+ }
61
+
62
+ public function testOptions()
63
+ {
64
+ $expr = new Expression('~abc~is');
65
+ $expr->getRegex()->removeOption('i')->addOption('m');
66
+
67
+ $this->assertEquals('~abc~sm', $expr->render());
68
+ }
69
+
70
+ public function testMixFlagsAndJokers()
71
+ {
72
+ $expr = new Expression('~^.*abc.*$~is');
73
+
74
+ $expr->getRegex()->setStartFlag(false)->setEndFlag(false)->setStartJoker(false)->setEndJoker(false);
75
+ $this->assertEquals('~abc~is', $expr->render());
76
+
77
+ $expr->getRegex()->setStartFlag(true)->setEndFlag(true)->setStartJoker(true)->setEndJoker(true);
78
+ $this->assertEquals('~^.*abc.*$~is', $expr->render());
79
+ }
80
+
81
+ /**
82
+ * @dataProvider getReplaceJokersTestData
83
+ */
84
+ public function testReplaceJokers($regex, $expected)
85
+ {
86
+ $expr = new Expression($regex);
87
+ $expr = $expr->getRegex()->replaceJokers('@');
88
+
89
+ $this->assertEquals($expected, $expr->renderPattern());
90
+ }
91
+
92
+ public function getHasFlagsData()
93
+ {
94
+ return array(
95
+ array('~^abc~', true, false),
96
+ array('~abc$~', false, true),
97
+ array('~abc~', false, false),
98
+ array('~^abc$~', true, true),
99
+ array('~^abc\\$~', true, false),
100
+ );
101
+ }
102
+
103
+ public function getHasJokersData()
104
+ {
105
+ return array(
106
+ array('~.*abc~', true, false),
107
+ array('~abc.*~', false, true),
108
+ array('~abc~', false, false),
109
+ array('~.*abc.*~', true, true),
110
+ array('~.*abc\\.*~', true, false),
111
+ );
112
+ }
113
+
114
+ public function getSetFlagsData()
115
+ {
116
+ return array(
117
+ array('~abc~', true, false, '~^abc~'),
118
+ array('~abc~', false, true, '~abc$~'),
119
+ array('~abc~', false, false, '~abc~'),
120
+ array('~abc~', true, true, '~^abc$~'),
121
+ );
122
+ }
123
+
124
+ public function getSetJokersData()
125
+ {
126
+ return array(
127
+ array('~abc~', true, false, '~.*abc~'),
128
+ array('~abc~', false, true, '~abc.*~'),
129
+ array('~abc~', false, false, '~abc~'),
130
+ array('~abc~', true, true, '~.*abc.*~'),
131
+ );
132
+ }
133
+
134
+ public function getReplaceJokersTestData()
135
+ {
136
+ return array(
137
+ array('~.abc~', '@abc'),
138
+ array('~\\.abc~', '\\.abc'),
139
+ array('~\\\\.abc~', '\\\\@abc'),
140
+ array('~\\\\\\.abc~', '\\\\\\.abc'),
141
+ );
142
+ }
143
+ }
vendor/symfony/finder/Tests/FakeAdapter/DummyAdapter.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\FakeAdapter;
13
+
14
+ use Symfony\Component\Finder\Adapter\AbstractAdapter;
15
+
16
+ /**
17
+ * @author Jean-François Simon <contact@jfsimon.fr>
18
+ */
19
+ class DummyAdapter extends AbstractAdapter
20
+ {
21
+ /**
22
+ * @var \Iterator
23
+ */
24
+ private $iterator;
25
+
26
+ /**
27
+ * @param \Iterator $iterator
28
+ */
29
+ public function __construct(\Iterator $iterator)
30
+ {
31
+ $this->iterator = $iterator;
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ public function searchInDirectory($dir)
38
+ {
39
+ return $this->iterator;
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ public function getName()
46
+ {
47
+ return 'yes';
48
+ }
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ protected function canBeUsed()
54
+ {
55
+ return true;
56
+ }
57
+ }
vendor/symfony/finder/Tests/FakeAdapter/FailingAdapter.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\FakeAdapter;
13
+
14
+ use Symfony\Component\Finder\Adapter\AbstractAdapter;
15
+ use Symfony\Component\Finder\Exception\AdapterFailureException;
16
+
17
+ /**
18
+ * @author Jean-François Simon <contact@jfsimon.fr>
19
+ */
20
+ class FailingAdapter extends AbstractAdapter
21
+ {
22
+ /**
23
+ * {@inheritdoc}
24
+ */
25
+ public function searchInDirectory($dir)
26
+ {
27
+ throw new AdapterFailureException($this);
28
+ }
29
+
30
+ /**
31
+ * {@inheritdoc}
32
+ */
33
+ public function getName()
34
+ {
35
+ return 'failing';
36
+ }
37
+
38
+ /**
39
+ * {@inheritdoc}
40
+ */
41
+ protected function canBeUsed()
42
+ {
43
+ return true;
44
+ }
45
+ }
vendor/symfony/finder/Tests/FakeAdapter/NamedAdapter.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\FakeAdapter;
13
+
14
+ use Symfony\Component\Finder\Adapter\AbstractAdapter;
15
+
16
+ /**
17
+ * @author Jean-François Simon <contact@jfsimon.fr>
18
+ */
19
+ class NamedAdapter extends AbstractAdapter
20
+ {
21
+ /**
22
+ * @var string
23
+ */
24
+ private $name;
25
+
26
+ /**
27
+ * @param string $name
28
+ */
29
+ public function __construct($name)
30
+ {
31
+ $this->name = $name;
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ public function searchInDirectory($dir)
38
+ {
39
+ return new \ArrayIterator(array());
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ public function getName()
46
+ {
47
+ return $this->name;
48
+ }
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ protected function canBeUsed()
54
+ {
55
+ return true;
56
+ }
57
+ }
vendor/symfony/finder/Tests/FakeAdapter/UnsupportedAdapter.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\FakeAdapter;
13
+
14
+ use Symfony\Component\Finder\Adapter\AbstractAdapter;
15
+
16
+ /**
17
+ * @author Jean-François Simon <contact@jfsimon.fr>
18
+ */
19
+ class UnsupportedAdapter extends AbstractAdapter
20
+ {
21
+ /**
22
+ * {@inheritdoc}
23
+ */
24
+ public function searchInDirectory($dir)
25
+ {
26
+ return new \ArrayIterator(array());
27
+ }
28
+
29
+ /**
30
+ * {@inheritdoc}
31
+ */
32
+ public function getName()
33
+ {
34
+ return 'unsupported';
35
+ }
36
+
37
+ /**
38
+ * {@inheritdoc}
39
+ */
40
+ protected function canBeUsed()
41
+ {
42
+ return false;
43
+ }
44
+ }
vendor/symfony/finder/Tests/FinderTest.php ADDED
@@ -0,0 +1,866 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests;
13
+
14
+ use Symfony\Component\Finder\Finder;
15
+ use Symfony\Component\Finder\Adapter;
16
+
17
+ class FinderTest extends Iterator\RealIteratorTestCase
18
+ {
19
+ public function testCreate()
20
+ {
21
+ $this->assertInstanceOf('Symfony\Component\Finder\Finder', Finder::create());
22
+ }
23
+
24
+ /**
25
+ * @dataProvider getAdaptersTestData
26
+ */
27
+ public function testDirectories($adapter)
28
+ {
29
+ $finder = $this->buildFinder($adapter);
30
+ $this->assertSame($finder, $finder->directories());
31
+ $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
32
+
33
+ $finder = $this->buildFinder($adapter);
34
+ $finder->directories();
35
+ $finder->files();
36
+ $finder->directories();
37
+ $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator());
38
+ }
39
+
40
+ /**
41
+ * @dataProvider getAdaptersTestData
42
+ */
43
+ public function testFiles($adapter)
44
+ {
45
+ $finder = $this->buildFinder($adapter);
46
+ $this->assertSame($finder, $finder->files());
47
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
48
+
49
+ $finder = $this->buildFinder($adapter);
50
+ $finder->files();
51
+ $finder->directories();
52
+ $finder->files();
53
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
54
+ }
55
+
56
+ /**
57
+ * @dataProvider getAdaptersTestData
58
+ */
59
+ public function testDepth($adapter)
60
+ {
61
+ $finder = $this->buildFinder($adapter);
62
+ $this->assertSame($finder, $finder->depth('< 1'));
63
+ $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
64
+
65
+ $finder = $this->buildFinder($adapter);
66
+ $this->assertSame($finder, $finder->depth('<= 0'));
67
+ $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
68
+
69
+ $finder = $this->buildFinder($adapter);
70
+ $this->assertSame($finder, $finder->depth('>= 1'));
71
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)->getIterator());
72
+
73
+ $finder = $this->buildFinder($adapter);
74
+ $finder->depth('< 1')->depth('>= 1');
75
+ $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
76
+ }
77
+
78
+ /**
79
+ * @dataProvider getAdaptersTestData
80
+ */
81
+ public function testName($adapter)
82
+ {
83
+ $finder = $this->buildFinder($adapter);
84
+ $this->assertSame($finder, $finder->name('*.php'));
85
+ $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
86
+
87
+ $finder = $this->buildFinder($adapter);
88
+ $finder->name('test.ph*');
89
+ $finder->name('test.py');
90
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
91
+
92
+ $finder = $this->buildFinder($adapter);
93
+ $finder->name('~^test~i');
94
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
95
+
96
+ $finder = $this->buildFinder($adapter);
97
+ $finder->name('~\\.php$~i');
98
+ $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
99
+
100
+ $finder = $this->buildFinder($adapter);
101
+ $finder->name('test.p{hp,y}');
102
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
103
+ }
104
+
105
+ /**
106
+ * @dataProvider getAdaptersTestData
107
+ */
108
+ public function testNotName($adapter)
109
+ {
110
+ $finder = $this->buildFinder($adapter);
111
+ $this->assertSame($finder, $finder->notName('*.php'));
112
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
113
+
114
+ $finder = $this->buildFinder($adapter);
115
+ $finder->notName('*.php');
116
+ $finder->notName('*.py');
117
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
118
+
119
+ $finder = $this->buildFinder($adapter);
120
+ $finder->name('test.ph*');
121
+ $finder->name('test.py');
122
+ $finder->notName('*.php');
123
+ $finder->notName('*.py');
124
+ $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
125
+
126
+ $finder = $this->buildFinder($adapter);
127
+ $finder->name('test.ph*');
128
+ $finder->name('test.py');
129
+ $finder->notName('*.p{hp,y}');
130
+ $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator());
131
+ }
132
+
133
+ /**
134
+ * @dataProvider getRegexNameTestData
135
+ */
136
+ public function testRegexName($adapter, $regex)
137
+ {
138
+ $finder = $this->buildFinder($adapter);
139
+ $finder->name($regex);
140
+ $this->assertIterator($this->toAbsolute(array('test.py', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
141
+ }
142
+
143
+ /**
144
+ * @dataProvider getAdaptersTestData
145
+ */
146
+ public function testSize($adapter)
147
+ {
148
+ $finder = $this->buildFinder($adapter);
149
+ $this->assertSame($finder, $finder->files()->size('< 1K')->size('> 500'));
150
+ $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator());
151
+ }
152
+
153
+ /**
154
+ * @dataProvider getAdaptersTestData
155
+ */
156
+ public function testDate($adapter)
157
+ {
158
+ $finder = $this->buildFinder($adapter);
159
+ $this->assertSame($finder, $finder->files()->date('until last month'));
160
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php')), $finder->in(self::$tmpDir)->getIterator());
161
+ }
162
+
163
+ /**
164
+ * @dataProvider getAdaptersTestData
165
+ */
166
+ public function testExclude($adapter)
167
+ {
168
+ $finder = $this->buildFinder($adapter);
169
+ $this->assertSame($finder, $finder->exclude('foo'));
170
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
171
+ }
172
+
173
+ /**
174
+ * @dataProvider getAdaptersTestData
175
+ */
176
+ public function testIgnoreVCS($adapter)
177
+ {
178
+ $finder = $this->buildFinder($adapter);
179
+ $this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false));
180
+ $this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
181
+
182
+ $finder = $this->buildFinder($adapter);
183
+ $finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false);
184
+ $this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
185
+
186
+ $finder = $this->buildFinder($adapter);
187
+ $this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false));
188
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
189
+ }
190
+
191
+ /**
192
+ * @dataProvider getAdaptersTestData
193
+ */
194
+ public function testIgnoreDotFiles($adapter)
195
+ {
196
+ $finder = $this->buildFinder($adapter);
197
+ $this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false));
198
+ $this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
199
+
200
+ $finder = $this->buildFinder($adapter);
201
+ $finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false);
202
+ $this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
203
+
204
+ $finder = $this->buildFinder($adapter);
205
+ $this->assertSame($finder, $finder->ignoreDotFiles(true)->ignoreVCS(false));
206
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
207
+ }
208
+
209
+ /**
210
+ * @dataProvider getAdaptersTestData
211
+ */
212
+ public function testSortByName($adapter)
213
+ {
214
+ $finder = $this->buildFinder($adapter);
215
+ $this->assertSame($finder, $finder->sortByName());
216
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
217
+ }
218
+
219
+ /**
220
+ * @dataProvider getAdaptersTestData
221
+ */
222
+ public function testSortByType($adapter)
223
+ {
224
+ $finder = $this->buildFinder($adapter);
225
+ $this->assertSame($finder, $finder->sortByType());
226
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'toto', 'foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
227
+ }
228
+
229
+ /**
230
+ * @dataProvider getAdaptersTestData
231
+ */
232
+ public function testSortByAccessedTime($adapter)
233
+ {
234
+ $finder = $this->buildFinder($adapter);
235
+ $this->assertSame($finder, $finder->sortByAccessedTime());
236
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
237
+ }
238
+
239
+ /**
240
+ * @dataProvider getAdaptersTestData
241
+ */
242
+ public function testSortByChangedTime($adapter)
243
+ {
244
+ $finder = $this->buildFinder($adapter);
245
+ $this->assertSame($finder, $finder->sortByChangedTime());
246
+ $this->assertIterator($this->toAbsolute(array('toto', 'test.py', 'test.php', 'foo/bar.tmp', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
247
+ }
248
+
249
+ /**
250
+ * @dataProvider getAdaptersTestData
251
+ */
252
+ public function testSortByModifiedTime($adapter)
253
+ {
254
+ $finder = $this->buildFinder($adapter);
255
+ $this->assertSame($finder, $finder->sortByModifiedTime());
256
+ $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
257
+ }
258
+
259
+ /**
260
+ * @dataProvider getAdaptersTestData
261
+ */
262
+ public function testSort($adapter)
263
+ {
264
+ $finder = $this->buildFinder($adapter);
265
+ $this->assertSame($finder, $finder->sort(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealPath(), $b->getRealPath()); }));
266
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator());
267
+ }
268
+
269
+ /**
270
+ * @dataProvider getAdaptersTestData
271
+ */
272
+ public function testFilter($adapter)
273
+ {
274
+ $finder = $this->buildFinder($adapter);
275
+ $this->assertSame($finder, $finder->filter(function (\SplFileInfo $f) { return false !== strpos($f, 'test'); }));
276
+ $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator());
277
+ }
278
+
279
+ /**
280
+ * @dataProvider getAdaptersTestData
281
+ */
282
+ public function testFollowLinks($adapter)
283
+ {
284
+ if ('\\' == DIRECTORY_SEPARATOR) {
285
+ return;
286
+ }
287
+
288
+ $finder = $this->buildFinder($adapter);
289
+ $this->assertSame($finder, $finder->followLinks());
290
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
291
+ }
292
+
293
+ /**
294
+ * @dataProvider getAdaptersTestData
295
+ */
296
+ public function testIn($adapter)
297
+ {
298
+ $finder = $this->buildFinder($adapter);
299
+ try {
300
+ $finder->in('foobar');
301
+ $this->fail('->in() throws a \InvalidArgumentException if the directory does not exist');
302
+ } catch (\Exception $e) {
303
+ $this->assertInstanceOf('InvalidArgumentException', $e, '->in() throws a \InvalidArgumentException if the directory does not exist');
304
+ }
305
+
306
+ $finder = $this->buildFinder($adapter);
307
+ $iterator = $finder->files()->name('*.php')->depth('< 1')->in(array(self::$tmpDir, __DIR__))->getIterator();
308
+
309
+ $this->assertIterator(array(self::$tmpDir.DIRECTORY_SEPARATOR.'test.php', __DIR__.DIRECTORY_SEPARATOR.'FinderTest.php', __DIR__.DIRECTORY_SEPARATOR.'GlobTest.php'), $iterator);
310
+ }
311
+
312
+ /**
313
+ * @dataProvider getAdaptersTestData
314
+ */
315
+ public function testInWithGlob($adapter)
316
+ {
317
+ $finder = $this->buildFinder($adapter);
318
+ $finder->in(array(__DIR__.'/Fixtures/*/B/C', __DIR__.'/Fixtures/*/*/B/C'))->getIterator();
319
+
320
+ $this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
321
+ }
322
+
323
+ /**
324
+ * @dataProvider getAdaptersTestData
325
+ * @expectedException \InvalidArgumentException
326
+ */
327
+ public function testInWithNonDirectoryGlob($adapter)
328
+ {
329
+ $finder = $this->buildFinder($adapter);
330
+ $finder->in(__DIR__.'/Fixtures/A/a*');
331
+ }
332
+
333
+ /**
334
+ * @dataProvider getAdaptersTestData
335
+ */
336
+ public function testInWithGlobBrace($adapter)
337
+ {
338
+ $finder = $this->buildFinder($adapter);
339
+ $finder->in(array(__DIR__.'/Fixtures/{A,copy/A}/B/C'))->getIterator();
340
+
341
+ $this->assertIterator($this->toAbsoluteFixtures(array('A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy')), $finder);
342
+ }
343
+
344
+ /**
345
+ * @dataProvider getAdaptersTestData
346
+ */
347
+ public function testGetIterator($adapter)
348
+ {
349
+ $finder = $this->buildFinder($adapter);
350
+ try {
351
+ $finder->getIterator();
352
+ $this->fail('->getIterator() throws a \LogicException if the in() method has not been called');
353
+ } catch (\Exception $e) {
354
+ $this->assertInstanceOf('LogicException', $e, '->getIterator() throws a \LogicException if the in() method has not been called');
355
+ }
356
+
357
+ $finder = $this->buildFinder($adapter);
358
+ $dirs = array();
359
+ foreach ($finder->directories()->in(self::$tmpDir) as $dir) {
360
+ $dirs[] = (string) $dir;
361
+ }
362
+
363
+ $expected = $this->toAbsolute(array('foo', 'toto'));
364
+
365
+ sort($dirs);
366
+ sort($expected);
367
+
368
+ $this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface');
369
+
370
+ $finder = $this->buildFinder($adapter);
371
+ $this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface');
372
+
373
+ $finder = $this->buildFinder($adapter);
374
+ $a = iterator_to_array($finder->directories()->in(self::$tmpDir));
375
+ $a = array_values(array_map(function ($a) { return (string) $a; }, $a));
376
+ sort($a);
377
+ $this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface');
378
+ }
379
+
380
+ /**
381
+ * @dataProvider getAdaptersTestData
382
+ */
383
+ public function testRelativePath($adapter)
384
+ {
385
+ $finder = $this->buildFinder($adapter)->in(self::$tmpDir);
386
+
387
+ $paths = array();
388
+
389
+ foreach ($finder as $file) {
390
+ $paths[] = $file->getRelativePath();
391
+ }
392
+
393
+ $ref = array('', '', '', '', 'foo', '');
394
+
395
+ sort($ref);
396
+ sort($paths);
397
+
398
+ $this->assertEquals($ref, $paths);
399
+ }
400
+
401
+ /**
402
+ * @dataProvider getAdaptersTestData
403
+ */
404
+ public function testRelativePathname($adapter)
405
+ {
406
+ $finder = $this->buildFinder($adapter)->in(self::$tmpDir)->sortByName();
407
+
408
+ $paths = array();
409
+
410
+ foreach ($finder as $file) {
411
+ $paths[] = $file->getRelativePathname();
412
+ }
413
+
414
+ $ref = array('test.php', 'toto', 'test.py', 'foo', 'foo'.DIRECTORY_SEPARATOR.'bar.tmp', 'foo bar');
415
+
416
+ sort($paths);
417
+ sort($ref);
418
+
419
+ $this->assertEquals($ref, $paths);
420
+ }
421
+
422
+ /**
423
+ * @dataProvider getAdaptersTestData
424
+ */
425
+ public function testAppendWithAFinder($adapter)
426
+ {
427
+ $finder = $this->buildFinder($adapter);
428
+ $finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
429
+
430
+ $finder1 = $this->buildFinder($adapter);
431
+ $finder1->directories()->in(self::$tmpDir);
432
+
433
+ $finder = $finder->append($finder1);
434
+
435
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
436
+ }
437
+
438
+ /**
439
+ * @dataProvider getAdaptersTestData
440
+ */
441
+ public function testAppendWithAnArray($adapter)
442
+ {
443
+ $finder = $this->buildFinder($adapter);
444
+ $finder->files()->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
445
+
446
+ $finder->append($this->toAbsolute(array('foo', 'toto')));
447
+
448
+ $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->getIterator());
449
+ }
450
+
451
+ /**
452
+ * @dataProvider getAdaptersTestData
453
+ */
454
+ public function testAppendReturnsAFinder($adapter)
455
+ {
456
+ $this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', $this->buildFinder($adapter)->append(array()));
457
+ }
458
+
459
+ /**
460
+ * @dataProvider getAdaptersTestData
461
+ */
462
+ public function testAppendDoesNotRequireIn($adapter)
463
+ {
464
+ $finder = $this->buildFinder($adapter);
465
+ $finder->in(self::$tmpDir.DIRECTORY_SEPARATOR.'foo');
466
+
467
+ $finder1 = Finder::create()->append($finder);
468
+
469
+ $this->assertIterator(iterator_to_array($finder->getIterator()), $finder1->getIterator());
470
+ }
471
+
472
+ public function testCountDirectories()
473
+ {
474
+ $directory = Finder::create()->directories()->in(self::$tmpDir);
475
+ $i = 0;
476
+
477
+ foreach ($directory as $dir) {
478
+ ++$i;
479
+ }
480
+
481
+ $this->assertCount($i, $directory);
482
+ }
483
+
484
+ public function testCountFiles()
485
+ {
486
+ $files = Finder::create()->files()->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures');
487
+ $i = 0;
488
+
489
+ foreach ($files as $file) {
490
+ ++$i;
491
+ }
492
+
493
+ $this->assertCount($i, $files);
494
+ }
495
+
496
+ /**
497
+ * @expectedException \LogicException
498
+ */
499
+ public function testCountWithoutIn()
500
+ {
501
+ $finder = Finder::create()->files();
502
+ count($finder);
503
+ }
504
+
505
+ /**
506
+ * @dataProvider getContainsTestData
507
+ */
508
+ public function testContains($adapter, $matchPatterns, $noMatchPatterns, $expected)
509
+ {
510
+ $finder = $this->buildFinder($adapter);
511
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
512
+ ->name('*.txt')->sortByName()
513
+ ->contains($matchPatterns)
514
+ ->notContains($noMatchPatterns);
515
+
516
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
517
+ }
518
+
519
+ /**
520
+ * @dataProvider getAdaptersTestData
521
+ */
522
+ public function testContainsOnDirectory(Adapter\AdapterInterface $adapter)
523
+ {
524
+ $finder = $this->buildFinder($adapter);
525
+ $finder->in(__DIR__)
526
+ ->directories()
527
+ ->name('Fixtures')
528
+ ->contains('abc');
529
+ $this->assertIterator(array(), $finder);
530
+ }
531
+
532
+ /**
533
+ * @dataProvider getAdaptersTestData
534
+ */
535
+ public function testNotContainsOnDirectory(Adapter\AdapterInterface $adapter)
536
+ {
537
+ $finder = $this->buildFinder($adapter);
538
+ $finder->in(__DIR__)
539
+ ->directories()
540
+ ->name('Fixtures')
541
+ ->notContains('abc');
542
+ $this->assertIterator(array(), $finder);
543
+ }
544
+
545
+ /**
546
+ * Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator
547
+ * with inner FilesystemIterator in an invalid state.
548
+ *
549
+ * @see https://bugs.php.net/bug.php?id=49104
550
+ *
551
+ * @dataProvider getAdaptersTestData
552
+ */
553
+ public function testMultipleLocations(Adapter\AdapterInterface $adapter)
554
+ {
555
+ $locations = array(
556
+ self::$tmpDir.'/',
557
+ self::$tmpDir.'/toto/',
558
+ );
559
+
560
+ // it is expected that there are test.py test.php in the tmpDir
561
+ $finder = $this->buildFinder($adapter);
562
+ $finder->in($locations)->depth('< 1')->name('test.php');
563
+
564
+ $this->assertCount(1, $finder);
565
+ }
566
+
567
+ /**
568
+ * Iterator keys must be the file pathname.
569
+ *
570
+ * @dataProvider getAdaptersTestData
571
+ */
572
+ public function testIteratorKeys(Adapter\AdapterInterface $adapter)
573
+ {
574
+ $finder = $this->buildFinder($adapter)->in(self::$tmpDir);
575
+ foreach ($finder as $key => $file) {
576
+ $this->assertEquals($file->getPathname(), $key);
577
+ }
578
+ }
579
+
580
+ /**
581
+ * @dataProvider getAdaptersTestData
582
+ */
583
+ public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag(Adapter\AdapterInterface $adapter)
584
+ {
585
+ $finder = $this->buildFinder($adapter);
586
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s')
587
+ ->path('/^dir/');
588
+
589
+ $expected = array('r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir',
590
+ 'r+e.gex[c]a(r)s'.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'bar.dat',);
591
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
592
+ }
593
+
594
+ public function testAdaptersOrdering()
595
+ {
596
+ $finder = Finder::create()
597
+ ->removeAdapters()
598
+ ->addAdapter(new FakeAdapter\NamedAdapter('a'), 0)
599
+ ->addAdapter(new FakeAdapter\NamedAdapter('b'), -50)
600
+ ->addAdapter(new FakeAdapter\NamedAdapter('c'), 50)
601
+ ->addAdapter(new FakeAdapter\NamedAdapter('d'), -25)
602
+ ->addAdapter(new FakeAdapter\NamedAdapter('e'), 25);
603
+
604
+ $this->assertEquals(
605
+ array('c', 'e', 'a', 'd', 'b'),
606
+ array_map(function (Adapter\AdapterInterface $adapter) {
607
+ return $adapter->getName();
608
+ }, $finder->getAdapters())
609
+ );
610
+ }
611
+
612
+ public function testAdaptersChaining()
613
+ {
614
+ $iterator = new \ArrayIterator(array());
615
+ $filenames = $this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto'));
616
+ foreach ($filenames as $file) {
617
+ $iterator->append(new \Symfony\Component\Finder\SplFileInfo($file, null, null));
618
+ }
619
+
620
+ $finder = Finder::create()
621
+ ->removeAdapters()
622
+ ->addAdapter(new FakeAdapter\UnsupportedAdapter(), 3)
623
+ ->addAdapter(new FakeAdapter\FailingAdapter(), 2)
624
+ ->addAdapter(new FakeAdapter\DummyAdapter($iterator), 1);
625
+
626
+ $this->assertIterator($filenames, $finder->in(sys_get_temp_dir())->getIterator());
627
+ }
628
+
629
+ public function getAdaptersTestData()
630
+ {
631
+ return array_map(
632
+ function ($adapter) { return array($adapter); },
633
+ $this->getValidAdapters()
634
+ );
635
+ }
636
+
637
+ public function getContainsTestData()
638
+ {
639
+ $tests = array(
640
+ array('', '', array()),
641
+ array('foo', 'bar', array()),
642
+ array('', 'foobar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
643
+ array('lorem ipsum dolor sit amet', 'foobar', array('lorem.txt')),
644
+ array('sit', 'bar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
645
+ array('dolor sit amet', '@^L@m', array('dolor.txt', 'ipsum.txt')),
646
+ array('/^lorem ipsum dolor sit amet$/m', 'foobar', array('lorem.txt')),
647
+ array('lorem', 'foobar', array('lorem.txt')),
648
+ array('', 'lorem', array('dolor.txt', 'ipsum.txt')),
649
+ array('ipsum dolor sit amet', '/^IPSUM/m', array('lorem.txt')),
650
+ );
651
+
652
+ return $this->buildTestData($tests);
653
+ }
654
+
655
+ public function getRegexNameTestData()
656
+ {
657
+ $tests = array(
658
+ array('~.+\\.p.+~i'),
659
+ array('~t.*s~i'),
660
+ );
661
+
662
+ return $this->buildTestData($tests);
663
+ }
664
+
665
+ /**
666
+ * @dataProvider getTestPathData
667
+ */
668
+ public function testPath(Adapter\AdapterInterface $adapter, $matchPatterns, $noMatchPatterns, array $expected)
669
+ {
670
+ $finder = $this->buildFinder($adapter);
671
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
672
+ ->path($matchPatterns)
673
+ ->notPath($noMatchPatterns);
674
+
675
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
676
+ }
677
+
678
+ public function testAdapterSelection()
679
+ {
680
+ // test that by default, PhpAdapter is selected
681
+ $adapters = Finder::create()->getAdapters();
682
+ $this->assertTrue($adapters[0] instanceof Adapter\PhpAdapter);
683
+
684
+ // test another adapter selection
685
+ $adapters = Finder::create()->setAdapter('gnu_find')->getAdapters();
686
+ $this->assertTrue($adapters[0] instanceof Adapter\GnuFindAdapter);
687
+
688
+ // test that useBestAdapter method removes selection
689
+ $adapters = Finder::create()->useBestAdapter()->getAdapters();
690
+ $this->assertFalse($adapters[0] instanceof Adapter\PhpAdapter);
691
+ }
692
+
693
+ public function getTestPathData()
694
+ {
695
+ $tests = array(
696
+ array('', '', array()),
697
+ array('/^A\/B\/C/', '/C$/',
698
+ array('A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat'),
699
+ ),
700
+ array('/^A\/B/', 'foobar',
701
+ array(
702
+ 'A'.DIRECTORY_SEPARATOR.'B',
703
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
704
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
705
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
706
+ ),
707
+ ),
708
+ array('A/B/C', 'foobar',
709
+ array(
710
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
711
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
712
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
713
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
714
+ ),
715
+ ),
716
+ array('A/B', 'foobar',
717
+ array(
718
+ //dirs
719
+ 'A'.DIRECTORY_SEPARATOR.'B',
720
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
721
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B',
722
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
723
+ //files
724
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
725
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
726
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat.copy',
727
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
728
+ ),
729
+ ),
730
+ array('/^with space\//', 'foobar',
731
+ array(
732
+ 'with space'.DIRECTORY_SEPARATOR.'foo.txt',
733
+ ),
734
+ ),
735
+ );
736
+
737
+ return $this->buildTestData($tests);
738
+ }
739
+
740
+ /**
741
+ * @dataProvider getAdaptersTestData
742
+ */
743
+ public function testAccessDeniedException(Adapter\AdapterInterface $adapter)
744
+ {
745
+ if ('\\' === DIRECTORY_SEPARATOR) {
746
+ $this->markTestSkipped('chmod is not supported on Windows');
747
+ }
748
+
749
+ $finder = $this->buildFinder($adapter);
750
+ $finder->files()->in(self::$tmpDir);
751
+
752
+ // make 'foo' directory non-readable
753
+ $testDir = self::$tmpDir.DIRECTORY_SEPARATOR.'foo';
754
+ chmod($testDir, 0333);
755
+
756
+ if (false === $couldRead = is_readable($testDir)) {
757
+ try {
758
+ $this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
759
+ $this->fail('Finder should throw an exception when opening a non-readable directory.');
760
+ } catch (\Exception $e) {
761
+ $expectedExceptionClass = 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException';
762
+ if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
763
+ $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit_Framework_ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
764
+ }
765
+
766
+ $this->assertInstanceOf($expectedExceptionClass, $e);
767
+ }
768
+ }
769
+
770
+ // restore original permissions
771
+ chmod($testDir, 0777);
772
+ clearstatcache($testDir);
773
+
774
+ if ($couldRead) {
775
+ $this->markTestSkipped('could read test files while test requires unreadable');
776
+ }
777
+ }
778
+
779
+ /**
780
+ * @dataProvider getAdaptersTestData
781
+ */
782
+ public function testIgnoredAccessDeniedException(Adapter\AdapterInterface $adapter)
783
+ {
784
+ if ('\\' === DIRECTORY_SEPARATOR) {
785
+ $this->markTestSkipped('chmod is not supported on Windows');
786
+ }
787
+
788
+ $finder = $this->buildFinder($adapter);
789
+ $finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
790
+
791
+ // make 'foo' directory non-readable
792
+ $testDir = self::$tmpDir.DIRECTORY_SEPARATOR.'foo';
793
+ chmod($testDir, 0333);
794
+
795
+ if (false === ($couldRead = is_readable($testDir))) {
796
+ $this->assertIterator($this->toAbsolute(array('foo bar', 'test.php', 'test.py')), $finder->getIterator());
797
+ }
798
+
799
+ // restore original permissions
800
+ chmod($testDir, 0777);
801
+ clearstatcache($testDir);
802
+
803
+ if ($couldRead) {
804
+ $this->markTestSkipped('could read test files while test requires unreadable');
805
+ }
806
+ }
807
+
808
+ private function buildTestData(array $tests)
809
+ {
810
+ $data = array();
811
+ foreach ($this->getValidAdapters() as $adapter) {
812
+ foreach ($tests as $test) {
813
+ $data[] = array_merge(array($adapter), $test);
814
+ }
815
+ }
816
+
817
+ return $data;
818
+ }
819
+
820
+ private function buildFinder(Adapter\AdapterInterface $adapter)
821
+ {
822
+ return Finder::create()
823
+ ->removeAdapters()
824
+ ->addAdapter($adapter);
825
+ }
826
+
827
+ private function getValidAdapters()
828
+ {
829
+ return array_filter(
830
+ array(
831
+ new Adapter\BsdFindAdapter(),
832
+ new Adapter\GnuFindAdapter(),
833
+ new Adapter\PhpAdapter(),
834
+ ),
835
+ function (Adapter\AdapterInterface $adapter) {
836
+ return $adapter->isSupported();
837
+ }
838
+ );
839
+ }
840
+
841
+ /**
842
+ * Searching in multiple locations with sub directories involves
843
+ * AppendIterator which does an unnecessary rewind which leaves
844
+ * FilterIterator with inner FilesystemIterator in an invalid state.
845
+ *
846
+ * @see https://bugs.php.net/bug.php?id=49104
847
+ */
848
+ public function testMultipleLocationsWithSubDirectories()
849
+ {
850
+ $locations = array(
851
+ __DIR__.'/Fixtures/one',
852
+ self::$tmpDir.DIRECTORY_SEPARATOR.'toto',
853
+ );
854
+
855
+ $finder = new Finder();
856
+ $finder->in($locations)->depth('< 10')->name('*.neon');
857
+
858
+ $expected = array(
859
+ __DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'c.neon',
860
+ __DIR__.'/Fixtures/one'.DIRECTORY_SEPARATOR.'b'.DIRECTORY_SEPARATOR.'d.neon',
861
+ );
862
+
863
+ $this->assertIterator($expected, $finder);
864
+ $this->assertIteratorInForeach($expected, $finder);
865
+ }
866
+ }
vendor/symfony/finder/Tests/Fixtures/A/B/C/abc.dat ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/A/B/ab.dat ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/A/a.dat ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/copy/A/B/C/abc.dat.copy ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/copy/A/B/ab.dat.copy ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/copy/A/a.dat.copy ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/dolor.txt ADDED
@@ -0,0 +1,2 @@
 
 
1
+ dolor sit amet
2
+ DOLOR SIT AMET
vendor/symfony/finder/Tests/Fixtures/ipsum.txt ADDED
@@ -0,0 +1,2 @@
 
 
1
+ ipsum dolor sit amet
2
+ IPSUM DOLOR SIT AMET
vendor/symfony/finder/Tests/Fixtures/lorem.txt ADDED
@@ -0,0 +1,2 @@
 
 
1
+ lorem ipsum dolor sit amet
2
+ LOREM IPSUM DOLOR SIT AMET
vendor/symfony/finder/Tests/Fixtures/one/a ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/one/b/c.neon ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/one/b/d.neon ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/r+e.gex[c]a(r)s/dir/bar.dat ADDED
File without changes
vendor/symfony/finder/Tests/Fixtures/with space/foo.txt ADDED
File without changes
vendor/symfony/finder/Tests/GlobTest.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests;
13
+
14
+ use Symfony\Component\Finder\Glob;
15
+
16
+ class GlobTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testGlobToRegexDelimiters()
19
+ {
20
+ $this->assertEquals('#^\.[^/]*$#', Glob::toRegex('.*'));
21
+ $this->assertEquals('^\.[^/]*$', Glob::toRegex('.*', true, true, ''));
22
+ $this->assertEquals('/^\.[^/]*$/', Glob::toRegex('.*', true, true, '/'));
23
+ }
24
+ }
vendor/symfony/finder/Tests/Iterator/CustomFilterIteratorTest.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\CustomFilterIterator;
15
+
16
+ class CustomFilterIteratorTest extends IteratorTestCase
17
+ {
18
+ /**
19
+ * @expectedException \InvalidArgumentException
20
+ */
21
+ public function testWithInvalidFilter()
22
+ {
23
+ new CustomFilterIterator(new Iterator(), array('foo'));
24
+ }
25
+
26
+ /**
27
+ * @dataProvider getAcceptData
28
+ */
29
+ public function testAccept($filters, $expected)
30
+ {
31
+ $inner = new Iterator(array('test.php', 'test.py', 'foo.php'));
32
+
33
+ $iterator = new CustomFilterIterator($inner, $filters);
34
+
35
+ $this->assertIterator($expected, $iterator);
36
+ }
37
+
38
+ public function getAcceptData()
39
+ {
40
+ return array(
41
+ array(array(function (\SplFileInfo $fileinfo) { return false; }), array()),
42
+ array(array(function (\SplFileInfo $fileinfo) { return 0 === strpos($fileinfo, 'test'); }), array('test.php', 'test.py')),
43
+ array(array('is_dir'), array()),
44
+ );
45
+ }
46
+ }
vendor/symfony/finder/Tests/Iterator/DateRangeFilterIteratorTest.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
15
+ use Symfony\Component\Finder\Comparator\DateComparator;
16
+
17
+ class DateRangeFilterIteratorTest extends RealIteratorTestCase
18
+ {
19
+ /**
20
+ * @dataProvider getAcceptData
21
+ */
22
+ public function testAccept($size, $expected)
23
+ {
24
+ $files = self::$files;
25
+ $files[] = self::toAbsolute('doesnotexist');
26
+ $inner = new Iterator($files);
27
+
28
+ $iterator = new DateRangeFilterIterator($inner, $size);
29
+
30
+ $this->assertIterator($expected, $iterator);
31
+ }
32
+
33
+ public function getAcceptData()
34
+ {
35
+ $since20YearsAgo = array(
36
+ '.git',
37
+ 'test.py',
38
+ 'foo',
39
+ 'foo/bar.tmp',
40
+ 'test.php',
41
+ 'toto',
42
+ '.bar',
43
+ '.foo',
44
+ '.foo/.bar',
45
+ 'foo bar',
46
+ '.foo/bar',
47
+ );
48
+
49
+ $since2MonthsAgo = array(
50
+ '.git',
51
+ 'test.py',
52
+ 'foo',
53
+ 'toto',
54
+ '.bar',
55
+ '.foo',
56
+ '.foo/.bar',
57
+ 'foo bar',
58
+ '.foo/bar',
59
+ );
60
+
61
+ $untilLastMonth = array(
62
+ 'foo/bar.tmp',
63
+ 'test.php',
64
+ );
65
+
66
+ return array(
67
+ array(array(new DateComparator('since 20 years ago')), $this->toAbsolute($since20YearsAgo)),
68
+ array(array(new DateComparator('since 2 months ago')), $this->toAbsolute($since2MonthsAgo)),
69
+ array(array(new DateComparator('until last month')), $this->toAbsolute($untilLastMonth)),
70
+ );
71
+ }
72
+ }
vendor/symfony/finder/Tests/Iterator/DepthRangeFilterIteratorTest.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
15
+
16
+ class DepthRangeFilterIteratorTest extends RealIteratorTestCase
17
+ {
18
+ /**
19
+ * @dataProvider getAcceptData
20
+ */
21
+ public function testAccept($minDepth, $maxDepth, $expected)
22
+ {
23
+ $inner = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->toAbsolute(), \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
24
+
25
+ $iterator = new DepthRangeFilterIterator($inner, $minDepth, $maxDepth);
26
+
27
+ $actual = array_keys(iterator_to_array($iterator));
28
+ sort($expected);
29
+ sort($actual);
30
+ $this->assertEquals($expected, $actual);
31
+ }
32
+
33
+ public function getAcceptData()
34
+ {
35
+ $lessThan1 = array(
36
+ '.git',
37
+ 'test.py',
38
+ 'foo',
39
+ 'test.php',
40
+ 'toto',
41
+ '.foo',
42
+ '.bar',
43
+ 'foo bar',
44
+ );
45
+
46
+ $lessThanOrEqualTo1 = array(
47
+ '.git',
48
+ 'test.py',
49
+ 'foo',
50
+ 'foo/bar.tmp',
51
+ 'test.php',
52
+ 'toto',
53
+ '.foo',
54
+ '.foo/.bar',
55
+ '.bar',
56
+ 'foo bar',
57
+ '.foo/bar',
58
+ );
59
+
60
+ $graterThanOrEqualTo1 = array(
61
+ 'foo/bar.tmp',
62
+ '.foo/.bar',
63
+ '.foo/bar',
64
+ );
65
+
66
+ $equalTo1 = array(
67
+ 'foo/bar.tmp',
68
+ '.foo/.bar',
69
+ '.foo/bar',
70
+ );
71
+
72
+ return array(
73
+ array(0, 0, $this->toAbsolute($lessThan1)),
74
+ array(0, 1, $this->toAbsolute($lessThanOrEqualTo1)),
75
+ array(2, PHP_INT_MAX, array()),
76
+ array(1, PHP_INT_MAX, $this->toAbsolute($graterThanOrEqualTo1)),
77
+ array(1, 1, $this->toAbsolute($equalTo1)),
78
+ );
79
+ }
80
+ }
vendor/symfony/finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
15
+ use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
16
+
17
+ class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
18
+ {
19
+ /**
20
+ * @dataProvider getAcceptData
21
+ */
22
+ public function testAccept($directories, $expected)
23
+ {
24
+ $inner = new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->toAbsolute(), \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
25
+
26
+ $iterator = new ExcludeDirectoryFilterIterator($inner, $directories);
27
+
28
+ $this->assertIterator($expected, $iterator);
29
+ }
30
+
31
+ public function getAcceptData()
32
+ {
33
+ $foo = array(
34
+ '.bar',
35
+ '.foo',
36
+ '.foo/.bar',
37
+ '.foo/bar',
38
+ '.git',
39
+ 'test.py',
40
+ 'test.php',
41
+ 'toto',
42
+ 'foo bar',
43
+ );
44
+
45
+ $fo = array(
46
+ '.bar',
47
+ '.foo',
48
+ '.foo/.bar',
49
+ '.foo/bar',
50
+ '.git',
51
+ 'test.py',
52
+ 'foo',
53
+ 'foo/bar.tmp',
54
+ 'test.php',
55
+ 'toto',
56
+ 'foo bar',
57
+ );
58
+
59
+ return array(
60
+ array(array('foo'), $this->toAbsolute($foo)),
61
+ array(array('fo'), $this->toAbsolute($fo)),
62
+ );
63
+ }
64
+ }
vendor/symfony/finder/Tests/Iterator/FilePathsIteratorTest.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\FilePathsIterator;
15
+
16
+ class FilePathsIteratorTest extends RealIteratorTestCase
17
+ {
18
+ /**
19
+ * @dataProvider getSubPathData
20
+ */
21
+ public function testSubPath($baseDir, array $paths, array $subPaths, array $subPathnames)
22
+ {
23
+ $iterator = new FilePathsIterator($paths, $baseDir);
24
+
25
+ foreach ($iterator as $index => $file) {
26
+ $this->assertEquals($paths[$index], $file->getPathname());
27
+ $this->assertEquals($subPaths[$index], $iterator->getSubPath());
28
+ $this->assertEquals($subPathnames[$index], $iterator->getSubPathname());
29
+ }
30
+ }
31
+
32
+ public function getSubPathData()
33
+ {
34
+ $tmpDir = sys_get_temp_dir().'/symfony_finder';
35
+
36
+ return array(
37
+ array(
38
+ $tmpDir,
39
+ array(
40
+ // paths
41
+ $tmpDir.DIRECTORY_SEPARATOR.'.git' => $tmpDir.DIRECTORY_SEPARATOR.'.git',
42
+ $tmpDir.DIRECTORY_SEPARATOR.'test.py' => $tmpDir.DIRECTORY_SEPARATOR.'test.py',
43
+ $tmpDir.DIRECTORY_SEPARATOR.'foo' => $tmpDir.DIRECTORY_SEPARATOR.'foo',
44
+ $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp',
45
+ $tmpDir.DIRECTORY_SEPARATOR.'test.php' => $tmpDir.DIRECTORY_SEPARATOR.'test.php',
46
+ $tmpDir.DIRECTORY_SEPARATOR.'toto' => $tmpDir.DIRECTORY_SEPARATOR.'toto',
47
+ ),
48
+ array(
49
+ // subPaths
50
+ $tmpDir.DIRECTORY_SEPARATOR.'.git' => '',
51
+ $tmpDir.DIRECTORY_SEPARATOR.'test.py' => '',
52
+ $tmpDir.DIRECTORY_SEPARATOR.'foo' => '',
53
+ $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => 'foo',
54
+ $tmpDir.DIRECTORY_SEPARATOR.'test.php' => '',
55
+ $tmpDir.DIRECTORY_SEPARATOR.'toto' => '',
56
+ ),
57
+ array(
58
+ // subPathnames
59
+ $tmpDir.DIRECTORY_SEPARATOR.'.git' => '.git',
60
+ $tmpDir.DIRECTORY_SEPARATOR.'test.py' => 'test.py',
61
+ $tmpDir.DIRECTORY_SEPARATOR.'foo' => 'foo',
62
+ $tmpDir.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'bar.tmp' => 'foo'.DIRECTORY_SEPARATOR.'bar.tmp',
63
+ $tmpDir.DIRECTORY_SEPARATOR.'test.php' => 'test.php',
64
+ $tmpDir.DIRECTORY_SEPARATOR.'toto' => 'toto',
65
+ ),
66
+ ),
67
+ );
68
+ }
69
+ }
vendor/symfony/finder/Tests/Iterator/FileTypeFilterIteratorTest.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\FileTypeFilterIterator;
15
+
16
+ class FileTypeFilterIteratorTest extends RealIteratorTestCase
17
+ {
18
+ /**
19
+ * @dataProvider getAcceptData
20
+ */
21
+ public function testAccept($mode, $expected)
22
+ {
23
+ $inner = new InnerTypeIterator(self::$files);
24
+
25
+ $iterator = new FileTypeFilterIterator($inner, $mode);
26
+
27
+ $this->assertIterator($expected, $iterator);
28
+ }
29
+
30
+ public function getAcceptData()
31
+ {
32
+ $onlyFiles = array(
33
+ 'test.py',
34
+ 'foo/bar.tmp',
35
+ 'test.php',
36
+ '.bar',
37
+ '.foo/.bar',
38
+ '.foo/bar',
39
+ 'foo bar',
40
+ );
41
+
42
+ $onlyDirectories = array(
43
+ '.git',
44
+ 'foo',
45
+ 'toto',
46
+ '.foo',
47
+ );
48
+
49
+ return array(
50
+ array(FileTypeFilterIterator::ONLY_FILES, $this->toAbsolute($onlyFiles)),
51
+ array(FileTypeFilterIterator::ONLY_DIRECTORIES, $this->toAbsolute($onlyDirectories)),
52
+ );
53
+ }
54
+ }
55
+
56
+ class InnerTypeIterator extends \ArrayIterator
57
+ {
58
+ public function current()
59
+ {
60
+ return new \SplFileInfo(parent::current());
61
+ }
62
+
63
+ public function isFile()
64
+ {
65
+ return $this->current()->isFile();
66
+ }
67
+
68
+ public function isDir()
69
+ {
70
+ return $this->current()->isDir();
71
+ }
72
+ }
vendor/symfony/finder/Tests/Iterator/FilecontentFilterIteratorTest.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
15
+
16
+ class FilecontentFilterIteratorTest extends IteratorTestCase
17
+ {
18
+ public function testAccept()
19
+ {
20
+ $inner = new MockFileListIterator(array('test.txt'));
21
+ $iterator = new FilecontentFilterIterator($inner, array(), array());
22
+ $this->assertIterator(array('test.txt'), $iterator);
23
+ }
24
+
25
+ public function testDirectory()
26
+ {
27
+ $inner = new MockFileListIterator(array('directory'));
28
+ $iterator = new FilecontentFilterIterator($inner, array('directory'), array());
29
+ $this->assertIterator(array(), $iterator);
30
+ }
31
+
32
+ public function testUnreadableFile()
33
+ {
34
+ $inner = new MockFileListIterator(array('file r-'));
35
+ $iterator = new FilecontentFilterIterator($inner, array('file r-'), array());
36
+ $this->assertIterator(array(), $iterator);
37
+ }
38
+
39
+ /**
40
+ * @dataProvider getTestFilterData
41
+ */
42
+ public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
43
+ {
44
+ $iterator = new FilecontentFilterIterator($inner, $matchPatterns, $noMatchPatterns);
45
+ $this->assertIterator($resultArray, $iterator);
46
+ }
47
+
48
+ public function getTestFilterData()
49
+ {
50
+ $inner = new MockFileListIterator();
51
+
52
+ $inner[] = new MockSplFileInfo(array(
53
+ 'name' => 'a.txt',
54
+ 'contents' => 'Lorem ipsum...',
55
+ 'type' => 'file',
56
+ 'mode' => 'r+', )
57
+ );
58
+
59
+ $inner[] = new MockSplFileInfo(array(
60
+ 'name' => 'b.yml',
61
+ 'contents' => 'dolor sit...',
62
+ 'type' => 'file',
63
+ 'mode' => 'r+', )
64
+ );
65
+
66
+ $inner[] = new MockSplFileInfo(array(
67
+ 'name' => 'some/other/dir/third.php',
68
+ 'contents' => 'amet...',
69
+ 'type' => 'file',
70
+ 'mode' => 'r+', )
71
+ );
72
+
73
+ $inner[] = new MockSplFileInfo(array(
74
+ 'name' => 'unreadable-file.txt',
75
+ 'contents' => false,
76
+ 'type' => 'file',
77
+ 'mode' => 'r+', )
78
+ );
79
+
80
+ return array(
81
+ array($inner, array('.'), array(), array('a.txt', 'b.yml', 'some/other/dir/third.php')),
82
+ array($inner, array('ipsum'), array(), array('a.txt')),
83
+ array($inner, array('i', 'amet'), array('Lorem', 'amet'), array('b.yml')),
84
+ );
85
+ }
86
+ }
vendor/symfony/finder/Tests/Iterator/FilenameFilterIteratorTest.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
15
+
16
+ class FilenameFilterIteratorTest extends IteratorTestCase
17
+ {
18
+ /**
19
+ * @dataProvider getAcceptData
20
+ */
21
+ public function testAccept($matchPatterns, $noMatchPatterns, $expected)
22
+ {
23
+ $inner = new InnerNameIterator(array('test.php', 'test.py', 'foo.php'));
24
+
25
+ $iterator = new FilenameFilterIterator($inner, $matchPatterns, $noMatchPatterns);
26
+
27
+ $this->assertIterator($expected, $iterator);
28
+ }
29
+
30
+ public function getAcceptData()
31
+ {
32
+ return array(
33
+ array(array('test.*'), array(), array('test.php', 'test.py')),
34
+ array(array(), array('test.*'), array('foo.php')),
35
+ array(array('*.php'), array('test.*'), array('foo.php')),
36
+ array(array('*.php', '*.py'), array('foo.*'), array('test.php', 'test.py')),
37
+ array(array('/\.php$/'), array(), array('test.php', 'foo.php')),
38
+ array(array(), array('/\.php$/'), array('test.py')),
39
+ );
40
+ }
41
+ }
42
+
43
+ class InnerNameIterator extends \ArrayIterator
44
+ {
45
+ public function current()
46
+ {
47
+ return new \SplFileInfo(parent::current());
48
+ }
49
+
50
+ public function getFilename()
51
+ {
52
+ return parent::current();
53
+ }
54
+ }
vendor/symfony/finder/Tests/Iterator/FilterIteratorTest.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ /**
15
+ * @author Alex Bogomazov
16
+ */
17
+ class FilterIteratorTest extends RealIteratorTestCase
18
+ {
19
+ public function testFilterFilesystemIterators()
20
+ {
21
+ $i = new \FilesystemIterator($this->toAbsolute());
22
+
23
+ // it is expected that there are test.py test.php in the tmpDir
24
+ $i = $this->getMockForAbstractClass('Symfony\Component\Finder\Iterator\FilterIterator', array($i));
25
+ $i->expects($this->any())
26
+ ->method('accept')
27
+ ->will($this->returnCallback(function () use ($i) {
28
+ return (bool) preg_match('/\.php/', (string) $i->current());
29
+ })
30
+ );
31
+
32
+ $c = 0;
33
+ foreach ($i as $item) {
34
+ ++$c;
35
+ }
36
+
37
+ $this->assertEquals(1, $c);
38
+
39
+ $i->rewind();
40
+
41
+ $c = 0;
42
+ foreach ($i as $item) {
43
+ ++$c;
44
+ }
45
+
46
+ // This would fail with \FilterIterator but works with Symfony\Component\Finder\Iterator\FilterIterator
47
+ // see https://bugs.php.net/bug.php?id=49104
48
+ $this->assertEquals(1, $c);
49
+ }
50
+ }
vendor/symfony/finder/Tests/Iterator/Iterator.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ class Iterator implements \Iterator
15
+ {
16
+ protected $values = array();
17
+
18
+ public function __construct(array $values = array())
19
+ {
20
+ foreach ($values as $value) {
21
+ $this->attach(new \SplFileInfo($value));
22
+ }
23
+ $this->rewind();
24
+ }
25
+
26
+ public function attach(\SplFileInfo $fileinfo)
27
+ {
28
+ $this->values[] = $fileinfo;
29
+ }
30
+
31
+ public function rewind()
32
+ {
33
+ reset($this->values);
34
+ }
35
+
36
+ public function valid()
37
+ {
38
+ return false !== $this->current();
39
+ }
40
+
41
+ public function next()
42
+ {
43
+ next($this->values);
44
+ }
45
+
46
+ public function current()
47
+ {
48
+ return current($this->values);
49
+ }
50
+
51
+ public function key()
52
+ {
53
+ return key($this->values);
54
+ }
55
+ }
vendor/symfony/finder/Tests/Iterator/IteratorTestCase.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ abstract class IteratorTestCase extends \PHPUnit_Framework_TestCase
15
+ {
16
+ protected function assertIterator($expected, \Traversable $iterator)
17
+ {
18
+ // set iterator_to_array $use_key to false to avoid values merge
19
+ // this made FinderTest::testAppendWithAnArray() failed with GnuFinderAdapter
20
+ $values = array_map(function (\SplFileInfo $fileinfo) { return str_replace('/', DIRECTORY_SEPARATOR, $fileinfo->getPathname()); }, iterator_to_array($iterator, false));
21
+
22
+ $expected = array_map(function ($path) { return str_replace('/', DIRECTORY_SEPARATOR, $path); }, $expected);
23
+
24
+ sort($values);
25
+ sort($expected);
26
+
27
+ $this->assertEquals($expected, array_values($values));
28
+ }
29
+
30
+ protected function assertOrderedIterator($expected, \Traversable $iterator)
31
+ {
32
+ $values = array_map(function (\SplFileInfo $fileinfo) { return $fileinfo->getPathname(); }, iterator_to_array($iterator));
33
+
34
+ $this->assertEquals($expected, array_values($values));
35
+ }
36
+
37
+ /**
38
+ * Same as assertOrderedIterator, but checks the order of groups of
39
+ * array elements.
40
+ *
41
+ * @param array $expected - an array of arrays. For any two subarrays
42
+ * $a and $b such that $a goes before $b in $expected, the method
43
+ * asserts that any element of $a goes before any element of $b
44
+ * in the sequence generated by $iterator
45
+ * @param \Traversable $iterator
46
+ */
47
+ protected function assertOrderedIteratorForGroups($expected, \Traversable $iterator)
48
+ {
49
+ $values = array_values(array_map(function (\SplFileInfo $fileinfo) { return $fileinfo->getPathname(); }, iterator_to_array($iterator)));
50
+
51
+ foreach ($expected as $subarray) {
52
+ $temp = array();
53
+ while (count($values) && count($temp) < count($subarray)) {
54
+ $temp[] = array_shift($values);
55
+ }
56
+ sort($temp);
57
+ sort($subarray);
58
+ $this->assertEquals($subarray, $temp);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Same as IteratorTestCase::assertIterator with foreach usage.
64
+ *
65
+ * @param array $expected
66
+ * @param \Traversable $iterator
67
+ */
68
+ protected function assertIteratorInForeach($expected, \Traversable $iterator)
69
+ {
70
+ $values = array();
71
+ foreach ($iterator as $file) {
72
+ $this->assertInstanceOf('Symfony\\Component\\Finder\\SplFileInfo', $file);
73
+ $values[] = $file->getPathname();
74
+ }
75
+
76
+ sort($values);
77
+ sort($expected);
78
+
79
+ $this->assertEquals($expected, array_values($values));
80
+ }
81
+
82
+ /**
83
+ * Same as IteratorTestCase::assertOrderedIterator with foreach usage.
84
+ *
85
+ * @param array $expected
86
+ * @param \Traversable $iterator
87
+ */
88
+ protected function assertOrderedIteratorInForeach($expected, \Traversable $iterator)
89
+ {
90
+ $values = array();
91
+ foreach ($iterator as $file) {
92
+ $this->assertInstanceOf('Symfony\\Component\\Finder\\SplFileInfo', $file);
93
+ $values[] = $file->getPathname();
94
+ }
95
+
96
+ $this->assertEquals($expected, array_values($values));
97
+ }
98
+ }
vendor/symfony/finder/Tests/Iterator/MockFileListIterator.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ class MockFileListIterator extends \ArrayIterator
15
+ {
16
+ public function __construct(array $filesArray = array())
17
+ {
18
+ $files = array_map(function ($file) { return new MockSplFileInfo($file); }, $filesArray);
19
+ parent::__construct($files);
20
+ }
21
+ }
vendor/symfony/finder/Tests/Iterator/MockSplFileInfo.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ class MockSplFileInfo extends \SplFileInfo
15
+ {
16
+ const TYPE_DIRECTORY = 1;
17
+ const TYPE_FILE = 2;
18
+ const TYPE_UNKNOWN = 3;
19
+
20
+ private $contents = null;
21
+ private $mode = null;
22
+ private $type = null;
23
+ private $relativePath = null;
24
+ private $relativePathname = null;
25
+
26
+ public function __construct($param)
27
+ {
28
+ if (is_string($param)) {
29
+ parent::__construct($param);
30
+ } elseif (is_array($param)) {
31
+ $defaults = array(
32
+ 'name' => 'file.txt',
33
+ 'contents' => null,
34
+ 'mode' => null,
35
+ 'type' => null,
36
+ 'relativePath' => null,
37
+ 'relativePathname' => null,
38
+ );
39
+ $defaults = array_merge($defaults, $param);
40
+ parent::__construct($defaults['name']);
41
+ $this->setContents($defaults['contents']);
42
+ $this->setMode($defaults['mode']);
43
+ $this->setType($defaults['type']);
44
+ $this->setRelativePath($defaults['relativePath']);
45
+ $this->setRelativePathname($defaults['relativePathname']);
46
+ } else {
47
+ throw new \RuntimeException(sprintf('Incorrect parameter "%s"', $param));
48
+ }
49
+ }
50
+
51
+ public function isFile()
52
+ {
53
+ if (null === $this->type) {
54
+ return false !== strpos($this->getFilename(), 'file');
55
+ };
56
+
57
+ return self::TYPE_FILE === $this->type;
58
+ }
59
+
60
+ public function isDir()
61
+ {
62
+ if (null === $this->type) {
63
+ return false !== strpos($this->getFilename(), 'directory');
64
+ }
65
+
66
+ return self::TYPE_DIRECTORY === $this->type;
67
+ }
68
+
69
+ public function isReadable()
70
+ {
71
+ if (null === $this->mode) {
72
+ return preg_match('/r\+/', $this->getFilename());
73
+ }
74
+
75
+ return preg_match('/r\+/', $this->mode);
76
+ }
77
+
78
+ public function getContents()
79
+ {
80
+ return $this->contents;
81
+ }
82
+
83
+ public function setContents($contents)
84
+ {
85
+ $this->contents = $contents;
86
+ }
87
+
88
+ public function setMode($mode)
89
+ {
90
+ $this->mode = $mode;
91
+ }
92
+
93
+ public function setType($type)
94
+ {
95
+ if (is_string($type)) {
96
+ switch ($type) {
97
+ case 'directory':
98
+ $this->type = self::TYPE_DIRECTORY;
99
+ case 'd':
100
+ $this->type = self::TYPE_DIRECTORY;
101
+ break;
102
+ case 'file':
103
+ $this->type = self::TYPE_FILE;
104
+ case 'f':
105
+ $this->type = self::TYPE_FILE;
106
+ break;
107
+ default:
108
+ $this->type = self::TYPE_UNKNOWN;
109
+ }
110
+ } else {
111
+ $this->type = $type;
112
+ }
113
+ }
114
+
115
+ public function setRelativePath($relativePath)
116
+ {
117
+ $this->relativePath = $relativePath;
118
+ }
119
+
120
+ public function setRelativePathname($relativePathname)
121
+ {
122
+ $this->relativePathname = $relativePathname;
123
+ }
124
+
125
+ public function getRelativePath()
126
+ {
127
+ return $this->relativePath;
128
+ }
129
+
130
+ public function getRelativePathname()
131
+ {
132
+ return $this->relativePathname;
133
+ }
134
+ }
vendor/symfony/finder/Tests/Iterator/MultiplePcreFilterIteratorTest.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator;
15
+
16
+ class MultiplePcreFilterIteratorTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ /**
19
+ * @dataProvider getIsRegexFixtures
20
+ */
21
+ public function testIsRegex($string, $isRegex, $message)
22
+ {
23
+ $testIterator = new TestMultiplePcreFilterIterator();
24
+ $this->assertEquals($isRegex, $testIterator->isRegex($string), $message);
25
+ }
26
+
27
+ public function getIsRegexFixtures()
28
+ {
29
+ return array(
30
+ array('foo', false, 'string'),
31
+ array(' foo ', false, '" " is not a valid delimiter'),
32
+ array('\\foo\\', false, '"\\" is not a valid delimiter'),
33
+ array('afooa', false, '"a" is not a valid delimiter'),
34
+ array('//', false, 'the pattern should contain at least 1 character'),
35
+ array('/a/', true, 'valid regex'),
36
+ array('/foo/', true, 'valid regex'),
37
+ array('/foo/i', true, 'valid regex with a single modifier'),
38
+ array('/foo/imsxu', true, 'valid regex with multiple modifiers'),
39
+ array('#foo#', true, '"#" is a valid delimiter'),
40
+ array('{foo}', true, '"{,}" is a valid delimiter pair'),
41
+ array('*foo.*', false, '"*" is not considered as a valid delimiter'),
42
+ array('?foo.?', false, '"?" is not considered as a valid delimiter'),
43
+ );
44
+ }
45
+ }
46
+
47
+ class TestMultiplePcreFilterIterator extends MultiplePcreFilterIterator
48
+ {
49
+ public function __construct()
50
+ {
51
+ }
52
+
53
+ public function accept()
54
+ {
55
+ throw new \BadFunctionCallException('Not implemented');
56
+ }
57
+
58
+ public function isRegex($str)
59
+ {
60
+ return parent::isRegex($str);
61
+ }
62
+
63
+ public function toRegex($str)
64
+ {
65
+ throw new \BadFunctionCallException('Not implemented');
66
+ }
67
+ }
vendor/symfony/finder/Tests/Iterator/PathFilterIteratorTest.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\PathFilterIterator;
15
+
16
+ class PathFilterIteratorTest extends IteratorTestCase
17
+ {
18
+ /**
19
+ * @dataProvider getTestFilterData
20
+ */
21
+ public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
22
+ {
23
+ $iterator = new PathFilterIterator($inner, $matchPatterns, $noMatchPatterns);
24
+ $this->assertIterator($resultArray, $iterator);
25
+ }
26
+
27
+ public function getTestFilterData()
28
+ {
29
+ $inner = new MockFileListIterator();
30
+
31
+ //PATH: A/B/C/abc.dat
32
+ $inner[] = new MockSplFileInfo(array(
33
+ 'name' => 'abc.dat',
34
+ 'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
35
+ ));
36
+
37
+ //PATH: A/B/ab.dat
38
+ $inner[] = new MockSplFileInfo(array(
39
+ 'name' => 'ab.dat',
40
+ 'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
41
+ ));
42
+
43
+ //PATH: A/a.dat
44
+ $inner[] = new MockSplFileInfo(array(
45
+ 'name' => 'a.dat',
46
+ 'relativePathname' => 'A'.DIRECTORY_SEPARATOR.'a.dat',
47
+ ));
48
+
49
+ //PATH: copy/A/B/C/abc.dat.copy
50
+ $inner[] = new MockSplFileInfo(array(
51
+ 'name' => 'abc.dat.copy',
52
+ 'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
53
+ ));
54
+
55
+ //PATH: copy/A/B/ab.dat.copy
56
+ $inner[] = new MockSplFileInfo(array(
57
+ 'name' => 'ab.dat.copy',
58
+ 'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
59
+ ));
60
+
61
+ //PATH: copy/A/a.dat.copy
62
+ $inner[] = new MockSplFileInfo(array(
63
+ 'name' => 'a.dat.copy',
64
+ 'relativePathname' => 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'a.dat',
65
+ ));
66
+
67
+ return array(
68
+ array($inner, array('/^A/'), array(), array('abc.dat', 'ab.dat', 'a.dat')),
69
+ array($inner, array('/^A\/B/'), array(), array('abc.dat', 'ab.dat')),
70
+ array($inner, array('/^A\/B\/C/'), array(), array('abc.dat')),
71
+ array($inner, array('/A\/B\/C/'), array(), array('abc.dat', 'abc.dat.copy')),
72
+
73
+ array($inner, array('A'), array(), array('abc.dat', 'ab.dat', 'a.dat', 'abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
74
+ array($inner, array('A/B'), array(), array('abc.dat', 'ab.dat', 'abc.dat.copy', 'ab.dat.copy')),
75
+ array($inner, array('A/B/C'), array(), array('abc.dat', 'abc.dat.copy')),
76
+
77
+ array($inner, array('copy/A'), array(), array('abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
78
+ array($inner, array('copy/A/B'), array(), array('abc.dat.copy', 'ab.dat.copy')),
79
+ array($inner, array('copy/A/B/C'), array(), array('abc.dat.copy')),
80
+
81
+ );
82
+ }
83
+ }
vendor/symfony/finder/Tests/Iterator/RealIteratorTestCase.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ abstract class RealIteratorTestCase extends IteratorTestCase
15
+ {
16
+ protected static $tmpDir;
17
+ protected static $files;
18
+
19
+ public static function setUpBeforeClass()
20
+ {
21
+ self::$tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'symfony_finder';
22
+
23
+ self::$files = array(
24
+ '.git/',
25
+ '.foo/',
26
+ '.foo/.bar',
27
+ '.foo/bar',
28
+ '.bar',
29
+ 'test.py',
30
+ 'foo/',
31
+ 'foo/bar.tmp',
32
+ 'test.php',
33
+ 'toto/',
34
+ 'foo bar',
35
+ );
36
+
37
+ self::$files = self::toAbsolute(self::$files);
38
+
39
+ if (is_dir(self::$tmpDir)) {
40
+ self::tearDownAfterClass();
41
+ } else {
42
+ mkdir(self::$tmpDir);
43
+ }
44
+
45
+ foreach (self::$files as $file) {
46
+ if (DIRECTORY_SEPARATOR === $file[strlen($file) - 1]) {
47
+ mkdir($file);
48
+ } else {
49
+ touch($file);
50
+ }
51
+ }
52
+
53
+ file_put_contents(self::toAbsolute('test.php'), str_repeat(' ', 800));
54
+ file_put_contents(self::toAbsolute('test.py'), str_repeat(' ', 2000));
55
+
56
+ touch(self::toAbsolute('foo/bar.tmp'), strtotime('2005-10-15'));
57
+ touch(self::toAbsolute('test.php'), strtotime('2005-10-15'));
58
+ }
59
+
60
+ public static function tearDownAfterClass()
61
+ {
62
+ foreach (array_reverse(self::$files) as $file) {
63
+ if (DIRECTORY_SEPARATOR === $file[strlen($file) - 1]) {
64
+ @rmdir($file);
65
+ } else {
66
+ @unlink($file);
67
+ }
68
+ }
69
+ }
70
+
71
+ protected static function toAbsolute($files = null)
72
+ {
73
+ /*
74
+ * Without the call to setUpBeforeClass() property can be null.
75
+ */
76
+ if (!self::$tmpDir) {
77
+ self::$tmpDir = realpath(sys_get_temp_dir()).DIRECTORY_SEPARATOR.'symfony_finder';
78
+ }
79
+
80
+ if (is_array($files)) {
81
+ $f = array();
82
+ foreach ($files as $file) {
83
+ if (is_array($file)) {
84
+ $f[] = self::toAbsolute($file);
85
+ } else {
86
+ $f[] = self::$tmpDir.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $file);
87
+ }
88
+ }
89
+
90
+ return $f;
91
+ }
92
+
93
+ if (is_string($files)) {
94
+ return self::$tmpDir.DIRECTORY_SEPARATOR.str_replace('/', DIRECTORY_SEPARATOR, $files);
95
+ }
96
+
97
+ return self::$tmpDir;
98
+ }
99
+
100
+ protected static function toAbsoluteFixtures($files)
101
+ {
102
+ $f = array();
103
+ foreach ($files as $file) {
104
+ $f[] = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$file);
105
+ }
106
+
107
+ return $f;
108
+ }
109
+ }
vendor/symfony/finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
15
+
16
+ class RecursiveDirectoryIteratorTest extends IteratorTestCase
17
+ {
18
+ /**
19
+ * @dataProvider getPaths
20
+ *
21
+ * @param string $path
22
+ * @param bool $seekable
23
+ * @param array $contains
24
+ * @param string $message
25
+ */
26
+ public function testRewind($path, $seekable, $contains, $message = null)
27
+ {
28
+ try {
29
+ $i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
30
+ } catch (\UnexpectedValueException $e) {
31
+ $this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
32
+ }
33
+
34
+ $i->rewind();
35
+
36
+ $this->assertTrue(true, $message);
37
+ }
38
+
39
+ /**
40
+ * @dataProvider getPaths
41
+ *
42
+ * @param string $path
43
+ * @param bool $seekable
44
+ * @param array $contains
45
+ * @param string $message
46
+ */
47
+ public function testSeek($path, $seekable, $contains, $message = null)
48
+ {
49
+ try {
50
+ $i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
51
+ } catch (\UnexpectedValueException $e) {
52
+ $this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
53
+ }
54
+
55
+ $actual = array();
56
+
57
+ $i->seek(0);
58
+ $actual[] = $i->getPathname();
59
+
60
+ $i->seek(1);
61
+ $actual[] = $i->getPathname();
62
+
63
+ $i->seek(2);
64
+ $actual[] = $i->getPathname();
65
+
66
+ $this->assertEquals($contains, $actual);
67
+ }
68
+
69
+ public function getPaths()
70
+ {
71
+ $data = array();
72
+
73
+ // ftp
74
+ $contains = array(
75
+ 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README',
76
+ 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html',
77
+ 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub',
78
+ );
79
+ $data[] = array('ftp://ftp.mozilla.org/', false, $contains);
80
+
81
+ return $data;
82
+ }
83
+ }
vendor/symfony/finder/Tests/Iterator/SizeRangeFilterIteratorTest.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
15
+ use Symfony\Component\Finder\Comparator\NumberComparator;
16
+
17
+ class SizeRangeFilterIteratorTest extends RealIteratorTestCase
18
+ {
19
+ /**
20
+ * @dataProvider getAcceptData
21
+ */
22
+ public function testAccept($size, $expected)
23
+ {
24
+ $inner = new InnerSizeIterator(self::$files);
25
+
26
+ $iterator = new SizeRangeFilterIterator($inner, $size);
27
+
28
+ $this->assertIterator($expected, $iterator);
29
+ }
30
+
31
+ public function getAcceptData()
32
+ {
33
+ $lessThan1KGreaterThan05K = array(
34
+ '.foo',
35
+ '.git',
36
+ 'foo',
37
+ 'test.php',
38
+ 'toto',
39
+ );
40
+
41
+ return array(
42
+ array(array(new NumberComparator('< 1K'), new NumberComparator('> 0.5K')), $this->toAbsolute($lessThan1KGreaterThan05K)),
43
+ );
44
+ }
45
+ }
46
+
47
+ class InnerSizeIterator extends \ArrayIterator
48
+ {
49
+ public function current()
50
+ {
51
+ return new \SplFileInfo(parent::current());
52
+ }
53
+
54
+ public function getFilename()
55
+ {
56
+ return parent::current();
57
+ }
58
+
59
+ public function isFile()
60
+ {
61
+ return $this->current()->isFile();
62
+ }
63
+
64
+ public function getSize()
65
+ {
66
+ return $this->current()->getSize();
67
+ }
68
+ }
vendor/symfony/finder/Tests/Iterator/SortableIteratorTest.php ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Iterator;
13
+
14
+ use Symfony\Component\Finder\Iterator\SortableIterator;
15
+
16
+ class SortableIteratorTest extends RealIteratorTestCase
17
+ {
18
+ public function testConstructor()
19
+ {
20
+ try {
21
+ new SortableIterator(new Iterator(array()), 'foobar');
22
+ $this->fail('__construct() throws an \InvalidArgumentException exception if the mode is not valid');
23
+ } catch (\Exception $e) {
24
+ $this->assertInstanceOf('InvalidArgumentException', $e, '__construct() throws an \InvalidArgumentException exception if the mode is not valid');
25
+ }
26
+ }
27
+
28
+ /**
29
+ * @dataProvider getAcceptData
30
+ */
31
+ public function testAccept($mode, $expected)
32
+ {
33
+ if (!is_callable($mode)) {
34
+ switch ($mode) {
35
+ case SortableIterator::SORT_BY_ACCESSED_TIME :
36
+ file_get_contents(self::toAbsolute('.git'));
37
+ sleep(1);
38
+ file_get_contents(self::toAbsolute('.bar'));
39
+ break;
40
+ case SortableIterator::SORT_BY_CHANGED_TIME :
41
+ file_put_contents(self::toAbsolute('test.php'), 'foo');
42
+ sleep(1);
43
+ file_put_contents(self::toAbsolute('test.py'), 'foo');
44
+ break;
45
+ case SortableIterator::SORT_BY_MODIFIED_TIME :
46
+ file_put_contents(self::toAbsolute('test.php'), 'foo');
47
+ sleep(1);
48
+ file_put_contents(self::toAbsolute('test.py'), 'foo');
49
+ break;
50
+ }
51
+ }
52
+
53
+ $inner = new Iterator(self::$files);
54
+
55
+ $iterator = new SortableIterator($inner, $mode);
56
+
57
+ if ($mode === SortableIterator::SORT_BY_ACCESSED_TIME
58
+ || $mode === SortableIterator::SORT_BY_CHANGED_TIME
59
+ || $mode === SortableIterator::SORT_BY_MODIFIED_TIME) {
60
+ $this->assertOrderedIteratorForGroups($expected, $iterator);
61
+ } else {
62
+ $this->assertOrderedIterator($expected, $iterator);
63
+ }
64
+ }
65
+
66
+ public function getAcceptData()
67
+ {
68
+ $sortByName = array(
69
+ '.bar',
70
+ '.foo',
71
+ '.foo/.bar',
72
+ '.foo/bar',
73
+ '.git',
74
+ 'foo',
75
+ 'foo bar',
76
+ 'foo/bar.tmp',
77
+ 'test.php',
78
+ 'test.py',
79
+ 'toto',
80
+ );
81
+
82
+ $sortByType = array(
83
+ '.foo',
84
+ '.git',
85
+ 'foo',
86
+ 'toto',
87
+ '.bar',
88
+ '.foo/.bar',
89
+ '.foo/bar',
90
+ 'foo bar',
91
+ 'foo/bar.tmp',
92
+ 'test.php',
93
+ 'test.py',
94
+ );
95
+
96
+ $customComparison = array(
97
+ '.bar',
98
+ '.foo',
99
+ '.foo/.bar',
100
+ '.foo/bar',
101
+ '.git',
102
+ 'foo',
103
+ 'foo bar',
104
+ 'foo/bar.tmp',
105
+ 'test.php',
106
+ 'test.py',
107
+ 'toto',
108
+ );
109
+
110
+ $sortByAccessedTime = array(
111
+ // For these two files the access time was set to 2005-10-15
112
+ array('foo/bar.tmp', 'test.php'),
113
+ // These files were created more or less at the same time
114
+ array(
115
+ '.git',
116
+ '.foo',
117
+ '.foo/.bar',
118
+ '.foo/bar',
119
+ 'test.py',
120
+ 'foo',
121
+ 'toto',
122
+ 'foo bar',
123
+ ),
124
+ // This file was accessed after sleeping for 1 sec
125
+ array('.bar'),
126
+ );
127
+
128
+ $sortByChangedTime = array(
129
+ array(
130
+ '.git',
131
+ '.foo',
132
+ '.foo/.bar',
133
+ '.foo/bar',
134
+ '.bar',
135
+ 'foo',
136
+ 'foo/bar.tmp',
137
+ 'toto',
138
+ 'foo bar',
139
+ ),
140
+ array('test.php'),
141
+ array('test.py'),
142
+ );
143
+
144
+ $sortByModifiedTime = array(
145
+ array(
146
+ '.git',
147
+ '.foo',
148
+ '.foo/.bar',
149
+ '.foo/bar',
150
+ '.bar',
151
+ 'foo',
152
+ 'foo/bar.tmp',
153
+ 'toto',
154
+ 'foo bar',
155
+ ),
156
+ array('test.php'),
157
+ array('test.py'),
158
+ );
159
+
160
+ return array(
161
+ array(SortableIterator::SORT_BY_NAME, $this->toAbsolute($sortByName)),
162
+ array(SortableIterator::SORT_BY_TYPE, $this->toAbsolute($sortByType)),
163
+ array(SortableIterator::SORT_BY_ACCESSED_TIME, $this->toAbsolute($sortByAccessedTime)),
164
+ array(SortableIterator::SORT_BY_CHANGED_TIME, $this->toAbsolute($sortByChangedTime)),
165
+ array(SortableIterator::SORT_BY_MODIFIED_TIME, $this->toAbsolute($sortByModifiedTime)),
166
+ array(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealPath(), $b->getRealPath()); }, $this->toAbsolute($customComparison)),
167
+ );
168
+ }
169
+ }
vendor/symfony/finder/Tests/Shell/CommandTest.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ namespace Symfony\Component\Finder\Tests\Shell;
13
+
14
+ use Symfony\Component\Finder\Shell\Command;
15
+
16
+ class CommandTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testCreate()
19
+ {
20
+ $this->assertInstanceOf('Symfony\Component\Finder\Shell\Command', Command::create());
21
+ }
22
+
23
+ public function testAdd()
24
+ {
25
+ $cmd = Command::create()->add('--force');
26
+ $this->assertSame('--force', $cmd->join());
27
+ }
28
+
29
+ public function testAddAsFirst()
30
+ {
31
+ $cmd = Command::create()->add('--force');
32
+
33
+ $cmd->addAtIndex(Command::create()->add('-F'), 0);
34
+ $this->assertSame('-F --force', $cmd->join());
35
+ }
36
+
37
+ public function testAddAsLast()
38
+ {
39
+ $cmd = Command::create()->add('--force');
40
+
41
+ $cmd->addAtIndex(Command::create()->add('-F'), 1);
42
+ $this->assertSame('--force -F', $cmd->join());
43
+ }
44
+
45
+ public function testAddInBetween()
46
+ {
47
+ $cmd = Command::create()->add('--force');
48
+ $cmd->addAtIndex(Command::create()->add('-F'), 0);
49
+
50
+ $cmd->addAtIndex(Command::create()->add('-X'), 1);
51
+ $this->assertSame('-F -X --force', $cmd->join());
52
+ }
53
+
54
+ public function testCount()
55
+ {
56
+ $cmd = Command::create();
57
+ $this->assertSame(0, $cmd->length());
58
+
59
+ $cmd->add('--force');
60
+ $this->assertSame(1, $cmd->length());
61
+
62
+ $cmd->add('--run');
63
+ $this->assertSame(2, $cmd->length());
64
+ }
65
+
66
+ public function testTop()
67
+ {
68
+ $cmd = Command::create()->add('--force');
69
+
70
+ $cmd->top('--run');
71
+ $this->assertSame('--run --force', $cmd->join());
72
+ }
73
+
74
+ public function testTopLabeled()
75
+ {
76
+ $cmd = Command::create()->add('--force');
77
+
78
+ $cmd->top('--run');
79
+ $cmd->ins('--something');
80
+ $cmd->top('--something');
81
+ $this->assertSame('--something --run --force ', $cmd->join());
82
+ }
83
+
84
+ public function testArg()
85
+ {
86
+ $cmd = Command::create()->add('--force');
87
+
88
+ $cmd->arg('--run');
89
+ $this->assertSame('--force \'--run\'', $cmd->join());
90
+ }
91
+
92
+ public function testCmd()
93
+ {
94
+ $cmd = Command::create()->add('--force');
95
+
96
+ $cmd->cmd('run');
97
+ $this->assertSame('--force run', $cmd->join());
98
+ }
99
+
100
+ public function testInsDuplicateLabelException()
101
+ {
102
+ $cmd = Command::create()->add('--force');
103
+
104
+ $cmd->ins('label');
105
+ $this->setExpectedException('RuntimeException');
106
+ $cmd->ins('label');
107
+ }
108
+
109
+ public function testEnd()
110
+ {
111
+ $parent = Command::create();
112
+ $cmd = Command::create($parent);
113
+
114
+ $this->assertSame($parent, $cmd->end());
115
+ }
116
+
117
+ public function testEndNoParentException()
118
+ {
119
+ $cmd = Command::create();
120
+
121
+ $this->setExpectedException('RuntimeException');
122
+ $cmd->end();
123
+ }
124
+
125
+ public function testGetMissingLabelException()
126
+ {
127
+ $cmd = Command::create();
128
+
129
+ $this->setExpectedException('RuntimeException');
130
+ $cmd->get('invalid');
131
+ }
132
+
133
+ public function testErrorHandler()
134
+ {
135
+ $cmd = Command::create();
136
+ $handler = function() { return 'error-handler'; };
137
+ $cmd->setErrorHandler($handler);
138
+
139
+ $this->assertSame($handler, $cmd->getErrorHandler());
140
+ }
141
+
142
+ public function testExecute()
143
+ {
144
+ $cmd = Command::create();
145
+ $cmd->add('php');
146
+ $cmd->add('--version');
147
+ $result = $cmd->execute();
148
+
149
+ $this->assertTrue(is_array($result));
150
+ $this->assertNotEmpty($result);
151
+ $this->assertRegexp('/PHP|HipHop/', $result[0]);
152
+ }
153
+
154
+ public function testCastToString()
155
+ {
156
+ $cmd = Command::create();
157
+ $cmd->add('--force');
158
+ $cmd->add('--run');
159
+
160
+ $this->assertSame('--force --run', (string) $cmd);
161
+ }
162
+ }
vendor/symfony/finder/composer.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "symfony/finder",
3
+ "type": "library",
4
+ "description": "Symfony Finder Component",
5
+ "keywords": [],
6
+ "homepage": "https://symfony.com",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Fabien Potencier",
11
+ "email": "fabien@symfony.com"
12
+ },
13
+ {
14
+ "name": "Symfony Community",
15
+ "homepage": "https://symfony.com/contributors"
16
+ }
17
+ ],
18
+ "require": {
19
+ "php": ">=5.3.9"
20
+ },
21
+ "require-dev": {
22
+ "symfony/phpunit-bridge": "~2.7"
23
+ },
24
+ "autoload": {
25
+ "psr-4": { "Symfony\\Component\\Finder\\": "" }
26
+ },
27
+ "minimum-stability": "dev",
28
+ "extra": {
29
+ "branch-alias": {
30
+ "dev-master": "2.7-dev"
31
+ }
32
+ }
33
+ }
vendor/symfony/finder/phpunit.xml.dist ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
5
+ backupGlobals="false"
6
+ colors="true"
7
+ bootstrap="vendor/autoload.php"
8
+ >
9
+ <php>
10
+ <ini name="error_reporting" value="-1" />
11
+ </php>
12
+
13
+ <testsuites>
14
+ <testsuite name="Symfony Finder Component Test Suite">
15
+ <directory>./Tests/</directory>
16
+ </testsuite>
17
+ </testsuites>
18
+
19
+ <filter>
20
+ <whitelist>
21
+ <directory>./</directory>
22
+ <exclude>
23
+ <directory>./Tests</directory>
24
+ <directory>./vendor</directory>
25
+ </exclude>
26
+ </whitelist>
27
+ </filter>
28
+ </phpunit>