コード例 #1
0
ファイル: StreamFile.php プロジェクト: whysasse/kmwiki
 /**
  * Stream a file to the browser, adding all the headings and fun stuff.
  * Headers sent include: Content-type, Content-Length, Last-Modified,
  * and Content-Disposition.
  *
  * @param string $fname Full name and path of the file to stream
  * @param array $headers Any additional headers to send
  * @param bool $sendErrors Send error messages if errors occur (like 404)
  * @throws MWException
  * @return bool Success
  */
 public static function stream($fname, $headers = array(), $sendErrors = true)
 {
     wfProfileIn(__METHOD__);
     if (FileBackend::isStoragePath($fname)) {
         // sanity
         wfProfileOut(__METHOD__);
         throw new MWException(__FUNCTION__ . " given storage path '{$fname}'.");
     }
     wfSuppressWarnings();
     $stat = stat($fname);
     wfRestoreWarnings();
     $res = self::prepareForStream($fname, $stat, $headers, $sendErrors);
     if ($res == self::NOT_MODIFIED) {
         $ok = true;
         // use client cache
     } elseif ($res == self::READY_STREAM) {
         wfProfileIn(__METHOD__ . '-send');
         $ok = readfile($fname);
         wfProfileOut(__METHOD__ . '-send');
     } else {
         $ok = false;
         // failed
     }
     wfProfileOut(__METHOD__);
     return $ok;
 }
コード例 #2
0
ファイル: FSFile.php プロジェクト: seedbank/old-repo
 /**
  * Sets up the file object
  *
  * @param $path string Path to temporary file on local disk
  * @throws MWException
  */
 public function __construct($path)
 {
     if (FileBackend::isStoragePath($path)) {
         throw new MWException(__METHOD__ . " given storage path `{$path}`.");
     }
     $this->path = $path;
 }
コード例 #3
0
ファイル: StreamFile.php プロジェクト: paladox/mediawiki
 /**
  * Stream a file to the browser, adding all the headings and fun stuff.
  * Headers sent include: Content-type, Content-Length, Last-Modified,
  * and Content-Disposition.
  *
  * @param string $fname Full name and path of the file to stream
  * @param array $headers Any additional headers to send if the file exists
  * @param bool $sendErrors Send error messages if errors occur (like 404)
  * @param array $optHeaders HTTP request header map (e.g. "range") (use lowercase keys)
  * @param integer $flags Bitfield of STREAM_* constants
  * @throws MWException
  * @return bool Success
  */
 public static function stream($fname, $headers = [], $sendErrors = true, $optHeaders = [], $flags = 0)
 {
     if (FileBackend::isStoragePath($fname)) {
         // sanity
         throw new InvalidArgumentException(__FUNCTION__ . " given storage path '{$fname}'.");
     }
     $streamer = new HTTPFileStreamer($fname, ['obResetFunc' => 'wfResetOutputBuffers', 'streamMimeFunc' => [__CLASS__, 'contentTypeFromPath']]);
     return $streamer->stream($headers, $sendErrors, $optHeaders, $flags);
 }
コード例 #4
0
ファイル: StreamFile.php プロジェクト: claudinec/galan-wiki
 /**
  * Stream a file to the browser, adding all the headings and fun stuff.
  * Headers sent include: Content-type, Content-Length, Last-Modified,
  * and Content-Disposition.
  *
  * @param string $fname Full name and path of the file to stream
  * @param array $headers Any additional headers to send
  * @param bool $sendErrors Send error messages if errors occur (like 404)
  * @throws MWException
  * @return bool Success
  */
 public static function stream($fname, $headers = [], $sendErrors = true)
 {
     if (FileBackend::isStoragePath($fname)) {
         // sanity
         throw new MWException(__FUNCTION__ . " given storage path '{$fname}'.");
     }
     MediaWiki\suppressWarnings();
     $stat = stat($fname);
     MediaWiki\restoreWarnings();
     $res = self::prepareForStream($fname, $stat, $headers, $sendErrors);
     if ($res == self::NOT_MODIFIED) {
         $ok = true;
         // use client cache
     } elseif ($res == self::READY_STREAM) {
         $ok = readfile($fname);
     } else {
         $ok = false;
         // failed
     }
     return $ok;
 }
