\n\tRequire all denied\n\n\n\tDeny from all\n\n" ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents } } /** * Random, unguessable file name token. * * @return string 24 lowercase alphanumerics. */ public static function token(): string { return strtolower( wp_generate_password( 24, false, false ) ); } /** * Resolve a stored file name to its path, refusing anything that is not a * plain file name of the expected shape inside the folder. * * @param string $sub Subfolder. * @param string $file File name. * @param string $pattern Allowed file name regex. * @return string|null Path or null. */ public static function path( string $sub, string $file, string $pattern ): ?string { $file = basename( $file ); if ( ! preg_match( $pattern, $file ) ) { return null; } $path = self::dir( $sub ) . $file; return is_file( $path ) ? $path : null; } /** * Stream a stored file to the browser and exit. * * @param string $path Absolute path from self::path(). * @param string $content_type Content type. * @param string $download_as File name for Content-Disposition. */ public static function send( string $path, string $content_type, string $download_as ) { nocache_headers(); header( 'Content-Type: ' . $content_type ); header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $download_as ) . '"' ); header( 'Content-Length: ' . (string) filesize( $path ) ); readfile( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile exit; } }