관리-도구
편집 파일: class-wpcode-file-cache.php
<?php /** * File cache class. Store files in the uploads folder. * Use the expiration in the get function to control how often a file should be refreshed. * * @package WPCode */ /** * WPCode_File_Cache class. */ class WPCode_File_Cache { /** * Name of the base folder in the Uploads folder. * * @var string */ private $basedir = 'wpcode'; /** * Name of the module-specific folder in the base folder. * * @var string */ private $dirname = 'cache'; /** * Full upload path, created form the WP uploads folder. * * @var string */ private $upload_path; /** * Write a file to the server with an expiration date. * * @param string $name The key by which to retrieve the data. * @param mixed $data The data to save - if it's a JSON it should be decoded first as it gets encoded here. * * @return void */ public function set( $name, $data ) { $this->write_file( $this->get_cache_filename_by_key( $name ), wp_json_encode( $data ) ); } /** * Get some data by its name. Checks if the data is expired and if so * returns false so you can update it. * * @param string $name The key of the data to save. * @param int $ttl For how long since creation should this file be used. * * @return array|false */ public function get( $name, $ttl = 0 ) { $file = $this->get_directory_path( $this->get_cache_filename_by_key( $name ) ); /** * Filter the $ttl for a file if you want to change it. * * @param int $ttl The time to live for the cache. * @param string $name The name of the file. * * @return int * @since 2.2.2 */ $ttl = apply_filters( 'wpcode_file_cache_ttl', $ttl, $name ); // If the file doesn't exist there's not much to do. if ( ! file_exists( $file ) ) { // Let's see if we have it in the database. $option = get_option( 'wpcode_alt_cache_' . $name, false ); if ( false !== $option ) { // Let's check if the time since the option was saved is less than the TTL. if ( empty( $option['time'] ) || $ttl > 0 && (int) $option['time'] + $ttl < time() ) { // If the option expired let's delete it, so we clean up in case the file will now work. delete_option( 'wpcode_alt_cache_' . $name ); return false; } return json_decode( $option['data'], true ); } return false; } // If TTL is 0, always return the file. if ( $ttl > 0 && (int) filemtime( $file ) + $ttl < time() ) { return false; } return json_decode( file_get_contents( $file ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents } /** * Delete a cached file by its key. * * @param string $key The key to find the file by. * * @return void */ public function delete( $key ) { $file = $this->get_directory_path( $this->get_cache_filename_by_key( $key ) ); wp_delete_file( $file ); delete_option( 'wpcode_alt_cache_' . $key ); } /** * Basically just adds JSON to the end of the key but we should use this * to also make sure it's a proper filename. * * @param string $name The key. * * @return string */ private function get_cache_filename_by_key( $name ) { return $name . '.json'; } /** * Write a file to the cache folder. Data should already be processed when using this. * * @param string $name The name of the file. * @param string $data The data to write to the file. * * @return void */ private function write_file( $name, $data ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents $written = file_put_contents( $this->get_directory_path( $name ), $data ); if ( false === $written ) { // If we can't save the file to the file cache let's try to save it to the database. // This is not ideal but it prevents having endless requests. // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents $option = array( 'time' => time(), 'data' => $data, ); // $name is the file name, in order to save it in the db we should remove the file extension. $name = str_replace( '.json', '', $name ); update_option( 'wpcode_alt_cache_' . $name, $option, false ); } } /** * Get a reliable path to write files to, it also creates the folders needed if they don't exist. * * @param string $filename The file path. * * @return string */ private function get_directory_path( $filename ) { if ( ! isset( $this->upload_path ) ) { $uploads = wp_upload_dir(); $base_path = trailingslashit( $uploads['basedir'] ) . $this->basedir; $this->upload_path = $base_path . '/' . $this->dirname; if ( ! file_exists( $this->upload_path ) || ! wp_is_writable( $this->upload_path ) ) { wp_mkdir_p( $this->upload_path ); $this->create_index_html_file( $this->upload_path ); } // Ensure the base path has an index file. $this->create_index_html_file( $base_path ); } $filepath = trailingslashit( $this->upload_path ) . $filename; $directory = dirname( $filepath ); if ( $directory !== $this->upload_path && ! file_exists( $directory ) ) { wp_mkdir_p( $directory ); $this->create_index_html_file( $directory ); } $this->create_index_html_file( $this->upload_path ); return $filepath; } /** * Create index.html file in the specified directory if it doesn't exist. * * @param string $path The path to the directory. * * @return false|int */ public static function create_index_html_file( $path ) { if ( ! is_dir( $path ) || is_link( $path ) ) { return false; } $index_file = wp_normalize_path( trailingslashit( $path ) . 'index.html' ); // Do nothing if index.html exists in the directory. if ( file_exists( $index_file ) ) { return false; } // Create empty index.html. return file_put_contents( $index_file, '' ); // phpcs:ignore WordPress.WP.AlternativeFunctions } /** * Create .htaccess file in the specified directory if it doesn't exist. * * @param string $path The path to the directory. * * @return false|int */ public static function create_htaccess_file( $path ) { if ( ! is_dir( $path ) || is_link( $path ) ) { return false; } $htaccess_file = wp_normalize_path( trailingslashit( $path ) . '.htaccess' ); // Do nothing if index.html exists in the directory. if ( file_exists( $htaccess_file ) ) { return false; } // Create empty index.html. return file_put_contents( $htaccess_file, 'deny from all' ); // phpcs:ignore WordPress.WP.AlternativeFunctions } }