コード例 #5
0
ファイル: FileRepo.php プロジェクト: Tjorriemorrie/app
 /**
  * Checks existence of an array of files.
  *
  * @param $files Array: Virtual URLs (or storage paths) of files to check
  * @param $flags Integer: bitwise combination of the following flags:
  *     self::FILES_ONLY     Mark file as existing only if it is a file (not directory)
  * @return array|bool Either array of files and existence flags, or false
  */
 public function fileExistsBatch($files, $flags = 0)
 {
     $result = array();
     foreach ($files as $key => $file) {
         if (self::isVirtualUrl($file)) {
             $file = $this->resolveVirtualUrl($file);
         }
         if (FileBackend::isStoragePath($file)) {
             $result[$key] = $this->backend->fileExists(array('src' => $file));
         } else {
             if ($flags & self::FILES_ONLY) {
                 $result[$key] = is_file($file);
                 // FS only
             } else {
                 $result[$key] = file_exists($file);
                 // FS only
             }
         }
     }
     return $result;
 }
コード例 #6
0
 /**
  * @dataProvider provider_testIsStoragePath
  */
 public function testIsStoragePath($path, $isStorePath)
 {
     $this->assertEquals($isStorePath, FileBackend::isStoragePath($path), "FileBackend::isStoragePath on path '{$path}'");
 }
コード例 #7
0
ファイル: LocalFile.php プロジェクト: spring/spring-website
 /**
  * Upload a file and record it in the DB
  * @param string $srcPath Source storage path, virtual URL, or filesystem path
  * @param string $comment Upload description
  * @param string $pageText Text to use for the new description page,
  *   if a new description page is created
  * @param int|bool $flags Flags for publish()
  * @param array|bool $props File properties, if known. This can be used to
  *   reduce the upload time when uploading virtual URLs for which the file
  *   info is already known
  * @param string|bool $timestamp Timestamp for img_timestamp, or false to use the
  *   current time
  * @param User|null $user User object or null to use $wgUser
  *
  * @return FileRepoStatus object. On success, the value member contains the
  *     archive name, or an empty string if it was a new file.
  */
 function upload($srcPath, $comment, $pageText, $flags = 0, $props = false, $timestamp = false, $user = null)
 {
     global $wgContLang;
     if ($this->getRepo()->getReadOnlyReason() !== false) {
         return $this->readOnlyFatalStatus();
     }
     if (!$props) {
         wfProfileIn(__METHOD__ . '-getProps');
         if ($this->repo->isVirtualUrl($srcPath) || FileBackend::isStoragePath($srcPath)) {
             $props = $this->repo->getFileProps($srcPath);
         } else {
             $props = FSFile::getPropsFromPath($srcPath);
         }
         wfProfileOut(__METHOD__ . '-getProps');
     }
     $options = array();
     $handler = MediaHandler::getHandler($props['mime']);
     if ($handler) {
         $options['headers'] = $handler->getStreamHeaders($props['metadata']);
     } else {
         $options['headers'] = array();
     }
     // Trim spaces on user supplied text
     $comment = trim($comment);
     // truncate nicely or the DB will do it for us
     // non-nicely (dangling multi-byte chars, non-truncated version in cache).
     $comment = $wgContLang->truncate($comment, 255);
     $this->lock();
     // begin
     $status = $this->publish($srcPath, $flags, $options);
     if ($status->successCount > 0) {
         # Essentially we are displacing any existing current file and saving
         # a new current file at the old location. If just the first succeeded,
         # we still need to displace the current DB entry and put in a new one.
         if (!$this->recordUpload2($status->value, $comment, $pageText, $props, $timestamp, $user)) {
             $status->fatal('filenotfound', $srcPath);
         }
     }
     $this->unlock();
     // done
     return $status;
 }
コード例 #8
0
 /**
  * Initialize the path information
  * @param string $name the desired destination name
  * @param string $tempPath the temporary path
  * @param int $fileSize the file size
  * @param bool $removeTempFile (false) remove the temporary file?
  * @throws MWException
  */
 public function initializePathInfo($name, $tempPath, $fileSize, $removeTempFile = false)
 {
     $this->mDesiredDestName = $name;
     if (FileBackend::isStoragePath($tempPath)) {
         throw new MWException(__METHOD__ . " given storage path `{$tempPath}`.");
     }
     $this->mTempPath = $tempPath;
     $this->mFileSize = $fileSize;
     $this->mRemoveTempFile = $removeTempFile;
 }
