Файловый менеджер - Редактировать - /var/www/html/fileop.zip
Ðазад
PK ! �1s~� � FileStatePredicates.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use Closure; /** * Helper class for tracking counterfactual file states when pre-checking file operation batches * * The file states are represented with (existence,size,sha1) triples. When combined with the * current state of files in the backend, this can be used to simulate how a batch of operations * would play out as a "dry run". This is used in FileBackend::doOperations() to bail out if any * failure can be predicted before modifying any data. This includes file operation batches where * the same file gets modified by different operations within the batch. * * @internal Only for use within FileBackend */ class FileStatePredicates { protected const EXISTS = 'exists'; protected const SIZE = 'size'; protected const SHA1 = 'sha1'; /** @var array<string,array> Map of (storage path => file state map) */ private $fileStateByPath; public function __construct() { $this->fileStateByPath = []; } /** * Predicate that a file exists at the path * * @param string $path Storage path * @param int|false|Closure $size File size or idempotent function yielding the size * @param string|Closure $sha1Base36 File hash, or, idempotent function yielding the hash */ public function assumeFileExists( string $path, $size, $sha1Base36 ) { $this->fileStateByPath[$path] = [ self::EXISTS => true, self::SIZE => $size, self::SHA1 => $sha1Base36 ]; } /** * Predicate that no file exists at the path * * @param string $path Storage path */ public function assumeFileDoesNotExist( string $path ) { $this->fileStateByPath[$path] = [ self::EXISTS => false, self::SIZE => false, self::SHA1 => false ]; } /** * Get the hypothetical existance a file given predicated and current state of files * * @param string $path Storage path * @param Closure $curExistenceFunc Function to compute the current existence for a given path * @return bool|null Whether the file exists; null on error */ public function resolveFileExistence( string $path, $curExistenceFunc ) { return self::resolveFileProperty( $path, self::EXISTS, $curExistenceFunc ); } /** * Get the hypothetical size of a file given predicated and current state of files * * @param string $path Storage path * @param Closure $curSizeFunc Function to compute the current size for a given path * @return int|false Bytes; false on error */ public function resolveFileSize( string $path, $curSizeFunc ) { return self::resolveFileProperty( $path, self::SIZE, $curSizeFunc ); } /** * Get the hypothetical SHA-1 hash of a file given predicated and current state of files * * @param string $path Storage path * @param Closure $curSha1Func Function to compute the current SHA-1 hash for a given path * @return string|false Base 36 SHA-1 hash; false on error */ public function resolveFileSha1Base36( string $path, $curSha1Func ) { return self::resolveFileProperty( $path, self::SHA1, $curSha1Func ); } /** * @param string $path Storage path * @param string $property One of (self::EXISTS, self::SIZE, self::SHA1) * @param Closure $curValueFunc Function to compute the current value for a given path * @return mixed */ private function resolveFileProperty( $path, $property, $curValueFunc ) { if ( isset( $this->fileStateByPath[$path] ) ) { // File is predicated to have a counterfactual state $value = $this->fileStateByPath[$path][$property]; if ( $value instanceof Closure ) { $value = $value(); $this->fileStateByPath[$path][$property] = $value; } } else { // File is not predicated to have a counterfactual state; use the current state $value = $curValueFunc( $path ); } return $value; } /** * @param string[] $paths List of storage paths * @return self Clone predicates limited to the given paths */ public function snapshot( array $paths ) { $snapshot = new self(); foreach ( $paths as $path ) { if ( isset( $this->fileStateByPath[$path] ) ) { $snapshot->fileStateByPath[$path] = $this->fileStateByPath[$path]; } } return $snapshot; } } /** @deprecated class alias since 1.43 */ class_alias( FileStatePredicates::class, 'FileStatePredicates' ); PK ! /���� � DescribeFileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use StatusValue; use Wikimedia\FileBackend\FileBackend; /** * Change metadata for a file at the given storage path in the backend. * Parameters for this operation are outlined in FileBackend::doOperations(). */ class DescribeFileOp extends FileOp { protected function allowedParams() { return [ [ 'src' ], [ 'headers' ], [ 'src' ] ]; } protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { $status = StatusValue::newGood(); // Check source file existence $srcExists = $this->resolveFileExistence( $this->params['src'], $opPredicates ); if ( $srcExists === false ) { $status->fatal( 'backend-fail-notexists', $this->params['src'] ); return $status; } elseif ( $srcExists === FileBackend::EXISTENCE_ERROR ) { $status->fatal( 'backend-fail-stat', $this->params['src'] ); return $status; } // Update file existence predicates since the operation is expected to be allowed to run $srcSize = function () use ( $opPredicates ) { static $size = null; $size ??= $this->resolveFileSize( $this->params['src'], $opPredicates ); return $size; }; $srcSha1 = function () use ( $opPredicates ) { static $sha1 = null; $sha1 ??= $this->resolveFileSha1Base36( $this->params['src'], $opPredicates ); return $sha1; }; $batchPredicates->assumeFileExists( $this->params['src'], $srcSize, $srcSha1 ); return $status; // safe to call attempt() } protected function doAttempt() { // Update the source file's metadata return $this->backend->describeInternal( $this->setFlags( $this->params ) ); } public function storagePathsChanged() { return [ $this->params['src'] ]; } } /** @deprecated class alias since 1.43 */ class_alias( DescribeFileOp::class, 'DescribeFileOp' ); PK ! �2�% % DeleteFileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use StatusValue; use Wikimedia\FileBackend\FileBackend; /** * Delete a file at the given storage path from the backend. * Parameters for this operation are outlined in FileBackend::doOperations(). */ class DeleteFileOp extends FileOp { protected function allowedParams() { return [ [ 'src' ], [ 'ignoreMissingSource' ], [ 'src' ] ]; } protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { $status = StatusValue::newGood(); // Check source file existence $srcExists = $this->resolveFileExistence( $this->params['src'], $opPredicates ); if ( $srcExists === false ) { if ( $this->getParam( 'ignoreMissingSource' ) ) { $this->noOp = true; // no-op // Update file existence predicates (cache 404s) $batchPredicates->assumeFileDoesNotExist( $this->params['src'] ); return $status; // nothing to do } else { $status->fatal( 'backend-fail-notexists', $this->params['src'] ); return $status; } } elseif ( $srcExists === FileBackend::EXISTENCE_ERROR ) { $status->fatal( 'backend-fail-stat', $this->params['src'] ); return $status; } // Update file existence predicates since the operation is expected to be allowed to run $batchPredicates->assumeFileDoesNotExist( $this->params['src'] ); return $status; // safe to call attempt() } protected function doAttempt() { // Delete the source file return $this->backend->deleteInternal( $this->setFlags( $this->params ) ); } public function storagePathsChanged() { return [ $this->params['src'] ]; } } /** @deprecated class alias since 1.43 */ class_alias( DeleteFileOp::class, 'DeleteFileOp' ); PK ! �Ki�� � MoveFileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use StatusValue; use Wikimedia\FileBackend\FileBackend; /** * Move a file from one storage path to another in the backend. * Parameters for this operation are outlined in FileBackend::doOperations(). */ class MoveFileOp extends FileOp { protected function allowedParams() { return [ [ 'src', 'dst' ], [ 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ], [ 'src', 'dst' ] ]; } protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { $status = StatusValue::newGood(); // Check source file existence $srcExists = $this->resolveFileExistence( $this->params['src'], $opPredicates ); if ( $srcExists === false ) { if ( $this->getParam( 'ignoreMissingSource' ) ) { $this->noOp = true; // no-op // Update file existence predicates (cache 404s) $batchPredicates->assumeFileDoesNotExist( $this->params['src'] ); return $status; // nothing to do } else { $status->fatal( 'backend-fail-notexists', $this->params['src'] ); return $status; } } elseif ( $srcExists === FileBackend::EXISTENCE_ERROR ) { $status->fatal( 'backend-fail-stat', $this->params['src'] ); return $status; } // Check if an incompatible destination file exists $srcSize = function () use ( $opPredicates ) { static $size = null; $size ??= $this->resolveFileSize( $this->params['src'], $opPredicates ); return $size; }; $srcSha1 = function () use ( $opPredicates ) { static $sha1 = null; $sha1 ??= $this->resolveFileSha1Base36( $this->params['src'], $opPredicates ); return $sha1; }; $status->merge( $this->precheckDestExistence( $opPredicates, $srcSize, $srcSha1 ) ); $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache() // Update file existence predicates if the operation is expected to be allowed to run if ( $status->isOK() ) { $batchPredicates->assumeFileExists( $this->params['dst'], $srcSize, $srcSha1 ); if ( $this->params['src'] !== $this->params['dst'] ) { $batchPredicates->assumeFileDoesNotExist( $this->params['src'] ); } } return $status; // safe to call attempt() } protected function doAttempt() { if ( $this->overwriteSameCase ) { if ( $this->params['src'] === $this->params['dst'] ) { // Do nothing to the destination (which is also the source) $status = StatusValue::newGood(); } else { // Just delete the source as the destination file needs no changes $status = $this->backend->deleteInternal( $this->setFlags( [ 'src' => $this->params['src'] ] ) ); } } elseif ( $this->params['src'] === $this->params['dst'] ) { // Just update the destination file headers $headers = $this->getParam( 'headers' ) ?: []; $status = $this->backend->describeInternal( $this->setFlags( [ 'src' => $this->params['dst'], 'headers' => $headers ] ) ); } else { // Move the file to the destination $status = $this->backend->moveInternal( $this->setFlags( $this->params ) ); } return $status; } public function storagePathsRead() { return [ $this->params['src'] ]; } public function storagePathsChanged() { return [ $this->params['src'], $this->params['dst'] ]; } } /** @deprecated class alias since 1.43 */ class_alias( MoveFileOp::class, 'MoveFileOp' ); PK ! �� CreateFileOp.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use StatusValue; /** * Create a file in the backend with the given content. * Parameters for this operation are outlined in FileBackend::doOperations(). */ class CreateFileOp extends FileOp { protected function allowedParams() { return [ [ 'content', 'dst' ], [ 'overwrite', 'overwriteSame', 'headers' ], [ 'dst' ] ]; } protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { $status = StatusValue::newGood(); // Check if the source data is too big $sourceSize = $this->getSourceSize(); $maxFileSize = $this->backend->maxFileSizeInternal(); if ( $sourceSize > $maxFileSize ) { $status->fatal( 'backend-fail-maxsize', $this->params['dst'], $maxFileSize ); return $status; } // Check if an incompatible destination file exists $sourceSha1 = $this->getSourceSha1Base36(); $status->merge( $this->precheckDestExistence( $opPredicates, $sourceSize, $sourceSha1 ) ); $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache() // Update file existence predicates if the operation is expected to be allowed to run if ( $status->isOK() ) { $batchPredicates->assumeFileExists( $this->params['dst'], $sourceSize, $sourceSha1 ); } return $status; // safe to call attempt() } protected function doAttempt() { if ( $this->overwriteSameCase ) { $status = StatusValue::newGood(); // nothing to do } else { // Create the file at the destination $status = $this->backend->createInternal( $this->setFlags( $this->params ) ); } return $status; } protected function getSourceSize() { return strlen( $this->params['content'] ); } protected function getSourceSha1Base36() { return \Wikimedia\base_convert( sha1( $this->params['content'] ), 16, 36, 31 ); } public function storagePathsChanged() { return [ $this->params['dst'] ]; } } /** @deprecated class alias since 1.43 */ class_alias( CreateFileOp::class, 'CreateFileOp' ); PK ! �^�� � CopyFileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use StatusValue; use Wikimedia\FileBackend\FileBackend; /** * Copy a file from one storage path to another in the backend. * Parameters for this operation are outlined in FileBackend::doOperations(). */ class CopyFileOp extends FileOp { protected function allowedParams() { return [ [ 'src', 'dst' ], [ 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ], [ 'src', 'dst' ] ]; } protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { $status = StatusValue::newGood(); // Check source file existence $srcExists = $this->resolveFileExistence( $this->params['src'], $opPredicates ); if ( $srcExists === false ) { if ( $this->getParam( 'ignoreMissingSource' ) ) { $this->noOp = true; // no-op // Update file existence predicates (cache 404s) $batchPredicates->assumeFileDoesNotExist( $this->params['src'] ); return $status; // nothing to do } else { $status->fatal( 'backend-fail-notexists', $this->params['src'] ); return $status; } } elseif ( $srcExists === FileBackend::EXISTENCE_ERROR ) { $status->fatal( 'backend-fail-stat', $this->params['src'] ); return $status; } // Check if an incompatible destination file exists $srcSize = function () use ( $opPredicates ) { static $size = null; $size ??= $this->resolveFileSize( $this->params['src'], $opPredicates ); return $size; }; $srcSha1 = function () use ( $opPredicates ) { static $sha1 = null; $sha1 ??= $this->resolveFileSha1Base36( $this->params['src'], $opPredicates ); return $sha1; }; $status->merge( $this->precheckDestExistence( $opPredicates, $srcSize, $srcSha1 ) ); $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache() // Update file existence predicates if the operation is expected to be allowed to run if ( $status->isOK() ) { $batchPredicates->assumeFileExists( $this->params['dst'], $srcSize, $srcSha1 ); } return $status; // safe to call attempt() } protected function doAttempt() { if ( $this->overwriteSameCase ) { $status = StatusValue::newGood(); // nothing to do } elseif ( $this->params['src'] === $this->params['dst'] ) { // Just update the destination file headers $headers = $this->getParam( 'headers' ) ?: []; $status = $this->backend->describeInternal( $this->setFlags( [ 'src' => $this->params['dst'], 'headers' => $headers ] ) ); } else { // Copy the file to the destination $status = $this->backend->copyInternal( $this->setFlags( $this->params ) ); } return $status; } public function storagePathsRead() { return [ $this->params['src'] ]; } public function storagePathsChanged() { return [ $this->params['dst'] ]; } } /** @deprecated class alias since 1.43 */ class_alias( CopyFileOp::class, 'CopyFileOp' ); PK ! V�_ _ NullFileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; /** * Placeholder operation that has no params and does nothing */ class NullFileOp extends FileOp { } /** @deprecated class alias since 1.43 */ class_alias( NullFileOp::class, 'NullFileOp' ); PK ! O�ez8 z8 FileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use Closure; use Exception; use InvalidArgumentException; use MediaWiki\Json\FormatJson; use Psr\Log\LoggerInterface; use StatusValue; use Wikimedia\FileBackend\FileBackend; use Wikimedia\FileBackend\FileBackendStore; use Wikimedia\RequestTimeout\TimeoutException; /** * FileBackend helper class for representing operations. * Do not use this class from places outside FileBackend. * * Methods called from FileOpBatch::attempt() should avoid throwing * exceptions at all costs. FileOp objects should be lightweight in order * to support large arrays in memory and serialization. * * @ingroup FileBackend * @since 1.19 */ abstract class FileOp { /** @var FileBackendStore */ protected $backend; /** @var LoggerInterface */ protected $logger; /** @var array */ protected $params = []; /** @var int Stage in the operation life-cycle */ protected $state = self::STATE_NEW; /** @var bool Whether the operation pre-check or attempt stage failed */ protected $failed = false; /** @var bool Whether the operation is part of a concurrent sub-batch of operation */ protected $async = false; /** @var bool Whether the operation pre-check stage marked the attempt stage as a no-op */ protected $noOp = false; /** @var bool|null */ protected $overwriteSameCase; /** @var bool|null */ protected $destExists; /** Operation has not yet been pre-checked nor run */ private const STATE_NEW = 1; /** Operation has been pre-checked but not yet attempted */ private const STATE_CHECKED = 2; /** Operation has been attempted */ private const STATE_ATTEMPTED = 3; /** * Build a new batch file operation transaction * * @param FileBackendStore $backend * @param array $params * @param LoggerInterface $logger PSR logger instance */ final public function __construct( FileBackendStore $backend, array $params, LoggerInterface $logger ) { $this->backend = $backend; $this->logger = $logger; [ $required, $optional, $paths ] = $this->allowedParams(); foreach ( $required as $name ) { if ( isset( $params[$name] ) ) { $this->params[$name] = $params[$name]; } else { throw new InvalidArgumentException( "File operation missing parameter '$name'." ); } } foreach ( $optional as $name ) { if ( isset( $params[$name] ) ) { $this->params[$name] = $params[$name]; } } foreach ( $paths as $name ) { if ( isset( $this->params[$name] ) ) { // Normalize paths so the paths to the same file have the same string $this->params[$name] = self::normalizeIfValidStoragePath( $this->params[$name] ); } } } /** * Normalize a string if it is a valid storage path * * @param string $path * @return string */ protected static function normalizeIfValidStoragePath( $path ) { if ( FileBackend::isStoragePath( $path ) ) { $res = FileBackend::normalizeStoragePath( $path ); return $res ?? $path; } return $path; } /** * Get the value of the parameter with the given name * * @param string $name * @return mixed Returns null if the parameter is not set */ final public function getParam( $name ) { return $this->params[$name] ?? null; } /** * Check if this operation failed precheck() or attempt() * * @return bool */ final public function failed() { return $this->failed; } /** * Get a new empty dependency tracking array for paths read/written to * * @return array */ final public static function newDependencies() { return [ 'read' => [], 'write' => [] ]; } /** * Update a dependency tracking array to account for this operation * * @param array $deps Prior path reads/writes; format of FileOp::newDependencies() * @return array */ final public function applyDependencies( array $deps ) { $deps['read'] += array_fill_keys( $this->storagePathsRead(), 1 ); $deps['write'] += array_fill_keys( $this->storagePathsChanged(), 1 ); return $deps; } /** * Check if this operation changes files listed in $paths * * @param array $deps Prior path reads/writes; format of FileOp::newDependencies() * @return bool */ final public function dependsOn( array $deps ) { foreach ( $this->storagePathsChanged() as $path ) { if ( isset( $deps['read'][$path] ) || isset( $deps['write'][$path] ) ) { return true; // "output" or "anti" dependency } } foreach ( $this->storagePathsRead() as $path ) { if ( isset( $deps['write'][$path] ) ) { return true; // "flow" dependency } } return false; } /** * Do a dry-run precondition check of the operation in the context of op batch * * Updates the batch predicates for all paths this op can change if an OK status is returned * * @param FileStatePredicates $predicates Counterfactual file states for the op batch * @return StatusValue */ final public function precheck( FileStatePredicates $predicates ) { if ( $this->state !== self::STATE_NEW ) { return StatusValue::newFatal( 'fileop-fail-state', self::STATE_NEW, $this->state ); } $this->state = self::STATE_CHECKED; $status = StatusValue::newGood(); foreach ( $this->storagePathsReadOrChanged() as $path ) { if ( !$this->backend->isPathUsableInternal( $path ) ) { $status->fatal( 'backend-fail-usable', $path ); } } if ( !$status->isOK() ) { return $status; } $opPredicates = $predicates->snapshot( $this->storagePathsReadOrChanged() ); $status = $this->doPrecheck( $opPredicates, $predicates ); if ( !$status->isOK() ) { $this->failed = true; } return $status; } /** * Do a dry-run precondition check of the operation in the context of op batch * * Updates the batch predicates for all paths this op can change if an OK status is returned * * @param FileStatePredicates $opPredicates Counterfactual file states for op paths at op start * @param FileStatePredicates $batchPredicates Counterfactual file states for the op batch * @return StatusValue */ protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { return StatusValue::newGood(); } /** * Attempt the operation * * @return StatusValue */ final public function attempt() { if ( $this->state !== self::STATE_CHECKED ) { return StatusValue::newFatal( 'fileop-fail-state', self::STATE_CHECKED, $this->state ); } elseif ( $this->failed ) { // failed precheck return StatusValue::newFatal( 'fileop-fail-attempt-precheck' ); } $this->state = self::STATE_ATTEMPTED; if ( $this->noOp ) { $status = StatusValue::newGood(); // no-op } else { $status = $this->doAttempt(); if ( !$status->isOK() ) { $this->failed = true; $this->logFailure( 'attempt' ); } } return $status; } /** * @return StatusValue */ protected function doAttempt() { return StatusValue::newGood(); } /** * Attempt the operation in the background * * @return StatusValue */ final public function attemptAsync() { $this->async = true; $result = $this->attempt(); $this->async = false; return $result; } /** * Attempt the operation without regards to prechecks * * @return StatusValue */ final public function attemptQuick() { $this->state = self::STATE_CHECKED; // bypassed return $this->attempt(); } /** * Attempt the operation in the background without regards to prechecks * * @return StatusValue */ final public function attemptAsyncQuick() { $this->state = self::STATE_CHECKED; // bypassed return $this->attemptAsync(); } /** * Get the file operation parameters * * @return array (required params list, optional params list, list of params that are paths) */ protected function allowedParams() { return [ [], [], [] ]; } /** * Adjust params to FileBackendStore internal file calls * * @param array $params * @return array (required params list, optional params list) */ protected function setFlags( array $params ) { return [ 'async' => $this->async ] + $params; } /** * Get a list of storage paths read from for this operation * * @return array */ public function storagePathsRead() { return []; } /** * Get a list of storage paths written to for this operation * * @return array */ public function storagePathsChanged() { return []; } /** * Get a list of storage paths read from or written to for this operation * * @return array */ final public function storagePathsReadOrChanged() { return array_values( array_unique( array_merge( $this->storagePathsRead(), $this->storagePathsChanged() ) ) ); } /** * Check for errors with regards to the destination file already existing * * Also set the destExists and overwriteSameCase member variables. * A bad StatusValue will be returned if there is no chance it can be overwritten. * * @param FileStatePredicates $opPredicates Counterfactual storage path states for this op * @param int|false|Closure $sourceSize Source size or idempotent function yielding the size * @param string|Closure $sourceSha1 Source hash, or, idempotent function yielding the hash * @return StatusValue */ protected function precheckDestExistence( FileStatePredicates $opPredicates, $sourceSize, $sourceSha1 ) { $status = StatusValue::newGood(); // Record the existence of destination file $this->destExists = $this->resolveFileExistence( $this->params['dst'], $opPredicates ); // Check if an incompatible file exists at the destination $this->overwriteSameCase = false; if ( $this->destExists ) { if ( $this->getParam( 'overwrite' ) ) { return $status; // OK, no conflict } elseif ( $this->getParam( 'overwriteSame' ) ) { // Operation does nothing other than return an OK or bad status $sourceSize = ( $sourceSize instanceof Closure ) ? $sourceSize() : $sourceSize; $sourceSha1 = ( $sourceSha1 instanceof Closure ) ? $sourceSha1() : $sourceSha1; $dstSha1 = $this->resolveFileSha1Base36( $this->params['dst'], $opPredicates ); $dstSize = $this->resolveFileSize( $this->params['dst'], $opPredicates ); // Check if hashes are valid and match each other... if ( !strlen( $sourceSha1 ) || !strlen( $dstSha1 ) ) { $status->fatal( 'backend-fail-hashes' ); } elseif ( !is_int( $sourceSize ) || !is_int( $dstSize ) ) { $status->fatal( 'backend-fail-sizes' ); } elseif ( $sourceSha1 !== $dstSha1 || $sourceSize !== $dstSize ) { // Give an error if the files are not identical $status->fatal( 'backend-fail-notsame', $this->params['dst'] ); } else { $this->overwriteSameCase = true; // OK } } else { $status->fatal( 'backend-fail-alreadyexists', $this->params['dst'] ); } } elseif ( $this->destExists === FileBackend::EXISTENCE_ERROR ) { $status->fatal( 'backend-fail-stat', $this->params['dst'] ); } return $status; } /** * Check if a file will exist in storage when this operation is attempted * * Ideally, the file stat entry should already be preloaded via preloadFileStat(). * Otherwise, this will query the backend. * * @param string $source Storage path * @param FileStatePredicates $opPredicates Counterfactual storage path states for this op * @return bool|null Whether the file will exist or null on error */ final protected function resolveFileExistence( $source, FileStatePredicates $opPredicates ) { return $opPredicates->resolveFileExistence( $source, function ( $path ) { return $this->backend->fileExists( [ 'src' => $path, 'latest' => true ] ); } ); } /** * Get the size a file in storage will have when this operation is attempted * * Ideally, file the stat entry should already be preloaded via preloadFileStat() and * the backend tracks hashes as extended attributes. Otherwise, this will query the backend. * Get the size of a file in storage when this operation is attempted * * @param string $source Storage path * @param FileStatePredicates $opPredicates Counterfactual storage path states for this op * @return int|false False on failure */ final protected function resolveFileSize( $source, FileStatePredicates $opPredicates ) { return $opPredicates->resolveFileSize( $source, function ( $path ) { return $this->backend->getFileSize( [ 'src' => $path, 'latest' => true ] ); } ); } /** * Get the SHA-1 of a file in storage when this operation is attempted * * @param string $source Storage path * @param FileStatePredicates $opPredicates Counterfactual storage path states for this op * @return string|false The SHA-1 hash the file will have or false if non-existent or on error */ final protected function resolveFileSha1Base36( $source, FileStatePredicates $opPredicates ) { return $opPredicates->resolveFileSha1Base36( $source, function ( $path ) { return $this->backend->getFileSha1Base36( [ 'src' => $path, 'latest' => true ] ); } ); } /** * Get the backend this operation is for * * @return FileBackendStore */ public function getBackend() { return $this->backend; } /** * Log a file operation failure and preserve any temp files * * @param string $action */ final public function logFailure( $action ) { $params = $this->params; $params['failedAction'] = $action; try { $this->logger->error( static::class . " failed: " . FormatJson::encode( $params ) ); } catch ( TimeoutException $e ) { throw $e; } catch ( Exception $e ) { // bad config? debug log error? } } } /** @deprecated class alias since 1.43 */ class_alias( FileOp::class, 'FileOp' ); PK ! �Z�W W StoreFileOp.phpnu �Iw�� <?php /** * Helper class for representing operations with transaction support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup FileBackend */ namespace Wikimedia\FileBackend\FileOps; use StatusValue; use Wikimedia\AtEase\AtEase; /** * Store a file into the backend from a file on the file system. * Parameters for this operation are outlined in FileBackend::doOperations(). */ class StoreFileOp extends FileOp { protected function allowedParams() { return [ [ 'src', 'dst' ], [ 'overwrite', 'overwriteSame', 'headers' ], [ 'src', 'dst' ] ]; } protected function doPrecheck( FileStatePredicates $opPredicates, FileStatePredicates $batchPredicates ) { $status = StatusValue::newGood(); // Check if the source file exists in the file system if ( !is_file( $this->params['src'] ) ) { $status->fatal( 'backend-fail-notexists', $this->params['src'] ); return $status; } // Check if the source file is too big $sourceSize = $this->getSourceSize(); $maxFileSize = $this->backend->maxFileSizeInternal(); if ( $sourceSize > $maxFileSize ) { $status->fatal( 'backend-fail-maxsize', $this->params['dst'], $maxFileSize ); return $status; } // Check if an incompatible destination file exists $sourceSha1 = function () { static $sha1 = null; $sha1 ??= $this->getSourceSha1Base36(); return $sha1; }; $status->merge( $this->precheckDestExistence( $opPredicates, $sourceSize, $sourceSha1 ) ); $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache() // Update file existence predicates if the operation is expected to be allowed to run if ( $status->isOK() ) { $batchPredicates->assumeFileExists( $this->params['dst'], $sourceSize, $sourceSha1 ); } return $status; // safe to call attempt() } protected function doAttempt() { if ( $this->overwriteSameCase ) { $status = StatusValue::newGood(); // nothing to do } else { // Store the file at the destination $status = $this->backend->storeInternal( $this->setFlags( $this->params ) ); } return $status; } protected function getSourceSize() { AtEase::suppressWarnings(); $size = filesize( $this->params['src'] ); AtEase::restoreWarnings(); return $size; } protected function getSourceSha1Base36() { AtEase::suppressWarnings(); $hash = sha1_file( $this->params['src'] ); AtEase::restoreWarnings(); if ( $hash !== false ) { $hash = \Wikimedia\base_convert( $hash, 16, 36, 31 ); } return $hash; } public function storagePathsChanged() { return [ $this->params['dst'] ]; } } /** @deprecated class alias since 1.43 */ class_alias( StoreFileOp::class, 'StoreFileOp' ); PK ! �1s~� � FileStatePredicates.phpnu �Iw�� PK ! /���� � � DescribeFileOp.phpnu �Iw�� PK ! �2�% % � DeleteFileOp.phpnu �Iw�� PK ! �Ki�� � 5) MoveFileOp.phpnu �Iw�� PK ! �� : CreateFileOp.phpnu �Iw�� PK ! �^�� � bE CopyFileOp.phpnu �Iw�� PK ! V�_ _ mT NullFileOp.phpnu �Iw�� PK ! O�ez8 z8 Y FileOp.phpnu �Iw�� PK ! �Z�W W �� StoreFileOp.phpnu �Iw�� PK � T�
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0.01 |
proxy
|
phpinfo
|
ÐаÑтройка