PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/p/snapshot/lib/Snapshot/Model/Full/Backup.php

https://bitbucket.org/matthewselby/wpdev
PHP | 505 lines | 246 code | 51 blank | 208 comment | 33 complexity | 9c9733cd7dfb07931eec1507e3dc290f MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, LGPL-3.0, LGPL-2.1, AGPL-1.0, BSD-3-Clause, MIT, GPL-3.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * Overall full backup model
  4. */
  5. class Snapshot_Model_Full_Backup extends Snapshot_Model_Full_Abstract {
  6. /**
  7. * Remote model instance reference
  8. *
  9. * @var object Snapshot_Model_Full_Remote
  10. */
  11. private $_storage;
  12. /**
  13. * Local model instance reference
  14. *
  15. * @var object Snapshot_Model_Full_Local
  16. */
  17. private $_local;
  18. /**
  19. * Create a new model instance
  20. *
  21. * Also populates internal facade references
  22. */
  23. public function __construct() {
  24. $this->_storage = new Snapshot_Model_Full_Remote;
  25. $this->_local = new Snapshot_Model_Full_Local;
  26. }
  27. /**
  28. * Gets model type
  29. *
  30. * Used in filtering implementation
  31. *
  32. * @return string Model type tag
  33. */
  34. public function get_model_type() {
  35. return 'backup';
  36. }
  37. /**
  38. * Gets local handler instance
  39. *
  40. * @return Snapshot_Model_Full_Local Local handler instance
  41. */
  42. public function local() {
  43. return $this->_local;
  44. }
  45. /**
  46. * Gets remote handler instance
  47. *
  48. * @return Snapshot_Model_Full_Remote Remote handler instance
  49. */
  50. public function remote() {
  51. return $this->_storage;
  52. }
  53. /**
  54. * Check for existence of any errors
  55. *
  56. * @return bool
  57. */
  58. public function has_errors() {
  59. if ( $this->_storage->has_errors() ) {
  60. return true;
  61. }
  62. if ( $this->_local->has_errors() ) {
  63. return true;
  64. }
  65. return empty( $this->_errors );
  66. }
  67. /**
  68. * Get errors as array of strings ready for showing.
  69. *
  70. * @return array
  71. */
  72. public function get_errors() {
  73. $from_storage = $this->_storage->get_errors();
  74. $from_local = $this->_storage->get_errors();
  75. $errors = is_array( $this->_errors )
  76. ? $this->_errors
  77. : array();
  78. return array_merge( $from_storage, $from_local, $errors );
  79. }
  80. /**
  81. * Proxy remote API info check
  82. *
  83. * @return bool
  84. */
  85. public function has_api_info() {
  86. return $this->_storage->has_api_info();
  87. }
  88. /**
  89. * Proxy remote API error check
  90. *
  91. * @return bool
  92. */
  93. public function has_api_error() {
  94. return $this->_storage->has_api_error();
  95. }
  96. /**
  97. * Proxy the current site DEV management link
  98. *
  99. * @return string
  100. */
  101. public function get_current_site_management_link() {
  102. return $this->_storage->get_current_site_management_link();
  103. }
  104. /**
  105. * Proxy the current site DEV secret key link
  106. *
  107. * @return string
  108. */
  109. public function get_current_secret_key_link() {
  110. return $this->_storage->get_current_secret_key_link();
  111. }
  112. /**
  113. * Updates the schedule frequencies on remote DEV side to their current local values
  114. *
  115. * Proxies the Remote schedule update method
  116. *
  117. * @param int $timestamp Optional last backup timestamp (to be passed on verbatim)
  118. *
  119. * @return bool
  120. */
  121. public function update_remote_schedule( $timestamp = false ) {
  122. $frequency = $this->get_frequency();
  123. $time = $this->get_schedule_time();
  124. return $this->_storage->update_schedule( $frequency, $time, $timestamp );
  125. }
  126. /**
  127. * Check if we have dashboard installed
  128. *
  129. * @return bool
  130. */
  131. public function has_dashboard() {
  132. return (bool) apply_filters(
  133. $this->get_filter( 'has_dashboard' ),
  134. $this->is_dashboard_active() && $this->has_dashboard_key()
  135. );
  136. }
  137. /**
  138. * Check if we have WPMU DEV Dashboard plugin installed and activated
  139. *
  140. * @return bool
  141. */
  142. public function is_dashboard_active() {
  143. return (bool) apply_filters(
  144. $this->get_filter( 'is_dashboard_active' ),
  145. class_exists( 'WPMUDEV_Dashboard' )
  146. );
  147. }
  148. /**
  149. * Checks if Dashboard plugin is installed, but not activated
  150. *
  151. * @return bool
  152. */
  153. public function is_dashboard_installed() {
  154. if ( $this->is_dashboard_active() ) {
  155. return true;
  156. }
  157. if ( ! function_exists( 'get_plugins' ) ) {
  158. require_once ABSPATH . 'wp-admin/includes/plugin.php';
  159. }
  160. $plugins = get_plugins();
  161. if ( ! is_array( $plugins ) || empty( $plugins ) ) {
  162. return false;
  163. }
  164. return ! empty( $plugins['wpmudev-updates/update-notifications.php'] );
  165. }
  166. /**
  167. * Check if we have our API key
  168. *
  169. * If we do, this means the user has logged into the dashboard
  170. *
  171. * @return bool
  172. */
  173. public function has_dashboard_key() {
  174. $key = $this->get_dashboard_api_key();
  175. return (bool) apply_filters(
  176. $this->get_filter( 'has_dashboard_key' ),
  177. ! empty( $key )
  178. );
  179. }
  180. /**
  181. * Remote facade for dashboard key getting.
  182. *
  183. * @return string API key
  184. */
  185. public function get_dashboard_api_key() {
  186. return $this->_storage->get_dashboard_api_key();
  187. }
  188. /**
  189. * Check if full backups are activated
  190. *
  191. * @return bool
  192. */
  193. public function is_active() {
  194. return $this->has_dashboard() && apply_filters(
  195. $this->get_filter( 'is_active' ),
  196. $this->get_config( 'active' )
  197. );
  198. }
  199. /**
  200. * Gets a list of known scheduled frequencies
  201. *
  202. * @param bool $title_case if true, will return capitalized frequency names, otherwise, lowercase
  203. *
  204. * @return array List of frequencies as key => label pairs
  205. */
  206. public function get_frequencies( $title_case = true ) {
  207. if ( $title_case ) {
  208. $frequencies = array(
  209. 'daily' => __( 'Daily', SNAPSHOT_I18N_DOMAIN ),
  210. 'weekly' => __( 'Weekly', SNAPSHOT_I18N_DOMAIN ),
  211. 'monthly' => __( 'Monthly', SNAPSHOT_I18N_DOMAIN ),
  212. );
  213. } else {
  214. $frequencies = array(
  215. 'daily' => __( 'daily', SNAPSHOT_I18N_DOMAIN ),
  216. 'weekly' => __( 'weekly', SNAPSHOT_I18N_DOMAIN ),
  217. 'monthly' => __( 'monthly', SNAPSHOT_I18N_DOMAIN ),
  218. );
  219. }
  220. return apply_filters( $this->get_filter( 'schedule_frequencies' ), $frequencies, $title_case );
  221. }
  222. /**
  223. * Gets the currently set schedule frequency
  224. *
  225. * @return string Schedule frequency key
  226. */
  227. public function get_frequency() {
  228. $default = 'weekly';
  229. $value = $this->get_config( 'frequency', $default );
  230. $value = ! empty( $value ) ? $value : $default;
  231. return apply_filters(
  232. $this->get_filter( 'schedule_frequency' ),
  233. $value
  234. );
  235. }
  236. /**
  237. * Gets a list of known schedule times
  238. *
  239. * @return array A list of schedule times, as key => label pairs
  240. */
  241. public function get_schedule_times() {
  242. $times = array();
  243. $midnight = strtotime( date( "Y-m-d 00:00:00" ) );
  244. $tf = get_option( 'time_format' );
  245. $offset = Snapshot_Model_Time::get()->get_utc_diff();
  246. for ( $i = 0; $i < DAY_IN_SECONDS; $i += HOUR_IN_SECONDS ) {
  247. $seconds = $i - $offset; // Deal with seconds, not hours
  248. if ( $seconds < 0 ) {
  249. $seconds += DAY_IN_SECONDS;
  250. }
  251. if ( $seconds >= DAY_IN_SECONDS ) {
  252. $seconds -= DAY_IN_SECONDS;
  253. }
  254. if ( 0 == $seconds ) {
  255. $seconds = 1;
  256. } // Because 0 will show current time in Hub :(
  257. $times[ $seconds ] = date_i18n( $tf, $midnight + $i );
  258. }
  259. return apply_filters(
  260. $this->get_filter( 'schedule_times' ),
  261. $times
  262. );
  263. }
  264. /**
  265. * Gets the currently set schedule time
  266. *
  267. * @return int Relative schedule time
  268. */
  269. public function get_schedule_time() {
  270. $default = 3600;
  271. $value = $this->get_config( 'schedule_time', $default );
  272. $value = is_numeric( $value ) ? (int) $value : $default;
  273. return (int) apply_filters(
  274. $this->get_filter( 'schedule_time' ),
  275. $value
  276. );
  277. }
  278. /**
  279. * Gets offset base value
  280. *
  281. * @param string $frequency Optional frequency for the offset base.
  282. *
  283. * @return int
  284. */
  285. public function get_offset_base ($frequency=false) {
  286. $offset = $this->get_config('schedule_offset', 0);
  287. if (empty($frequency)) $frequency = $this->get_frequency();
  288. if ('weekly' === $frequency && $offset > 6) return 0;
  289. return (int)$offset;
  290. }
  291. /**
  292. * Gets concrete offset, relative to timestamp
  293. *
  294. * @param int $timestamp Date to calculate offset relative to.
  295. * @param string $frequency Optional frequency for the offset base.
  296. *
  297. * @return int
  298. */
  299. public function get_offset ($timestamp, $frequency=false) {
  300. if (empty($frequency)) $frequency = $this->get_frequency();
  301. $base = $this->get_offset_base($frequency);
  302. $offset = $timestamp;
  303. if ('weekly' === $frequency) {
  304. $monday = Snapshot_Model_Time::get()->get_next_monday();
  305. $next = $base * DAY_IN_SECONDS;
  306. if ($timestamp > $monday + $next) {
  307. // Ensure we're in the future.
  308. $monday += 7 * DAY_IN_SECONDS;
  309. }
  310. if ($monday + $next > $timestamp + (7 * DAY_IN_SECONDS)) {
  311. // Ensure we're not too far in the future.
  312. $monday -= 7 * DAY_IN_SECONDS;
  313. }
  314. $offset = $monday + $next;
  315. } else if ('monthly' === $frequency) {
  316. $offset = strtotime(date('Y-m-01 00:00:00', $timestamp));
  317. $next = $base > 1 ? ($base - 1) * DAY_IN_SECONDS : 0;
  318. // Ensure we're in the future
  319. if ($timestamp > $offset + $next) $offset += (int)date('t', $offset) * DAY_IN_SECONDS;
  320. $offset += $next;
  321. }
  322. return $offset;
  323. }
  324. /**
  325. * Gets a list of offsets as offset base, offset weekday pairs
  326. *
  327. * @return array
  328. */
  329. public function get_offsets ($frequency=false) {
  330. if (empty($frequency)) $frequency = $this->get_frequency();
  331. $offsets = array();
  332. if ('weekly' === $frequency) {
  333. $monday = Snapshot_Model_Time::get()->get_next_monday();
  334. foreach (range(0, 6) as $wday) {
  335. $offsets[$wday] = date_i18n( 'l', $monday + ($wday*DAY_IN_SECONDS));
  336. }
  337. } else if ('monthly' === $frequency) {
  338. foreach (range(1, 30) as $mday) {
  339. $offsets[$mday] = $mday;
  340. }
  341. }
  342. return $offsets;
  343. }
  344. /**
  345. * Check if we have any backups here
  346. *
  347. * @return bool
  348. */
  349. public function has_backups() {
  350. $backups = $this->get_backups();
  351. return apply_filters(
  352. $this->get_filter( 'has_backups' ),
  353. ! empty( $backups )
  354. );
  355. }
  356. /**
  357. * Gets a list of backups
  358. *
  359. * @return array A list of full backup items
  360. */
  361. public function get_backups() {
  362. return apply_filters(
  363. $this->get_filter( 'get_backups' ),
  364. array_merge(
  365. $this->_storage->get_backups(),
  366. $this->_local->get_backups()
  367. )
  368. );
  369. }
  370. /**
  371. * Send finished backup file to remote destination.
  372. *
  373. * Facade method for storage action.
  374. *
  375. * @param Snapshot_Helper_Backup $backup Backup helper to send away
  376. *
  377. * @return bool
  378. */
  379. public function send_backup( Snapshot_Helper_Backup $backup ) {
  380. return $this->_storage->send_backup( $backup );
  381. }
  382. /**
  383. * Continue item upload for this backup
  384. *
  385. * @param int $timestamp Timestamp for backup to resolve
  386. *
  387. * @return bool
  388. */
  389. public function continue_item_upload( $timestamp ) {
  390. return $this->_storage->continue_item_upload( $timestamp );
  391. }
  392. /**
  393. * Gets a (local) backup file instance
  394. *
  395. * @param int $timestamp Timestamp for backup to resolve
  396. *
  397. * @return mixed Path to backup if local file exists, (bool)false otherwise
  398. */
  399. public function get_backup( $timestamp ) {
  400. $local = $this->_local->get_backup( $timestamp );
  401. if ( ! empty( $local ) ) {
  402. return $local;
  403. }
  404. return $this->_storage->get_backup( $timestamp );
  405. }
  406. /**
  407. * Deletes a remote backup instance
  408. *
  409. * @param int $timestamp Timestamp for backup to resolve
  410. *
  411. * @return bool
  412. */
  413. public function delete_backup( $timestamp ) {
  414. $local_result = $this->_local->delete_backup( $timestamp );
  415. $remote_result = $this->_storage->delete_backup( $timestamp );
  416. return $local_result || $remote_result;
  417. }
  418. /**
  419. * Proxies local backups rotation
  420. *
  421. * @return bool
  422. */
  423. public function rotate_local_backups() {
  424. return $this->_local->rotate_backups();
  425. }
  426. /**
  427. * Gets the next scheduled automatic backup start
  428. *
  429. * @return mixed (int)UNIX timestamp on success, (bool)false on failure
  430. */
  431. public function get_next_automatic_backup_start_time() {
  432. $cron = Snapshot_Controller_Full_Cron::get();
  433. $schedule = wp_next_scheduled( $cron->get_filter( 'start_backup' ) );
  434. return ! empty( $schedule )
  435. ? $schedule
  436. : false;
  437. }
  438. /**
  439. * Filter/action name getter
  440. *
  441. * @param string $filter Filter name to convert
  442. *
  443. * @return string Full filter name
  444. */
  445. public function get_filter( $filter = false ) {
  446. if ( empty( $filter ) ) {
  447. return false;
  448. }
  449. if ( ! is_string( $filter ) ) {
  450. return false;
  451. }
  452. return 'snapshot-model-full-backup-' . $filter;
  453. }
  454. }