strlen($base) ? substr($dir, strlen($base)) : null;
}
/**
* Folder holding job state and staging files.
*
* @return string
*/
public static function jobs_dir()
{
return self::dir() . '/jobs';
}
/**
* Folder holding in-progress uploads.
*
* @return string
*/
public static function uploads_dir()
{
return self::dir() . '/uploads';
}
/**
* Creates the folders and blocks direct web access.
*
* @return bool
*/
public static function ensure()
{
foreach (array(self::dir(), self::jobs_dir(), self::uploads_dir()) as $dir) {
if (! is_dir($dir) && ! wp_mkdir_p($dir)) {
return false;
}
if (! file_exists($dir . '/index.php')) {
@file_put_contents($dir . '/index.php', "\nRequire all denied\n\n\nOrder allow,deny\nDeny from all\n\nOptions -Indexes\n");
}
if (! file_exists($dir . '/web.config')) {
@file_put_contents($dir . '/web.config', "\n\n");
}
}
return is_writable(self::dir());
}
/**
* Backups in the storage folder, newest first.
*
* @return array[] name, size, time.
*/
public static function list_backups()
{
$out = array();
$files = array_merge((array) glob(self::dir() . '/*' . self::EXT), (array) glob(self::dir() . '/*.wpress'));
foreach ($files as $file) {
if (is_file($file)) {
$out[] = array(
'name' => basename($file),
'size' => (float) filesize($file),
'time' => (int) filemtime($file),
);
}
}
usort(
$out,
static function ($a, $b) {
return $b['time'] - $a['time'];
}
);
return $out;
}
/**
* Safe absolute path to a stored backup, or false.
*
* @param string $name File name.
* @return string|false
*/
public static function backup_path($name)
{
$name = basename((string) $name);
if (! preg_match('/^[A-Za-z0-9._-]+\.(shiftbox|wpress)$/', $name)) {
return false;
}
$path = self::dir() . '/' . $name;
return is_file($path) ? $path : false;
}
/**
* Folder where All-in-One WP Migration keeps its backups on this site.
*
* @return string
*/
public static function ai1wm_dir()
{
return self::content_dir() . '/ai1wm-backups';
}
/**
* .wpress backups made by All-in-One WP Migration on this site, newest first.
*
* @return array[] name, size, time.
*/
public static function list_ai1wm()
{
$out = array();
foreach ((array) glob(self::ai1wm_dir() . '/*.wpress') as $file) {
if (is_file($file)) {
$out[] = array(
'name' => basename($file),
'size' => (float) filesize($file),
'time' => (int) filemtime($file),
);
}
}
usort(
$out,
static function ($a, $b) {
return $b['time'] - $a['time'];
}
);
return $out;
}
/**
* Safe path to an All-in-One WP Migration backup on this site, or false.
*
* @param string $name File name.
* @return string|false
*/
public static function ai1wm_path($name)
{
$name = basename((string) $name);
if (! preg_match('/^[A-Za-z0-9._-]+\.wpress$/', $name)) {
return false;
}
$path = self::ai1wm_dir() . '/' . $name;
return is_file($path) ? $path : false;
}
/**
* New unguessable backup file name.
*
* @param string $tag Optional tag.
* @return string
*/
public static function new_backup_name($tag = '')
{
/**
* Filters the first part of backup file names (default: the site's host name).
*
* @param string $host Host name.
*/
$host = apply_filters('shiftbox_backup_name_prefix', (string) wp_parse_url(home_url(), PHP_URL_HOST));
$host = preg_replace('/[^A-Za-z0-9-]+/', '-', (string) $host);
$tag = $tag ? '-' . sanitize_key($tag) : '';
return trim($host, '-') . $tag . '-' . gmdate('Ymd-His') . '-' . strtolower(wp_generate_password(16, false)) . self::EXT;
}
/**
* Removes a folder recursively.
*
* @param string $dir Folder.
* @return void
*/
public static function rrmdir($dir)
{
if (! is_dir($dir) || is_link($dir)) {
if (is_link($dir) || is_file($dir)) {
@unlink($dir);
}
return;
}
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($it as $f) {
if ($f->isDir() && ! $f->isLink()) {
@rmdir($f->getPathname());
} else {
@unlink($f->getPathname());
}
}
@rmdir($dir);
}
/**
* Free disk space in bytes, or -1 when unknown.
*
* @return float
*/
public static function free_space()
{
if (function_exists('disk_free_space')) {
$free = @disk_free_space(self::dir());
if (false !== $free) {
return (float) $free;
}
}
return -1;
}
/**
* Moves a file or folder, falling back to copy across devices.
*
* @param string $from Source.
* @param string $to Target.
* @return bool
*/
public static function move($from, $to)
{
if (@rename($from, $to)) {
return true;
}
if (is_dir($from)) {
if (! wp_mkdir_p($to)) {
return false;
}
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($from, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($it as $f) {
$target = $to . '/' . substr($f->getPathname(), strlen($from) + 1);
if ($f->isDir()) {
wp_mkdir_p($target);
} elseif (! @copy($f->getPathname(), $target)) {
return false;
}
}
self::rrmdir($from);
return true;
}
if (@copy($from, $to)) {
@unlink($from);
return true;
}
return false;
}
}