コード例 #9
0
ファイル: ForeignAPIRepo.php プロジェクト: paladox/mediawiki
 /**
  * @param array $files
  * @return array
  */
 function fileExistsBatch(array $files)
 {
     $results = [];
     foreach ($files as $k => $f) {
         if (isset($this->mFileExists[$f])) {
             $results[$k] = $this->mFileExists[$f];
             unset($files[$k]);
         } elseif (self::isVirtualUrl($f)) {
             # @todo FIXME: We need to be able to handle virtual
             # URLs better, at least when we know they refer to the
             # same repo.
             $results[$k] = false;
             unset($files[$k]);
         } elseif (FileBackend::isStoragePath($f)) {
             $results[$k] = false;
             unset($files[$k]);
             wfWarn("Got mwstore:// path '{$f}'.");
         }
     }
     $data = $this->fetchImageQuery(['titles' => implode($files, '|'), 'prop' => 'imageinfo']);
     if (isset($data['query']['pages'])) {
         # First, get results from the query. Note we only care whether the image exists,
         # not whether it has a description page.
         foreach ($data['query']['pages'] as $p) {
             $this->mFileExists[$p['title']] = $p['imagerepository'] !== '';
         }
         # Second, copy the results to any redirects that were queried
         if (isset($data['query']['redirects'])) {
             foreach ($data['query']['redirects'] as $r) {
                 $this->mFileExists[$r['from']] = $this->mFileExists[$r['to']];
             }
         }
         # Third, copy the results to any non-normalized titles that were queried
         if (isset($data['query']['normalized'])) {
             foreach ($data['query']['normalized'] as $n) {
                 $this->mFileExists[$n['from']] = $this->mFileExists[$n['to']];
             }
         }
         # Finally, copy the results to the output
         foreach ($files as $key => $file) {
             $results[$key] = $this->mFileExists[$file];
         }
     }
     return $results;
 }
コード例 #10
0
ファイル: FileRepo.php プロジェクト: seedbank/old-repo
 /**
  * Publish a batch of files
  *
  * @param $triplets Array: (source, dest, archive) triplets as per publish()
  * @param $flags Integer: bitfield, may be FileRepo::DELETE_SOURCE to indicate
  *        that the source files should be deleted if possible
  * @throws MWException
  * @return FileRepoStatus
  */
 public function publishBatch(array $triplets, $flags = 0)
 {
     $this->assertWritableRepo();
     // fail out if read-only
     $backend = $this->backend;
     // convenience
     // Try creating directories
     $status = $this->initZones('public');
     if (!$status->isOK()) {
         return $status;
     }
     $status = $this->newGood(array());
     $operations = array();
     $sourceFSFilesToDelete = array();
     // cleanup for disk source files
     // Validate each triplet and get the store operation...
     foreach ($triplets as $i => $triplet) {
         list($srcPath, $dstRel, $archiveRel) = $triplet;
         // Resolve source to a storage path if virtual
         $srcPath = $this->resolveToStoragePath($srcPath);
         if (!$this->validateFilename($dstRel)) {
             throw new MWException('Validation error in $dstRel');
         }
         if (!$this->validateFilename($archiveRel)) {
             throw new MWException('Validation error in $archiveRel');
         }
         $publicRoot = $this->getZonePath('public');
         $dstPath = "{$publicRoot}/{$dstRel}";
         $archivePath = "{$publicRoot}/{$archiveRel}";
         $dstDir = dirname($dstPath);
         $archiveDir = dirname($archivePath);
         // Abort immediately on directory creation errors since they're likely to be repetitive
         if (!$this->initDirectory($dstDir)->isOK()) {
             return $this->newFatal('directorycreateerror', $dstDir);
         }
         if (!$this->initDirectory($archiveDir)->isOK()) {
             return $this->newFatal('directorycreateerror', $archiveDir);
         }
         // Archive destination file if it exists
         if ($backend->fileExists(array('src' => $dstPath))) {
             // Check if the archive file exists
             // This is a sanity check to avoid data loss. In UNIX, the rename primitive
             // unlinks the destination file if it exists. DB-based synchronisation in
             // publishBatch's caller should prevent races. In Windows there's no
             // problem because the rename primitive fails if the destination exists.
             if ($backend->fileExists(array('src' => $archivePath))) {
                 $operations[] = array('op' => 'null');
                 continue;
             } else {
                 $operations[] = array('op' => 'move', 'src' => $dstPath, 'dst' => $archivePath);
             }
             $status->value[$i] = 'archived';
         } else {
             $status->value[$i] = 'new';
         }
         // Copy (or move) the source file to the destination
         if (FileBackend::isStoragePath($srcPath)) {
             if ($flags & self::DELETE_SOURCE) {
                 $operations[] = array('op' => 'move', 'src' => $srcPath, 'dst' => $dstPath);
             } else {
                 $operations[] = array('op' => 'copy', 'src' => $srcPath, 'dst' => $dstPath);
             }
         } else {
             // FS source path
             $operations[] = array('op' => 'store', 'src' => $srcPath, 'dst' => $dstPath);
             if ($flags & self::DELETE_SOURCE) {
                 $sourceFSFilesToDelete[] = $srcPath;
             }
         }
     }
     // Execute the operations for each triplet
     $opts = array('force' => true);
     $status->merge($backend->doOperations($operations, $opts));
     // Cleanup for disk source files...
     foreach ($sourceFSFilesToDelete as $file) {
         wfSuppressWarnings();
         unlink($file);
         // FS cleanup
         wfRestoreWarnings();
     }
     return $status;
 }
