Files
medicalalert-web-reloaded/wp/wp-content/plugins/imagify/inc/classes/class-imagify-filesystem.php
2024-09-25 09:25:31 -04:00

1128 lines
29 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
defined( 'ABSPATH' ) || die( 'Cheatin uh?' );
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
/**
* Class that enhance the WP filesystem class.
*
* @since 1.7.1
* @author Grégory Viguier
*/
class Imagify_Filesystem extends WP_Filesystem_Direct {
/**
* Class version.
*
* @var string
*/
const VERSION = '1.2';
/**
* Delimiter used for regex patterns.
*
* @var string
* @since 1.8
* @author Grégory Viguier
*/
const PATTERN_DELIMITER = '@';
/**
* The single instance of the class.
*
* @var object
* @access protected
*/
protected static $_instance;
/** ----------------------------------------------------------------------------------------- */
/** INSTANCIATION =========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Constructor.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*/
public function __construct() {
// Define the permission constants if not already done.
if ( ! defined( 'FS_CHMOD_DIR' ) ) {
define( 'FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) );
}
if ( ! defined( 'FS_CHMOD_FILE' ) ) {
define( 'FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) );
}
parent::__construct( '' );
}
/**
* Get the main Instance.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @return object Main instance.
*/
public static function get_instance() {
if ( ! isset( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/** ----------------------------------------------------------------------------------------- */
/** CUSTOM TOOLS ============================================================================ */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the file name.
* Replacement for basename().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return string|bool The base name of the given path. False on failure.
*/
public function file_name( $file_path ) {
if ( ! $file_path ) {
return false;
}
return wp_basename( $file_path );
}
/**
* Get the parent directory's path.
* Replacement for dirname().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return string|bool The directory path with a trailing slash. False on failure.
*/
public function dir_path( $file_path ) {
if ( ! $file_path ) {
return false;
}
$file_path = dirname( $file_path );
return $this->is_root( $file_path ) ? $this->get_root() : trailingslashit( $file_path );
}
/**
* Get information about a file path.
* Replacement for pathinfo().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @param string $option If present, specifies a specific element to be returned; one of 'dir_path', 'file_name', 'extension' or 'file_base'.
* If option is not specified, returns all available elements.
* @return array|string|null If the option parameter is not passed, an associative array containing the following elements is returned: 'dir_path' (with trailing slash), 'file_name' (with extension), 'extension' (if any), and 'file_base' (without extension).
*/
public function path_info( $file_path, $option = null ) {
if ( ! $file_path ) {
if ( isset( $option ) ) {
return '';
}
return array(
'dir_path' => '',
'file_name' => '',
'extension' => null,
'file_base' => '',
);
}
if ( isset( $option ) ) {
$options = array(
'dir_path' => PATHINFO_DIRNAME,
'file_name' => PATHINFO_BASENAME,
'extension' => PATHINFO_EXTENSION,
'file_base' => PATHINFO_FILENAME,
);
if ( ! isset( $options[ $option ] ) ) {
return '';
}
$output = pathinfo( $file_path, $options[ $option ] );
if ( 'dir_path' !== $option ) {
return $output;
}
return $this->is_root( $output ) ? $this->get_root() : trailingslashit( $output );
}
$output = pathinfo( $file_path );
$output['dirname'] = $this->is_root( $output['dirname'] ) ? $this->get_root() : trailingslashit( $output['dirname'] );
$output['extension'] = isset( $output['extension'] ) ? $output['extension'] : null;
// '/www/htdocs/inc/lib.inc.php'
return array(
'dir_path' => $output['dirname'], // '/www/htdocs/inc/'
'file_name' => $output['basename'], // 'lib.inc.php'
'extension' => $output['extension'], // 'php'
'file_base' => $output['filename'], // 'lib.inc'
);
}
/**
* Recursive directory creation based on full path. Will attempt to set permissions on folders.
* Replacement for recursive mkdir().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $path Full path to attempt to create.
* @return bool Whether the path was created. True if path already exists.
*/
public function make_dir( $path ) {
/*
* Safe mode fails with a trailing slash under certain PHP versions.
*/
$path = untrailingslashit( wp_normalize_path( $path ) );
if ( $this->is_root( $path ) ) {
return $this->is_dir( $this->get_root() ) && $this->is_writable( $this->get_root() );
}
if ( $this->exists( $path ) ) {
return $this->is_dir( $path ) && $this->is_writable( $path );
}
$site_root = $this->get_site_root();
if ( strpos( $path, $site_root ) !== 0 ) {
return false;
}
$bits = preg_replace( '@^' . preg_quote( $site_root, '@' ) . '@i', '', $path );
$bits = explode( '/', trim( $bits, '/' ) );
$path = untrailingslashit( $site_root );
foreach ( $bits as $bit ) {
$parent_path = $path;
$path .= '/' . $bit;
if ( $this->exists( $path ) ) {
if ( ! $this->is_dir( $path ) ) {
return false;
}
continue;
}
if ( ! $this->is_writable( $parent_path ) ) {
$this->chmod_dir( $parent_path );
if ( ! $this->is_writable( $parent_path ) ) {
return false;
}
}
$this->mkdir( $path );
if ( ! $this->exists( $path ) ) {
return false;
}
$this->touch( trailingslashit( $path ) . 'index.php' );
}
return true;
}
/**
* Set a file permissions using FS_CHMOD_FILE.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return bool True on success, false on failure.
*/
public function chmod_file( $file_path ) {
if ( ! $file_path ) {
return false;
}
return $this->chmod( $file_path, FS_CHMOD_FILE );
}
/**
* Set a directory permissions using FS_CHMOD_DIR.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the directory.
* @return bool True on success, false on failure.
*/
public function chmod_dir( $file_path ) {
if ( ! $file_path ) {
return false;
}
return $this->chmod( $file_path, FS_CHMOD_DIR );
}
/**
* Get a file mime type.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path A file path (prefered) or a filename.
* @return string|bool A mime type. False on failure: the test is limited to mime types supported by Imagify.
*/
public function get_mime_type( $file_path ) {
if ( ! $file_path ) {
return false;
}
$file_type = wp_check_filetype( $file_path, imagify_get_mime_types() );
return $file_type['type'];
}
/**
* Get a file modification date, formated as "mysql". Fallback to current date.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return string The date.
*/
public function get_date( $file_path ) {
static $offset;
if ( ! $file_path ) {
return current_time( 'mysql' );
}
$date = $this->mtime( $file_path );
if ( ! $date ) {
return current_time( 'mysql' );
}
if ( ! isset( $offset ) ) {
$offset = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
}
return gmdate( 'Y-m-d H:i:s', $date + $offset );
}
/**
* Tell if a file is symlinked.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path An absolute path.
* @return bool
*/
public function is_symlinked( $file_path ) {
static $site_root;
static $plugin_paths = array();
global $wp_plugin_paths;
if ( ! $file_path ) {
return false;
}
$real_path = realpath( $file_path );
if ( ! $real_path ) {
return false;
}
if ( ! isset( $site_root ) ) {
$site_root = $this->normalize_path_for_comparison( $this->get_site_root() );
}
$lower_file_path = $this->normalize_path_for_comparison( $real_path );
if ( strpos( $lower_file_path, $site_root ) !== 0 ) {
return true;
}
if ( $wp_plugin_paths && is_array( $wp_plugin_paths ) ) {
if ( ! $plugin_paths ) {
foreach ( $wp_plugin_paths as $dir => $real_dir ) {
$dir = $this->normalize_path_for_comparison( $dir );
$plugin_paths[ $dir ] = $this->normalize_path_for_comparison( $real_dir );
}
}
$lower_file_path = $this->normalize_path_for_comparison( $file_path );
foreach ( $plugin_paths as $dir => $real_dir ) {
if ( strpos( $lower_file_path, $dir ) === 0 ) {
return true;
}
}
}
return false;
}
/**
* Tell if a file is a pdf.
*
* @since 1.8
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return bool
*/
public function is_pdf( $file_path ) {
if ( function_exists( 'finfo_fopen' ) ) {
$finfo = finfo_open( FILEINFO_MIME );
if ( $finfo ) {
$mimetype = finfo_file( $finfo, $file_path );
if ( false !== $mimetype ) {
return 'application/pdf' === $mimetype;
}
}
}
if ( function_exists( 'mime_content_type' ) ) {
$mimetype = mime_content_type( $file_path );
return 'application/pdf' === $mimetype;
}
return false;
}
/** ----------------------------------------------------------------------------------------- */
/** CLASS OVERWRITES ======================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Move a file and apply chmod.
* If the file failed to be moved once, a 2nd attempt is made after applying chmod.
*
* @since 1.8
* @access public
* @author Grégory Viguier
*
* @param string $source Path to the file to move.
* @param string $destination Path to the destination.
* @param bool $overwrite Allow to overwrite existing file at destination.
* @return bool True on success, false on failure.
*/
public function move( $source, $destination, $overwrite = false ) {
if ( parent::move( $source, $destination, $overwrite ) ) {
return $this->chmod_file( $destination );
}
if ( ! $this->chmod_file( $destination ) ) {
return false;
}
if ( parent::move( $source, $destination, $overwrite ) ) {
return $this->chmod_file( $destination );
}
return false;
}
/**
* Determine if a file or directory is writable.
* This function is used to work around certain ACL issues in PHP primarily affecting Windows Servers.
* Replacement for is_writable().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return bool
*/
public function is_writable( $file_path ) {
if ( ! $file_path ) {
return false;
}
return wp_is_writable( $file_path );
}
/** ----------------------------------------------------------------------------------------- */
/** WORK WITH IMAGES ======================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Tell if a file is an image.
*
* @since 1.8
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return bool
*/
public function is_image( $file_path ) {
if ( function_exists( 'finfo_fopen' ) ) {
$finfo = finfo_open( FILEINFO_MIME );
if ( $finfo ) {
$mimetype = finfo_file( $finfo, $file_path );
if ( false !== $mimetype ) {
return strpos( $mimetype, 'image/' ) === 0;
}
}
}
if ( function_exists( 'exif_imagetype' ) ) {
$mimetype = exif_imagetype( $file_path );
return (bool) $mimetype;
}
if ( function_exists( 'mime_content_type' ) ) {
$mimetype = mime_content_type( $file_path );
return strpos( $mimetype, 'image/' ) === 0;
}
return false;
}
/**
* Get an image data.
* Replacement for getimagesize().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return array The image data. An empty array on failure.
*/
public function get_image_size( $file_path ) {
if ( ! $file_path ) {
return array();
}
$size = @getimagesize( $file_path );
if ( ! $size || ! isset( $size[0], $size[1] ) ) {
return array();
}
return array(
0 => (int) $size[0],
1 => (int) $size[1],
'width' => (int) $size[0],
'height' => (int) $size[1],
'type' => (int) $size[2],
'attr' => $size[3],
'channels' => isset( $size['channels'] ) ? (int) $size['channels'] : null,
'bits' => isset( $size['bits'] ) ? (int) $size['bits'] : null,
'mime' => $size['mime'],
);
}
/**
* Tell if exif_read_data() is available.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @return bool
*/
public function can_get_exif() {
static $callable;
if ( ! isset( $callable ) ) {
$callable = is_callable( 'exif_read_data' );
}
return $callable;
}
/**
* Get the EXIF headers from an image file.
* Replacement for exif_read_data().
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
* @see https://secure.php.net/manual/en/function.exif-read-data.php
*
* @param string $file_path Path to the file.
* @param string $sections A comma separated list of sections that need to be present in file to produce a result array. See exif_read_data() documentation for values: FILE, COMPUTED, ANY_TAG, IFD0, THUMBNAIL, COMMENT, EXIF.
* @param bool $arrays Specifies whether or not each section becomes an array. The sections COMPUTED, THUMBNAIL, and COMMENT always become arrays as they may contain values whose names conflict with other sections.
* @param bool $thumbnail When set to TRUE the thumbnail itself is read. Otherwise, only the tagged data is read.
* @return array The EXIF headers. An empty array on failure.
*/
public function get_image_exif( $file_path, $sections = null, $arrays = false, $thumbnail = false ) {
if ( ! $file_path || ! $this->can_get_exif() ) {
return array();
}
$exif = @exif_read_data( $file_path, $sections, $arrays, $thumbnail );
return is_array( $exif ) ? $exif : array();
}
/**
* Tell if a file is an animated gif.
*
* @since 1.9.5
* @access public
* @source https://www.php.net/manual/en/function.imagecreatefromgif.php#104473
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return bool|null Null if the file cannot be read.
*/
public function is_animated_gif( $file_path ) {
if ( $this->path_info( $file_path, 'extension' ) !== 'gif' ) {
// Not a gif file.
return false;
}
$fh = @fopen( $file_path, 'rb' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
if ( ! $fh ) {
// Could not open the file.
return null;
}
/**
* An animated gif contains multiple "frames", with each frame having a header made up of:
* - a static 4-byte sequence (\x00\x21\xF9\x04),
* - 4 variable bytes,
* - a static 2-byte sequence (\x00\x2C) (some variants may use \x00\x21 ?).
*/
$count = 0;
// We read through the file til we reach the end of the file, or we've found at least 2 frame headers.
while ( ! feof( $fh ) && $count < 2 ) {
// Read 100kb at a time.
$chunk = fread( $fh, 1024 * 100 ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fread
$count += preg_match_all( '#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches );
}
fclose( $fh ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
return $count > 1;
}
/** ----------------------------------------------------------------------------------------- */
/** WORK WITH PATHS ========================================================================= */
/** ----------------------------------------------------------------------------------------- */
/**
* Make an absolute path relative to WordPress' root folder.
* Also works for files from registered symlinked plugins.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path An absolute path.
* @param string $base A base path to use instead of ABSPATH.
* @return string|bool A relative path. Can return the absolute path or false in case of a failure.
*/
public function make_path_relative( $file_path, $base = '' ) {
global $wp_plugin_paths;
if ( ! $file_path ) {
return false;
}
$file_path = wp_normalize_path( $file_path );
$base = $base ? $this->normalize_dir_path( $base ) : $this->get_site_root();
$pos = strpos( $file_path, $base );
if ( false === $pos && $wp_plugin_paths && is_array( $wp_plugin_paths ) ) {
// The file is probably part of a symlinked plugin.
arsort( $wp_plugin_paths );
foreach ( $wp_plugin_paths as $dir => $real_dir ) {
if ( strpos( $file_path, $real_dir ) === 0 ) {
$file_path = wp_normalize_path( $dir . substr( $file_path, strlen( $real_dir ) ) );
}
}
$pos = strpos( $file_path, $base );
}
if ( false === $pos ) {
// We're in trouble.
return $file_path;
}
return substr_replace( $file_path, '', 0, $pos + strlen( $base ) );
}
/**
* Normalize a directory path.
* The path is normalized and a trailing slash is added.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path The file path.
* @return string The normalized dir path.
*/
public function normalize_dir_path( $file_path ) {
return wp_normalize_path( trailingslashit( $file_path ) );
}
/**
* Normalize a file path, aiming for path comparison.
* The path is normalized, case-lowered, and a trailing slash is added.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $file_path The file path.
* @return string The normalized file path.
*/
public function normalize_path_for_comparison( $file_path ) {
return strtolower( $this->normalize_dir_path( $file_path ) );
}
/** ----------------------------------------------------------------------------------------- */
/** SOME WELL KNOWN PATHS AND URLS ========================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Tell if WordPress is installed in its own directory: aka WP's path !== site's path.
*
* @since 1.8.1
* @access public
* @see https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
* @author Grégory Viguier
*
* @return string
*/
public function has_wp_its_own_directory() {
return $this->get_abspath() !== $this->get_site_root();
}
/**
* The path to the server's root is not always '/', it can also be '//' or 'C://'.
* I am get_root.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @return string The path to the server's root.
*/
public function get_root() {
static $groot;
if ( isset( $groot ) ) {
return $groot;
}
$groot = preg_replace( '@^((?:.:)?/+).*@', '$1', $this->get_site_root() );
return $groot;
}
/**
* Tell if a path is the server's root.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $path The path.
* @return bool
*/
public function is_root( $path ) {
$path = rtrim( $path, '/\\' );
return '.' === $path || '' === $path || preg_match( '@^.:$@', $path );
}
/**
* Get the path to the site's root.
* This is an improved version of get_home_path() that *should* work in almost every cases.
* Because creating a constant like ABSPATH was too simple.
*
* @since 1.8.1
* @access public
* @see get_home_path()
* @author Grégory Viguier
*
* @return string
*/
public function get_site_root() {
static $root_path;
if ( isset( $root_path ) ) {
return $root_path;
}
/**
* Filter the path to the site's root.
*
* @since 1.8.1
* @author Grégory Viguier
*
* @param string $root_path Path to the site's root. Default is null.
*/
$root_path = apply_filters( 'imagify_site_root', null );
if ( is_string( $root_path ) ) {
$root_path = trailingslashit( wp_normalize_path( $root_path ) );
return $root_path;
}
$home = set_url_scheme( untrailingslashit( get_option( 'home' ) ), 'http' );
$siteurl = set_url_scheme( untrailingslashit( get_option( 'siteurl' ) ), 'http' );
if ( ! empty( $home ) && 0 !== strcasecmp( $home, $siteurl ) ) {
$wp_path_rel_to_home = str_ireplace( $home, '', $siteurl ); /* $siteurl - $home */
$pos = strripos( str_replace( '\\', '/', ABSPATH ), trailingslashit( $wp_path_rel_to_home ) );
$root_path = substr( ABSPATH, 0, $pos );
$root_path = trailingslashit( wp_normalize_path( $root_path ) );
return $root_path;
}
if ( ! defined( 'PATH_CURRENT_SITE' ) || ! is_multisite() || is_main_site() ) {
$root_path = $this->get_abspath();
return $root_path;
}
/**
* For a multisite in its own directory, get_home_path() returns the expected path only for the main site.
*
* Friend, each time an attempt is made to improve this method, and especially this part, please increment the following counter.
* Improvement attempts: 3.
*/
$document_root = realpath( wp_unslash( $_SERVER['DOCUMENT_ROOT'] ) ); // `realpath()` is needed for those cases where $_SERVER['DOCUMENT_ROOT'] is totally different from ABSPATH.
$document_root = trailingslashit( str_replace( '\\', '/', $document_root ) );
$path_current_site = trim( str_replace( '\\', '/', PATH_CURRENT_SITE ), '/' );
$root_path = trailingslashit( wp_normalize_path( $document_root . $path_current_site ) );
return $root_path;
}
/**
* Get the URL of the site's root. It corresponds to the main site's home page URL.
*
* @since 1.8.1
* @access public
* @author Grégory Viguier
*
* @return string
*/
public function get_site_root_url() {
static $root_url;
if ( isset( $root_url ) ) {
return $root_url;
}
if ( ! is_multisite() || is_main_site() ) {
$root_url = home_url( '/' );
return $root_url;
}
$current_network = false;
if ( function_exists( 'get_network' ) ) {
$current_network = get_network();
} elseif ( function_exists( 'get_current_site' ) ) {
$current_network = get_current_site();
}
if ( ! $current_network ) {
$root_url = home_url( '/' );
return $root_url;
}
$root_url = is_ssl() ? 'https' : 'http';
$root_url = set_url_scheme( 'http://' . $current_network->domain . $current_network->path, $root_url );
$root_url = trailingslashit( $root_url );
return $root_url;
}
/**
* Tell if a path is the site's root.
*
* @since 1.8.1
* @access public
* @author Grégory Viguier
*
* @param string $path The path.
* @return bool
*/
public function is_site_root( $path ) {
return $this->normalize_dir_path( $path ) === $this->get_site_root();
}
/**
* Get a clean value of ABSPATH.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @return string The path to WordPress' root folder.
*/
public function get_abspath() {
static $abspath;
if ( isset( $abspath ) ) {
return $abspath;
}
$abspath = wp_normalize_path( ABSPATH );
// Make sure ABSPATH is not messed up: it could be defined as a relative path for example (yeah, I know, but we've seen it).
$test_file = wp_normalize_path( IMAGIFY_FILE );
$pos = strpos( $test_file, $abspath );
if ( $pos > 0 ) {
// ABSPATH has a wrong value.
$abspath = substr( $test_file, 0, $pos ) . $abspath;
} elseif ( false === $pos && class_exists( 'ReflectionClass' ) ) {
// Imagify is symlinked (dude, you look for trouble).
$reflector = new ReflectionClass( 'WP' );
$test_file = $reflector->getFileName();
$pos = strpos( $test_file, $abspath );
if ( 0 < $pos ) {
// ABSPATH has a wrong value.
$abspath = substr( $test_file, 0, $pos ) . $abspath;
}
}
$abspath = trailingslashit( $abspath );
if ( '/' !== substr( $abspath, 0, 1 ) && ':' !== substr( $abspath, 1, 1 ) ) {
$abspath = '/' . $abspath;
}
return $abspath;
}
/**
* Tell if a path is WP's root (ABSPATH).
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param string $path The path.
* @return bool
*/
public function is_abspath( $path ) {
return $this->normalize_dir_path( $path ) === $this->get_abspath();
}
/**
* Get the upload basedir.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @param bool $bypass_error True to return the path even if there is an error. This is used when we want to display this path in a message for example.
* @return string|bool The path. False on failure.
*/
public function get_upload_basedir( $bypass_error = false ) {
static $upload_basedir;
static $upload_basedir_or_error;
if ( isset( $upload_basedir ) ) {
return $bypass_error ? $upload_basedir : $upload_basedir_or_error;
}
$uploads = wp_upload_dir();
$upload_basedir = $this->normalize_dir_path( $uploads['basedir'] );
if ( false !== $uploads['error'] ) {
$upload_basedir_or_error = false;
} else {
$upload_basedir_or_error = $upload_basedir;
}
return $bypass_error ? $upload_basedir : $upload_basedir_or_error;
}
/**
* Get the upload baseurl.
*
* @since 1.7.1
* @access public
* @author Grégory Viguier
*
* @return string|bool The URL. False on failure.
*/
public function get_upload_baseurl() {
static $upload_baseurl;
if ( isset( $upload_baseurl ) ) {
return $upload_baseurl;
}
$uploads = wp_upload_dir();
if ( false !== $uploads['error'] ) {
$upload_baseurl = false;
return $upload_baseurl;
}
$upload_baseurl = trailingslashit( $uploads['baseurl'] );
return $upload_baseurl;
}
/**
* Get the path to the uploads base directory of the main site.
*
* @since 1.8
* @access public
* @author Grégory Viguier
*
* @return string
*/
public function get_main_upload_basedir() {
static $basedir;
if ( isset( $basedir ) ) {
return $basedir;
}
$basedir = get_imagify_upload_basedir( true );
if ( is_multisite() ) {
$pattern = '/' . $this->get_multisite_uploads_subdir_pattern() . '$';
$basedir = preg_replace( self::PATTERN_DELIMITER . $pattern . self::PATTERN_DELIMITER, '/', $basedir );
}
return $basedir;
}
/**
* Get the URL of the uploads base directory of the main site.
*
* @since 1.8
* @access public
* @author Grégory Viguier
*
* @return string
*/
public function get_main_upload_baseurl() {
static $baseurl;
if ( isset( $baseurl ) ) {
return $baseurl;
}
$baseurl = get_imagify_upload_baseurl( true );
if ( is_multisite() ) {
$pattern = '/' . $this->get_multisite_uploads_subdir_pattern() . '$';
$baseurl = preg_replace( self::PATTERN_DELIMITER . $pattern . self::PATTERN_DELIMITER, '/', $baseurl );
}
return $baseurl;
}
/**
* Get the regex pattern used to match the uploads subdir on multisite in a file path.
* Pattern delimiter is `Imagify_Filesystem::PATTERN_DELIMITER`.
* Paths tested against these patterns are lower-cased.
*
* @since 1.8
* @access public
* @see _wp_upload_dir()
* @author Grégory Viguier
*
* @return string
*/
public function get_multisite_uploads_subdir_pattern() {
static $pattern;
if ( isset( $pattern ) ) {
return $pattern;
}
$pattern = '';
if ( ! is_multisite() ) {
return $pattern;
}
if ( ! get_site_option( 'ms_files_rewriting' ) ) {
if ( defined( 'MULTISITE' ) ) {
$pattern = 'sites/\d+/';
} else {
$pattern = '\d+/';
}
} elseif ( defined( 'UPLOADS' ) ) {
$site_id = (string) get_current_blog_id();
$path = $this->get_upload_basedir( true ); // Something like `/absolute/path/to/wp-content/blogs.dir/3/files/`, also for site 1.
$path = strrev( $path );
if ( preg_match( self::PATTERN_DELIMITER . '^.*' . strrev( $site_id ) . '[^/]*/' . self::PATTERN_DELIMITER . 'U', $path, $matches ) ) {
$pattern = end( $matches );
$pattern = ltrim( strtolower( strrev( $pattern ) ), '/' );
$pattern = str_replace( $site_id, '\d+', $pattern );
}
}
/**
* Filter the regex pattern used to match the uploads subdir on multisite in a file path.
* Pattern delimiter is `Imagify_Filesystem::PATTERN_DELIMITER`.
* Important: lowercase, no heading slash, mandatory trailing slash.
*
* @since 1.8
* @author Grégory Viguier
*
* @param string $pattern The regex pattern.
*/
$pattern = apply_filters( 'imagify_multisite_uploads_subdir_pattern', $pattern );
return $pattern;
}
}