class-import-settings.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin\Import
  6. */
  7. /**
  8. * Class WPSEO_Import_Settings
  9. *
  10. * Class with functionality to import the Yoast SEO settings.
  11. */
  12. class WPSEO_Import_Settings {
  13. /**
  14. * @var WPSEO_Import_Status
  15. */
  16. public $status;
  17. /**
  18. * @var array
  19. */
  20. private $file;
  21. /**
  22. * @var string
  23. */
  24. private $filename;
  25. /**
  26. * @var string
  27. */
  28. private $old_wpseo_version = null;
  29. /**
  30. * @var string
  31. */
  32. private $path;
  33. /**
  34. * @var array
  35. */
  36. private $upload_dir;
  37. /**
  38. * Class constructor
  39. */
  40. public function __construct() {
  41. $this->status = new WPSEO_Import_Status( 'import', false );
  42. if ( ! $this->handle_upload() ) {
  43. return $this->status;
  44. }
  45. $this->determine_path();
  46. if ( ! $this->unzip_file() ) {
  47. $this->clean_up();
  48. return $this->status;
  49. }
  50. $this->parse_options();
  51. $this->clean_up();
  52. }
  53. /**
  54. * Handle the file upload
  55. *
  56. * @return boolean Import status.
  57. */
  58. private function handle_upload() {
  59. $overrides = array( 'mimes' => array( 'zip' => 'application/zip' ) ); // Explicitly allow zip in multisite.
  60. $this->file = wp_handle_upload( $_FILES['settings_import_file'], $overrides );
  61. if ( is_wp_error( $this->file ) ) {
  62. $this->status->set_msg( __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . $this->file->get_error_message() );
  63. return false;
  64. }
  65. if ( is_array( $this->file ) && isset( $this->file['error'] ) ) {
  66. $this->status->set_msg( __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . $this->file['error'] );
  67. return false;
  68. }
  69. if ( ! isset( $this->file['file'] ) ) {
  70. $this->status->set_msg( __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'Upload failed.', 'wordpress-seo' ) );
  71. return false;
  72. }
  73. return true;
  74. }
  75. /**
  76. * Determine the path to the import file
  77. */
  78. private function determine_path() {
  79. $this->upload_dir = wp_upload_dir();
  80. if ( ! defined( 'DIRECTORY_SEPARATOR' ) ) {
  81. define( 'DIRECTORY_SEPARATOR', '/' );
  82. }
  83. $this->path = $this->upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'wpseo-import' . DIRECTORY_SEPARATOR;
  84. if ( ! isset( $GLOBALS['wp_filesystem'] ) || ! is_object( $GLOBALS['wp_filesystem'] ) ) {
  85. $url = wp_nonce_url(
  86. self_admin_url( 'admin.php?page=wpseo_tools&tool=import-export' ),
  87. 'wpseo-import'
  88. );
  89. $credentials = request_filesystem_credentials( esc_url_raw( $url ) );
  90. WP_Filesystem( $credentials );
  91. }
  92. }
  93. /**
  94. * Unzip the file
  95. *
  96. * @return boolean
  97. */
  98. private function unzip_file() {
  99. $unzipped = unzip_file( $this->file['file'], $this->path );
  100. $msg_base = __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ';
  101. if ( is_wp_error( $unzipped ) ) {
  102. /* translators: %s expands to an error message. */
  103. $this->status->set_msg( $msg_base . sprintf( __( 'Unzipping failed with error "%s".', 'wordpress-seo' ), $unzipped->get_error_message() ) );
  104. return false;
  105. }
  106. $this->filename = $this->path . 'settings.ini';
  107. if ( ! is_file( $this->filename ) || ! is_readable( $this->filename ) ) {
  108. $this->status->set_msg( $msg_base . __( 'Unzipping failed - file settings.ini not found.', 'wordpress-seo' ) );
  109. return false;
  110. }
  111. return true;
  112. }
  113. /**
  114. * Parse the option file
  115. */
  116. private function parse_options() {
  117. if ( defined( 'INI_SCANNER_RAW' ) ) {
  118. /*
  119. * Implemented INI_SCANNER_RAW to make sure variables aren't parsed.
  120. *
  121. * http://php.net/manual/en/function.parse-ini-file.php#99943
  122. */
  123. $options = parse_ini_file( $this->filename, true, INI_SCANNER_RAW );
  124. }
  125. else {
  126. // PHP 5.2 does not implement the 3rd argument, this is a fallback.
  127. $options = parse_ini_file( $this->filename, true );
  128. }
  129. if ( is_array( $options ) && $options !== array() ) {
  130. $this->import_options( $options );
  131. return;
  132. }
  133. $this->status->set_msg( __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'No settings found in file.', 'wordpress-seo' ) );
  134. }
  135. /**
  136. * Parse the option group and import it
  137. *
  138. * @param string $name Name string.
  139. * @param array $option_group Option group data.
  140. * @param array $options Options data.
  141. */
  142. private function parse_option_group( $name, $option_group, $options ) {
  143. // Make sure that the imported options are cleaned/converted on import.
  144. $option_instance = WPSEO_Options::get_option_instance( $name );
  145. if ( is_object( $option_instance ) && method_exists( $option_instance, 'import' ) ) {
  146. $option_instance->import( $option_group, $this->old_wpseo_version, $options );
  147. }
  148. }
  149. /**
  150. * Remove the files
  151. */
  152. private function clean_up() {
  153. if ( file_exists( $this->filename ) && is_writable( $this->filename ) ) {
  154. unlink( $this->filename );
  155. }
  156. if ( ! empty( $this->file['file'] ) && file_exists( $this->file['file'] ) && is_writable( $this->file['file'] ) ) {
  157. unlink( $this->file['file'] );
  158. }
  159. if ( file_exists( $this->path ) && is_writable( $this->path ) ) {
  160. $wp_file = new WP_Filesystem_Direct( $this->path );
  161. $wp_file->rmdir( $this->path, true );
  162. }
  163. }
  164. /**
  165. * Imports the options if found.
  166. *
  167. * @param array $options The options parsed from the ini file.
  168. */
  169. private function import_options( $options ) {
  170. if ( isset( $options['wpseo']['version'] ) && $options['wpseo']['version'] !== '' ) {
  171. $this->old_wpseo_version = $options['wpseo']['version'];
  172. }
  173. foreach ( $options as $name => $option_group ) {
  174. $this->parse_option_group( $name, $option_group, $options );
  175. }
  176. $this->status->set_msg( __( 'Settings successfully imported.', 'wordpress-seo' ) );
  177. $this->status->set_status( true );
  178. }
  179. }