コード例 #11
0
ファイル: FileRepo.php プロジェクト: whysasse/kmwiki
 /**
  * Publish a batch of files
  *
  * @param array $ntuples (source, dest, archive) triplets or
  *   (source, dest, archive, options) 4-tuples as per publish().
  * @param int $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
  *   that the source files should be deleted if possible
  * @throws MWException
  * @return FileRepoStatus
  */
 public function publishBatch(array $ntuples, $flags = 0)
 {
     $this->assertWritableRepo();
     // fail out if read-only
     $backend = $this->backend;
     // convenience
     // Try creating directories
     $status = $this->initZones('public');
     if (!$status->isOK()) {
         return $status;
     }
     $status = $this->newGood(array());
     $operations = array();
     $sourceFSFilesToDelete = array();
     // cleanup for disk source files
     // Validate each triplet and get the store operation...
     foreach ($ntuples as $ntuple) {
         list($srcPath, $dstRel, $archiveRel) = $ntuple;
         $options = isset($ntuple[3]) ? $ntuple[3] : array();
         // Resolve source to a storage path if virtual
         $srcPath = $this->resolveToStoragePath($srcPath);
         if (!$this->validateFilename($dstRel)) {
             throw new MWException('Validation error in $dstRel');
         }
         if (!$this->validateFilename($archiveRel)) {
             throw new MWException('Validation error in $archiveRel');
         }
         $publicRoot = $this->getZonePath('public');
         $dstPath = "{$publicRoot}/{$dstRel}";
         $archivePath = "{$publicRoot}/{$archiveRel}";
         $dstDir = dirname($dstPath);
         $archiveDir = dirname($archivePath);
         // Abort immediately on directory creation errors since they're likely to be repetitive
         if (!$this->initDirectory($dstDir)->isOK()) {
             return $this->newFatal('directorycreateerror', $dstDir);
         }
         if (!$this->initDirectory($archiveDir)->isOK()) {
             return $this->newFatal('directorycreateerror', $archiveDir);
         }
         // Set any desired headers to be use in GET/HEAD responses
         $headers = isset($options['headers']) ? $options['headers'] : array();
         // Archive destination file if it exists.
         // This will check if the archive file also exists and fail if does.
         // This is a sanity check to avoid data loss. On Windows and Linux,
         // copy() will overwrite, so the existence check is vulnerable to
         // race conditions unless a functioning LockManager is used.
         // LocalFile also uses SELECT FOR UPDATE for synchronization.
         $operations[] = array('op' => 'copy', 'src' => $dstPath, 'dst' => $archivePath, 'ignoreMissingSource' => true);
         // Copy (or move) the source file to the destination
         if (FileBackend::isStoragePath($srcPath)) {
             if ($flags & self::DELETE_SOURCE) {
                 $operations[] = array('op' => 'move', 'src' => $srcPath, 'dst' => $dstPath, 'overwrite' => true, 'headers' => $headers);
             } else {
                 $operations[] = array('op' => 'copy', 'src' => $srcPath, 'dst' => $dstPath, 'overwrite' => true, 'headers' => $headers);
             }
         } else {
             // FS source path
             $operations[] = array('op' => 'store', 'src' => $srcPath, 'dst' => $dstPath, 'overwrite' => true, 'headers' => $headers);
             if ($flags & self::DELETE_SOURCE) {
                 $sourceFSFilesToDelete[] = $srcPath;
             }
         }
     }
     // Execute the operations for each triplet
     $status->merge($backend->doOperations($operations));
     // Find out which files were archived...
     foreach ($ntuples as $i => $ntuple) {
         list(, , $archiveRel) = $ntuple;
         $archivePath = $this->getZonePath('public') . "/{$archiveRel}";
         if ($this->fileExists($archivePath)) {
             $status->value[$i] = 'archived';
         } else {
             $status->value[$i] = 'new';
         }
     }
     // Cleanup for disk source files...
     foreach ($sourceFSFilesToDelete as $file) {
         wfSuppressWarnings();
         unlink($file);
         // FS cleanup
         wfRestoreWarnings();
     }
     return $status;
 }
