ile creating feed directory.', array( 'event' => 'feed_upload', 'event_type' => 'create_feed_directory', 'extra_data' => [ 'feed_name' => $this->feed_name, 'file_directory' => $file_directory, ], ), array( 'should_send_log_to_meta' => true, 'should_save_log_in_woocommerce' => false, 'woocommerce_log_level' => \WC_Log_Levels::DEBUG, ), $exception, ); throw $exception; } } /** * Creates files in the feed directory to prevent directory listing and hotlinking. * * @throws \Exception Caught exception is rethrown. * @since 3.5.0 */ public function create_files_to_protect_feed_directory(): void { $feed_directory = trailingslashit( $this->get_file_directory() ); try { $files = array( array( 'base' => $feed_directory, 'file' => 'index.html', 'content' => '', ), array( 'base' => $feed_directory, 'file' => '.htaccess', 'content' => 'deny from all', ), ); foreach ( $files as $file ) { $file_path = trailingslashit( $file['base'] ) . $file['file']; if ( wp_mkdir_p( $file['base'] ) && ! file_exists( $file_path ) ) { // phpcs:ignore -- use php file i/o functions $file_handle = fopen( $file_path, 'w' ); if ( $file_handle ) { try { fwrite( $file_handle, $file['content'] ); //phpcs:ignore } finally { fclose( $file_handle ); //phpcs:ignore } } } } } catch ( \Exception $exception ) { Logger::log( 'Error while creating files to protect feed directory.', array( 'event' => 'feed_upload', 'event_type' => 'create_files_to_protect_feed_directory', 'extra_data' => [ 'feed_name' => $this->feed_name, 'feed_directory' => $feed_directory, ], ), array( 'should_send_log_to_meta' => true, 'should_save_log_in_woocommerce' => false, 'woocommerce_log_level' => \WC_Log_Levels::DEBUG, ), $exception, ); throw $exception; } } /** * Gets the feed file path of given feed. * * @return string * @since 3.5.0 */ public function get_file_path(): string { return "{$this->get_file_directory()}/{$this->get_file_name()}"; } /** * Gets the temporary feed file path. * * @return string * @since 3.5.0 */ public function get_temp_file_path(): string { return "{$this->get_file_directory()}/{$this->get_temp_file_name()}"; } /** * Gets the feed file directory. * * @return string * @since 3.5.0 */ public function get_file_directory(): string { $uploads_directory = wp_upload_dir( null, false ); return trailingslashit( $uploads_directory['basedir'] ) . sprintf( self::UPLOADS_DIRECTORY, $this->feed_name ); } /** * Gets the feed file name. * * @return string * @since 3.5.0 */ public function get_file_name(): string { $feed_secret = facebook_for_woocommerce()->feed_manager->get_feed_secret( $this->feed_name ); return sprintf( static::FILE_NAME, $this->feed_name, $feed_secret ); } /** * Gets the temporary feed file name. * * @return string * @since 3.5.0 */ public function get_temp_file_name(): string { $feed_secret = facebook_for_woocommerce()->feed_manager->get_feed_secret( $this->feed_name ); return sprintf( static::FILE_NAME, $this->feed_name, 'temp_' . wp_hash( $feed_secret ) ); } /** * Prepare a fresh empty temporary feed file with the header row. * * @throws PluginException We can't open the file or the file is not writable. * @throws \Exception Caught exception is rethrown. * @return resource A file pointer resource. * @since 3.5.0 */ public function prepare_temporary_feed_file() { $temp_file_path = $this->get_temp_file_path(); $temp_feed_file = false; $file_path = $this->get_file_path(); try { // phpcs:ignore -- use php file i/o functions $temp_feed_file = fopen( $temp_file_path, 'w' ); // Check if we can open the temporary feed file. // phpcs:ignore if ( false === $temp_feed_file || ! is_writable( $temp_file_path ) ) { throw new PluginException( "Could not open file {$temp_file_path} for writing.", 500 ); } // Check if we will be able to write to the final feed file. // phpcs:ignore -- use php file i/o functions if ( file_exists( $file_path ) && ! is_writable( $file_path ) ) { throw new PluginException( "Could not open file {$file_path} for writing.", 500 ); } if ( ! empty( $this->header_row ) ) { $headers = str_getcsv( $this->header_row, $this->delimiter, $this->enclosure, $this->escape_char ); if ( fputcsv( $temp_feed_file, $headers, $this->delimiter, $this->enclosure, $this->escape_char ) === false ) { throw new PluginException( "Failed to write header row to {$temp_file_path}.", 500 ); } } return $temp_feed_file; } catch ( \Exception $exception ) { Logger::log( 'Error while creating temporary feed file.', array( 'event' => 'feed_upload', 'event_type' => 'prepare_temporary_feed_file', 'extra_data' => [ 'feed_name' => $this->feed_name, 'temp_file_path' => $temp_file_path, 'file_path' => $file_path, ], ), array( 'should_send_log_to_meta' => true, 'should_save_log_in_woocommerce' => false, 'woocommerce_log_level' => \WC_Log_Levels::DEBUG, ), $exception, ); if ( $temp_feed_file ) { // phpcs:ignore -- use php file i/o functions fclose( $temp_feed_file ); } throw $exception; } } /** * Rename temporary feed file into the final feed file. * This is the last step fo the feed generation procedure. * * @throws PluginException If the temporary feed file could not be renamed. * @throws \Exception Caught exception is rethrown. * @since 3.5.0 */ public function promote_temp_file(): void { $temp_file_path = $this->get_temp_file_path(); $file_path = $this->get_file_path(); try { if ( ! empty( $temp_file_path ) && ! empty( $file_path ) ) { // phpcs:ignore -- use php file i/o functions $renamed = rename( $temp_file_path, $file_path ); if ( empty( $renamed ) ) { throw new PluginException( "Could not promote temp file: {$temp_file_path}", 500 ); } } } catch ( \Exception $exception ) { Logger::log( 'Error while promoting temporary file.', array( 'event' => 'feed_upload', 'event_type' => 'promote_temp_file', 'extra_data' => [ 'feed_name' => $this->feed_name, 'temp_file_path' => $temp_file_path, 'file_path' => $file_path, ], ), array( 'should_send_log_to_meta' => true, 'should_save_log_in_woocommerce' => false, 'woocommerce_log_level' => \WC_Log_Levels::DEBUG, ), $exception, ); throw $exception; } } /** * Write to the temp feed file. * * @param array $data The data to write to the feed file. * @since 3.5.0 */ abstract public function write_temp_feed_file( array $data ); }