PageRenderTime 27ms CodeModel.GetById 19ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

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