コード例 #12
0
 /**
  * Stream the file if there were no errors
  *
  * @param array $headers Additional HTTP headers to send on success
  * @return Status
  * @since 1.27
  */
 public function streamFileWithStatus($headers = [])
 {
     if (!$this->path) {
         return Status::newFatal('backend-fail-stream', '<no path>');
     } elseif (FileBackend::isStoragePath($this->path)) {
         $be = $this->file->getRepo()->getBackend();
         return $be->streamFile(['src' => $this->path, 'headers' => $headers]);
     } else {
         // FS-file
         $success = StreamFile::stream($this->getLocalCopyPath(), $headers);
         return $success ? Status::newGood() : Status::newFatal('backend-fail-stream', $this->path);
     }
 }
コード例 #13
0
	/**
	 * Stream the file if there were no errors
	 *
	 * @param array $headers Additional HTTP headers to send on success
	 * @return Bool success
	 */
	public function streamFile( $headers = array() ) {
		if ( !$this->path ) {
			return false;
		} elseif ( FileBackend::isStoragePath( $this->path ) ) {
			$be = $this->file->getRepo()->getBackend();
			return $be->streamFile( array( 'src' => $this->path, 'headers' => $headers ) )->isOK();
		} else { // FS-file
			return StreamFile::stream( $this->getLocalCopyPath(), $headers );
		}
	}
コード例 #14
0
/**
 * Make directory, and make all parent directories if they don't exist
 *
 * @param $dir String: full path to directory to create
 * @param $mode Integer: chmod value to use, default is $wgDirectoryMode
 * @param $caller String: optional caller param for debugging.
 * @throws MWException
 * @return bool
 */
function wfMkdirParents($dir, $mode = null, $caller = null)
{
    global $wgDirectoryMode;
    if (FileBackend::isStoragePath($dir)) {
        // sanity
        throw new MWException(__FUNCTION__ . " given storage path '{$dir}'.");
    }
    if (!is_null($caller)) {
        wfDebug("{$caller}: called wfMkdirParents({$dir})\n");
    }
    if (strval($dir) === '' || file_exists($dir)) {
        return true;
    }
    $dir = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $dir);
    if (is_null($mode)) {
        $mode = $wgDirectoryMode;
    }
    // Turn off the normal warning, we're doing our own below
    wfSuppressWarnings();
    $ok = mkdir($dir, $mode, true);
    // PHP5 <3
    wfRestoreWarnings();
    if (!$ok) {
        // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
        trigger_error(sprintf("%s: failed to mkdir \"%s\" mode 0%o", __FUNCTION__, $dir, $mode), E_USER_WARNING);
    }
    return $ok;
}
コード例 #15
0
ファイル: ForeignAPIRepo.php プロジェクト: mangowi/mediawiki
 /**
  * @param $files array
  * @return array
  */
 function fileExistsBatch(array $files)
 {
     $results = array();
     foreach ($files as $k => $f) {
         if (isset($this->mFileExists[$k])) {
             $results[$k] = true;
             unset($files[$k]);
         } elseif (self::isVirtualUrl($f)) {
             # @todo FIXME: We need to be able to handle virtual
             # URLs better, at least when we know they refer to the
             # same repo.
             $results[$k] = false;
             unset($files[$k]);
         } elseif (FileBackend::isStoragePath($f)) {
             $results[$k] = false;
             unset($files[$k]);
             wfWarn("Got mwstore:// path '{$f}'.");
         }
     }
     $data = $this->fetchImageQuery(array('titles' => implode($files, '|'), 'prop' => 'imageinfo'));
     if (isset($data['query']['pages'])) {
         $i = 0;
         foreach ($files as $key => $file) {
             $results[$key] = $this->mFileExists[$key] = !isset($data['query']['pages'][$i]['missing']);
             $i++;
         }
     }
     return $results;
 }
