/wp-content/plugins/wordpress-seo/admin/class-export.php

https://bitbucket.org/carloskikea/helpet · PHP · 287 lines · 142 code · 47 blank · 98 comment · 17 complexity · a0bfa7cea1d77b4e285fa324ff6d32f0 MD5 · raw file

  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin\Export
  6. */
  7. /**
  8. * Class WPSEO_Export
  9. *
  10. * Class with functionality to export the WP SEO settings
  11. */
  12. class WPSEO_Export {
  13. const ZIP_FILENAME = 'yoast-seo-settings-export.zip';
  14. const INI_FILENAME = 'settings.ini';
  15. const NONCE_ACTION = 'wpseo_export';
  16. const NONCE_NAME = 'wpseo_export_nonce';
  17. /**
  18. * @var string
  19. */
  20. private $export = '';
  21. /**
  22. * @var string
  23. */
  24. private $error = '';
  25. /**
  26. * @var string
  27. */
  28. public $export_zip_url = '';
  29. /**
  30. * @var boolean
  31. */
  32. public $success;
  33. /**
  34. * Whether or not the export will include taxonomy metadata
  35. *
  36. * @var boolean
  37. */
  38. private $include_taxonomy;
  39. /**
  40. * @var array
  41. */
  42. private $dir = array();
  43. /**
  44. * Class constructor
  45. *
  46. * @param boolean $include_taxonomy Whether to include the taxonomy metadata the plugin creates.
  47. */
  48. public function __construct( $include_taxonomy = false ) {
  49. $this->include_taxonomy = $include_taxonomy;
  50. $this->dir = wp_upload_dir();
  51. $this->export_settings();
  52. }
  53. /**
  54. * Returns true when the property error has a value.
  55. *
  56. * @return bool
  57. */
  58. public function has_error() {
  59. return ( $this->error !== '' );
  60. }
  61. /**
  62. * Sets the error hook, to display the error to the user.
  63. */
  64. public function set_error_hook() {
  65. /* translators: %1$s expands to Yoast SEO */
  66. $message = sprintf( __( 'Error creating %1$s export: ', 'wordpress-seo' ), 'Yoast SEO' ) . $this->error;
  67. printf(
  68. '<div class="notice notice-error"><p>%1$s</p></div>',
  69. $message
  70. );
  71. }
  72. /**
  73. * Exports the current site's WP SEO settings.
  74. */
  75. private function export_settings() {
  76. $this->export_header();
  77. foreach ( WPSEO_Options::get_option_names() as $opt_group ) {
  78. $this->write_opt_group( $opt_group );
  79. }
  80. $this->taxonomy_metadata();
  81. if ( ! $this->write_settings_file() ) {
  82. $this->error = __( 'Could not write settings to file.', 'wordpress-seo' );
  83. return;
  84. }
  85. if ( $this->zip_file() ) {
  86. // Just exit, because there is a download being served.
  87. exit;
  88. }
  89. }
  90. /**
  91. * Writes the header of the export file.
  92. */
  93. private function export_header() {
  94. $header = sprintf(
  95. /* translators: %1$s expands to Yoast SEO, %2$s expands to Yoast.com */
  96. esc_html__( 'This is a settings export file for the %1$s plugin by %2$s', 'wordpress-seo' ),
  97. 'Yoast SEO',
  98. 'Yoast.com'
  99. );
  100. $this->write_line( '; ' . $header . ' - ' . esc_url( WPSEO_Shortlinker::get( 'https://yoa.st/1yd' ) ) );
  101. if ( $this->include_taxonomy ) {
  102. $this->write_line( '; ' . __( 'This export includes taxonomy metadata', 'wordpress-seo' ) );
  103. }
  104. }
  105. /**
  106. * Writes a line to the export
  107. *
  108. * @param string $line Line string.
  109. * @param boolean $newline_first Boolean flag whether to prepend with new line.
  110. */
  111. private function write_line( $line, $newline_first = false ) {
  112. if ( $newline_first ) {
  113. $this->export .= PHP_EOL;
  114. }
  115. $this->export .= $line . PHP_EOL;
  116. }
  117. /**
  118. * Writes an entire option group to the export
  119. *
  120. * @param string $opt_group Option group name.
  121. */
  122. private function write_opt_group( $opt_group ) {
  123. $this->write_line( '[' . $opt_group . ']', true );
  124. $options = get_option( $opt_group );
  125. if ( ! is_array( $options ) ) {
  126. return;
  127. }
  128. foreach ( $options as $key => $elem ) {
  129. if ( is_array( $elem ) ) {
  130. $count = count( $elem );
  131. for ( $i = 0; $i < $count; $i ++ ) {
  132. $this->write_setting( $key . '[]', $elem[ $i ] );
  133. }
  134. }
  135. else {
  136. $this->write_setting( $key, $elem );
  137. }
  138. }
  139. }
  140. /**
  141. * Writes a settings line to the export
  142. *
  143. * @param string $key Key string.
  144. * @param string $val Value string.
  145. */
  146. private function write_setting( $key, $val ) {
  147. if ( is_string( $val ) ) {
  148. $val = '"' . $val . '"';
  149. }
  150. $this->write_line( $key . ' = ' . $val );
  151. }
  152. /**
  153. * Adds the taxonomy meta data if there is any
  154. */
  155. private function taxonomy_metadata() {
  156. if ( $this->include_taxonomy ) {
  157. $taxonomy_meta = get_option( 'wpseo_taxonomy_meta' );
  158. if ( is_array( $taxonomy_meta ) ) {
  159. $this->write_line( '[wpseo_taxonomy_meta]', true );
  160. $this->write_setting( 'wpseo_taxonomy_meta', urlencode( wp_json_encode( $taxonomy_meta ) ) );
  161. }
  162. else {
  163. $this->write_line( '; ' . __( 'No taxonomy metadata found', 'wordpress-seo' ), true );
  164. }
  165. }
  166. }
  167. /**
  168. * Writes the settings to our temporary settings.ini file
  169. *
  170. * @return boolean unsigned
  171. */
  172. private function write_settings_file() {
  173. $handle = fopen( $this->dir['path'] . '/' . self::INI_FILENAME, 'w' );
  174. if ( ! $handle ) {
  175. return false;
  176. }
  177. $res = fwrite( $handle, $this->export );
  178. if ( ! $res ) {
  179. return false;
  180. }
  181. fclose( $handle );
  182. return true;
  183. }
  184. /**
  185. * Zips the settings ini file
  186. *
  187. * @return bool|null
  188. */
  189. private function zip_file() {
  190. $is_zip_created = $this->create_zip();
  191. // The settings.ini isn't needed, because it's in the zipfile.
  192. $this->remove_settings_ini();
  193. if ( ! $is_zip_created ) {
  194. $this->error = __( 'Could not zip settings-file.', 'wordpress-seo' );
  195. return false;
  196. }
  197. $this->serve_settings_export();
  198. $this->remove_zip();
  199. return true;
  200. }
  201. /**
  202. * Creates the zipfile and returns true if it created successful.
  203. *
  204. * @return bool
  205. */
  206. private function create_zip() {
  207. chdir( $this->dir['path'] );
  208. $zip = new PclZip( './' . self::ZIP_FILENAME );
  209. if ( 0 === $zip->create( './' . self::INI_FILENAME ) ) {
  210. return false;
  211. }
  212. return file_exists( self::ZIP_FILENAME );
  213. }
  214. /**
  215. * Downloads the zip file.
  216. */
  217. private function serve_settings_export() {
  218. // Clean any content that has been already output. For example by other plugins or faulty PHP files.
  219. if ( ob_get_contents() ) {
  220. ob_clean();
  221. }
  222. header( 'Content-Type: application/octet-stream; charset=utf-8' );
  223. header( 'Content-Transfer-Encoding: Binary' );
  224. header( 'Content-Disposition: attachment; filename=' . self::ZIP_FILENAME );
  225. header( 'Content-Length: ' . filesize( self::ZIP_FILENAME ) );
  226. readfile( self::ZIP_FILENAME );
  227. }
  228. /**
  229. * Removes the settings ini file.
  230. */
  231. private function remove_settings_ini() {
  232. unlink( './' . self::INI_FILENAME );
  233. }
  234. /**
  235. * Removes the files because they are already downloaded.
  236. */
  237. private function remove_zip() {
  238. unlink( './' . self::ZIP_FILENAME );
  239. }
  240. }