コード例 #16
0
ファイル: GlobalFunctions.php プロジェクト: D66Ha/mediawiki
/**
 * Make directory, and make all parent directories if they don't exist
 *
 * @param string $dir Full path to directory to create
 * @param int $mode Chmod value to use, default is $wgDirectoryMode
 * @param string $caller Optional caller param for debugging.
 * @throws MWException
 * @return bool
 */
function wfMkdirParents($dir, $mode = null, $caller = null)
{
    global $wgDirectoryMode;
    if (FileBackend::isStoragePath($dir)) {
        // sanity
        throw new MWException(__FUNCTION__ . " given storage path '{$dir}'.");
    }
    if (!is_null($caller)) {
        wfDebug("{$caller}: called wfMkdirParents({$dir})\n");
    }
    if (strval($dir) === '' || is_dir($dir)) {
        return true;
    }
    $dir = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $dir);
    if (is_null($mode)) {
        $mode = $wgDirectoryMode;
    }
    // Turn off the normal warning, we're doing our own below
    MediaWiki\suppressWarnings();
    $ok = mkdir($dir, $mode, true);
    // PHP5 <3
    MediaWiki\restoreWarnings();
    if (!$ok) {
        //directory may have been created on another request since we last checked
        if (is_dir($dir)) {
            return true;
        }
        // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
        wfLogWarning(sprintf("failed to mkdir \"%s\" mode 0%o", $dir, $mode));
    }
    return $ok;
}
コード例 #17
0
 /**
  * Normalize a string if it is a valid storage path
  *
  * @param $path string
  * @return string
  */
 protected static function normalizeIfValidStoragePath($path)
 {
     if (FileBackend::isStoragePath($path)) {
         $res = FileBackend::normalizeStoragePath($path);
         return $res !== null ? $res : $path;
     }
     return $path;
 }
コード例 #18
0
ファイル: LocalFile.php プロジェクト: paladox/2
 /**
  * Upload a file and record it in the DB
  * @param string $srcPath Source storage path, virtual URL, or filesystem path
  * @param string $comment Upload description
  * @param string $pageText Text to use for the new description page,
  *   if a new description page is created
  * @param int|bool $flags Flags for publish()
  * @param array|bool $props File properties, if known. This can be used to
  *   reduce the upload time when uploading virtual URLs for which the file
  *   info is already known
  * @param string|bool $timestamp Timestamp for img_timestamp, or false to use the
  *   current time
  * @param User|null $user User object or null to use $wgUser
  * @param string[] $tags Change tags to add to the log entry and page revision.
  *   (This doesn't check $user's permissions.)
  * @return FileRepoStatus On success, the value member contains the
  *     archive name, or an empty string if it was a new file.
  */
 function upload($srcPath, $comment, $pageText, $flags = 0, $props = false, $timestamp = false, $user = null, $tags = array())
 {
     global $wgContLang;
     if ($this->getRepo()->getReadOnlyReason() !== false) {
         return $this->readOnlyFatalStatus();
     }
     if (!$props) {
         if ($this->repo->isVirtualUrl($srcPath) || FileBackend::isStoragePath($srcPath)) {
             $props = $this->repo->getFileProps($srcPath);
         } else {
             $props = FSFile::getPropsFromPath($srcPath);
         }
     }
     $options = array();
     $handler = MediaHandler::getHandler($props['mime']);
     if ($handler) {
         $options['headers'] = $handler->getStreamHeaders($props['metadata']);
     } else {
         $options['headers'] = array();
     }
     // Trim spaces on user supplied text
     $comment = trim($comment);
     // Truncate nicely or the DB will do it for us
     // non-nicely (dangling multi-byte chars, non-truncated version in cache).
     $comment = $wgContLang->truncate($comment, 255);
     $this->lock();
     // begin
     $status = $this->publish($srcPath, $flags, $options);
     if ($status->successCount >= 2) {
         // There will be a copy+(one of move,copy,store).
         // The first succeeding does not commit us to updating the DB
         // since it simply copied the current version to a timestamped file name.
         // It is only *preferable* to avoid leaving such files orphaned.
         // Once the second operation goes through, then the current version was
         // updated and we must therefore update the DB too.
         $oldver = $status->value;
         if (!$this->recordUpload2($oldver, $comment, $pageText, $props, $timestamp, $user, $tags)) {
             $status->fatal('filenotfound', $srcPath);
         }
     }
     $this->unlock();
     // done
     return $status;
 }