[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Temporary storage for uploaded files. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup Upload 22 */ 23 24 /** 25 * UploadStash is intended to accomplish a few things: 26 * - Enable applications to temporarily stash files without publishing them to 27 * the wiki. 28 * - Several parts of MediaWiki do this in similar ways: UploadBase, 29 * UploadWizard, and FirefoggChunkedExtension. 30 * And there are several that reimplement stashing from scratch, in 31 * idiosyncratic ways. The idea is to unify them all here. 32 * Mostly all of them are the same except for storing some custom fields, 33 * which we subsume into the data array. 34 * - Enable applications to find said files later, as long as the db table or 35 * temp files haven't been purged. 36 * - Enable the uploading user (and *ONLY* the uploading user) to access said 37 * files, and thumbnails of said files, via a URL. We accomplish this using 38 * a database table, with ownership checking as you might expect. See 39 * SpecialUploadStash, which implements a web interface to some files stored 40 * this way. 41 * 42 * UploadStash right now is *mostly* intended to show you one user's slice of 43 * the entire stash. The user parameter is only optional because there are few 44 * cases where we clean out the stash from an automated script. In the future we 45 * might refactor this. 46 * 47 * UploadStash represents the entire stash of temporary files. 48 * UploadStashFile is a filestore for the actual physical disk files. 49 * UploadFromStash extends UploadBase, and represents a single stashed file as 50 * it is moved from the stash to the regular file repository 51 * 52 * @ingroup Upload 53 */ 54 class UploadStash { 55 // Format of the key for files -- has to be suitable as a filename itself (e.g. ab12cd34ef.jpg) 56 const KEY_FORMAT_REGEX = '/^[\w-\.]+\.\w*$/'; 57 58 /** 59 * repository that this uses to store temp files 60 * public because we sometimes need to get a LocalFile within the same repo. 61 * 62 * @var LocalRepo 63 */ 64 public $repo; 65 66 // array of initialized repo objects 67 protected $files = array(); 68 69 // cache of the file metadata that's stored in the database 70 protected $fileMetadata = array(); 71 72 // fileprops cache 73 protected $fileProps = array(); 74 75 // current user 76 protected $user, $userId, $isLoggedIn; 77 78 /** 79 * Represents a temporary filestore, with metadata in the database. 80 * Designed to be compatible with the session stashing code in UploadBase 81 * (should replace it eventually). 82 * 83 * @param FileRepo $repo 84 * @param User $user (default null) 85 */ 86 public function __construct( FileRepo $repo, $user = null ) { 87 // this might change based on wiki's configuration. 88 $this->repo = $repo; 89 90 // if a user was passed, use it. otherwise, attempt to use the global. 91 // this keeps FileRepo from breaking when it creates an UploadStash object 92 if ( $user ) { 93 $this->user = $user; 94 } else { 95 global $wgUser; 96 $this->user = $wgUser; 97 } 98 99 if ( is_object( $this->user ) ) { 100 $this->userId = $this->user->getId(); 101 $this->isLoggedIn = $this->user->isLoggedIn(); 102 } 103 } 104 105 /** 106 * Get a file and its metadata from the stash. 107 * The noAuth param is a bit janky but is required for automated scripts 108 * which clean out the stash. 109 * 110 * @param string $key Key under which file information is stored 111 * @param bool $noAuth (optional) Don't check authentication. Used by maintenance scripts. 112 * @throws UploadStashFileNotFoundException 113 * @throws UploadStashNotLoggedInException 114 * @throws UploadStashWrongOwnerException 115 * @throws UploadStashBadPathException 116 * @return UploadStashFile 117 */ 118 public function getFile( $key, $noAuth = false ) { 119 if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) { 120 throw new UploadStashBadPathException( "key '$key' is not in a proper format" ); 121 } 122 123 if ( !$noAuth && !$this->isLoggedIn ) { 124 throw new UploadStashNotLoggedInException( __METHOD__ . 125 ' No user is logged in, files must belong to users' ); 126 } 127 128 if ( !isset( $this->fileMetadata[$key] ) ) { 129 if ( !$this->fetchFileMetadata( $key ) ) { 130 // If nothing was received, it's likely due to replication lag. 131 // Check the master to see if the record is there. 132 $this->fetchFileMetadata( $key, DB_MASTER ); 133 } 134 135 if ( !isset( $this->fileMetadata[$key] ) ) { 136 throw new UploadStashFileNotFoundException( "key '$key' not found in stash" ); 137 } 138 139 // create $this->files[$key] 140 $this->initFile( $key ); 141 142 // fetch fileprops 143 if ( strlen( $this->fileMetadata[$key]['us_props'] ) ) { 144 $this->fileProps[$key] = unserialize( $this->fileMetadata[$key]['us_props'] ); 145 } else { // b/c for rows with no us_props 146 wfDebug( __METHOD__ . " fetched props for $key from file\n" ); 147 $path = $this->fileMetadata[$key]['us_path']; 148 $this->fileProps[$key] = $this->repo->getFileProps( $path ); 149 } 150 } 151 152 if ( !$this->files[$key]->exists() ) { 153 wfDebug( __METHOD__ . " tried to get file at $key, but it doesn't exist\n" ); 154 throw new UploadStashBadPathException( "path doesn't exist" ); 155 } 156 157 if ( !$noAuth ) { 158 if ( $this->fileMetadata[$key]['us_user'] != $this->userId ) { 159 throw new UploadStashWrongOwnerException( "This file ($key) doesn't " 160 . "belong to the current user." ); 161 } 162 } 163 164 return $this->files[$key]; 165 } 166 167 /** 168 * Getter for file metadata. 169 * 170 * @param string $key Key under which file information is stored 171 * @return array 172 */ 173 public function getMetadata( $key ) { 174 $this->getFile( $key ); 175 176 return $this->fileMetadata[$key]; 177 } 178 179 /** 180 * Getter for fileProps 181 * 182 * @param string $key Key under which file information is stored 183 * @return array 184 */ 185 public function getFileProps( $key ) { 186 $this->getFile( $key ); 187 188 return $this->fileProps[$key]; 189 } 190 191 /** 192 * Stash a file in a temp directory and record that we did this in the 193 * database, along with other metadata. 194 * 195 * @param string $path Path to file you want stashed 196 * @param string $sourceType The type of upload that generated this file 197 * (currently, I believe, 'file' or null) 198 * @throws UploadStashBadPathException 199 * @throws UploadStashFileException 200 * @throws UploadStashNotLoggedInException 201 * @return UploadStashFile|null File, or null on failure 202 */ 203 public function stashFile( $path, $sourceType = null ) { 204 if ( !is_file( $path ) ) { 205 wfDebug( __METHOD__ . " tried to stash file at '$path', but it doesn't exist\n" ); 206 throw new UploadStashBadPathException( "path doesn't exist" ); 207 } 208 $fileProps = FSFile::getPropsFromPath( $path ); 209 wfDebug( __METHOD__ . " stashing file at '$path'\n" ); 210 211 // we will be initializing from some tmpnam files that don't have extensions. 212 // most of MediaWiki assumes all uploaded files have good extensions. So, we fix this. 213 $extension = self::getExtensionForPath( $path ); 214 if ( !preg_match( "/\\.\\Q$extension\\E$/", $path ) ) { 215 $pathWithGoodExtension = "$path.$extension"; 216 } else { 217 $pathWithGoodExtension = $path; 218 } 219 220 // If no key was supplied, make one. a mysql insertid would be totally 221 // reasonable here, except that for historical reasons, the key is this 222 // random thing instead. At least it's not guessable. 223 // 224 // Some things that when combined will make a suitably unique key. 225 // see: http://www.jwz.org/doc/mid.html 226 list( $usec, $sec ) = explode( ' ', microtime() ); 227 $usec = substr( $usec, 2 ); 228 $key = wfBaseConvert( $sec . $usec, 10, 36 ) . '.' . 229 wfBaseConvert( mt_rand(), 10, 36 ) . '.' . 230 $this->userId . '.' . 231 $extension; 232 233 $this->fileProps[$key] = $fileProps; 234 235 if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) { 236 throw new UploadStashBadPathException( "key '$key' is not in a proper format" ); 237 } 238 239 wfDebug( __METHOD__ . " key for '$path': $key\n" ); 240 241 // if not already in a temporary area, put it there 242 $storeStatus = $this->repo->storeTemp( basename( $pathWithGoodExtension ), $path ); 243 244 if ( !$storeStatus->isOK() ) { 245 // It is a convention in MediaWiki to only return one error per API 246 // exception, even if multiple errors are available. We use reset() 247 // to pick the "first" thing that was wrong, preferring errors to 248 // warnings. This is a bit lame, as we may have more info in the 249 // $storeStatus and we're throwing it away, but to fix it means 250 // redesigning API errors significantly. 251 // $storeStatus->value just contains the virtual URL (if anything) 252 // which is probably useless to the caller. 253 $error = $storeStatus->getErrorsArray(); 254 $error = reset( $error ); 255 if ( !count( $error ) ) { 256 $error = $storeStatus->getWarningsArray(); 257 $error = reset( $error ); 258 if ( !count( $error ) ) { 259 $error = array( 'unknown', 'no error recorded' ); 260 } 261 } 262 // At this point, $error should contain the single "most important" 263 // error, plus any parameters. 264 $errorMsg = array_shift( $error ); 265 throw new UploadStashFileException( "Error storing file in '$path': " 266 . wfMessage( $errorMsg, $error )->text() ); 267 } 268 $stashPath = $storeStatus->value; 269 270 // fetch the current user ID 271 if ( !$this->isLoggedIn ) { 272 throw new UploadStashNotLoggedInException( __METHOD__ 273 . ' No user is logged in, files must belong to users' ); 274 } 275 276 // insert the file metadata into the db. 277 wfDebug( __METHOD__ . " inserting $stashPath under $key\n" ); 278 $dbw = $this->repo->getMasterDb(); 279 280 $this->fileMetadata[$key] = array( 281 'us_id' => $dbw->nextSequenceValue( 'uploadstash_us_id_seq' ), 282 'us_user' => $this->userId, 283 'us_key' => $key, 284 'us_orig_path' => $path, 285 'us_path' => $stashPath, // virtual URL 286 'us_props' => $dbw->encodeBlob( serialize( $fileProps ) ), 287 'us_size' => $fileProps['size'], 288 'us_sha1' => $fileProps['sha1'], 289 'us_mime' => $fileProps['mime'], 290 'us_media_type' => $fileProps['media_type'], 291 'us_image_width' => $fileProps['width'], 292 'us_image_height' => $fileProps['height'], 293 'us_image_bits' => $fileProps['bits'], 294 'us_source_type' => $sourceType, 295 'us_timestamp' => $dbw->timestamp(), 296 'us_status' => 'finished' 297 ); 298 299 $dbw->insert( 300 'uploadstash', 301 $this->fileMetadata[$key], 302 __METHOD__ 303 ); 304 305 // store the insertid in the class variable so immediate retrieval 306 // (possibly laggy) isn't necesary. 307 $this->fileMetadata[$key]['us_id'] = $dbw->insertId(); 308 309 # create the UploadStashFile object for this file. 310 $this->initFile( $key ); 311 312 return $this->getFile( $key ); 313 } 314 315 /** 316 * Remove all files from the stash. 317 * Does not clean up files in the repo, just the record of them. 318 * 319 * @throws UploadStashNotLoggedInException 320 * @return bool Success 321 */ 322 public function clear() { 323 if ( !$this->isLoggedIn ) { 324 throw new UploadStashNotLoggedInException( __METHOD__ 325 . ' No user is logged in, files must belong to users' ); 326 } 327 328 wfDebug( __METHOD__ . ' clearing all rows for user ' . $this->userId . "\n" ); 329 $dbw = $this->repo->getMasterDb(); 330 $dbw->delete( 331 'uploadstash', 332 array( 'us_user' => $this->userId ), 333 __METHOD__ 334 ); 335 336 # destroy objects. 337 $this->files = array(); 338 $this->fileMetadata = array(); 339 340 return true; 341 } 342 343 /** 344 * Remove a particular file from the stash. Also removes it from the repo. 345 * 346 * @param string $key 347 * @throws UploadStashNoSuchKeyException|UploadStashNotLoggedInException 348 * @throws UploadStashWrongOwnerException 349 * @return bool Success 350 */ 351 public function removeFile( $key ) { 352 if ( !$this->isLoggedIn ) { 353 throw new UploadStashNotLoggedInException( __METHOD__ 354 . ' No user is logged in, files must belong to users' ); 355 } 356 357 $dbw = $this->repo->getMasterDb(); 358 359 // this is a cheap query. it runs on the master so that this function 360 // still works when there's lag. It won't be called all that often. 361 $row = $dbw->selectRow( 362 'uploadstash', 363 'us_user', 364 array( 'us_key' => $key ), 365 __METHOD__ 366 ); 367 368 if ( !$row ) { 369 throw new UploadStashNoSuchKeyException( "No such key ($key), cannot remove" ); 370 } 371 372 if ( $row->us_user != $this->userId ) { 373 throw new UploadStashWrongOwnerException( "Can't delete: " 374 . "the file ($key) doesn't belong to this user." ); 375 } 376 377 return $this->removeFileNoAuth( $key ); 378 } 379 380 /** 381 * Remove a file (see removeFile), but doesn't check ownership first. 382 * 383 * @param string $key 384 * @return bool Success 385 */ 386 public function removeFileNoAuth( $key ) { 387 wfDebug( __METHOD__ . " clearing row $key\n" ); 388 389 // Ensure we have the UploadStashFile loaded for this key 390 $this->getFile( $key, true ); 391 392 $dbw = $this->repo->getMasterDb(); 393 394 $dbw->delete( 395 'uploadstash', 396 array( 'us_key' => $key ), 397 __METHOD__ 398 ); 399 400 /** @todo Look into UnregisteredLocalFile and find out why the rv here is 401 * sometimes wrong (false when file was removed). For now, ignore. 402 */ 403 $this->files[$key]->remove(); 404 405 unset( $this->files[$key] ); 406 unset( $this->fileMetadata[$key] ); 407 408 return true; 409 } 410 411 /** 412 * List all files in the stash. 413 * 414 * @throws UploadStashNotLoggedInException 415 * @return array 416 */ 417 public function listFiles() { 418 if ( !$this->isLoggedIn ) { 419 throw new UploadStashNotLoggedInException( __METHOD__ 420 . ' No user is logged in, files must belong to users' ); 421 } 422 423 $dbr = $this->repo->getSlaveDb(); 424 $res = $dbr->select( 425 'uploadstash', 426 'us_key', 427 array( 'us_user' => $this->userId ), 428 __METHOD__ 429 ); 430 431 if ( !is_object( $res ) || $res->numRows() == 0 ) { 432 // nothing to do. 433 return false; 434 } 435 436 // finish the read before starting writes. 437 $keys = array(); 438 foreach ( $res as $row ) { 439 array_push( $keys, $row->us_key ); 440 } 441 442 return $keys; 443 } 444 445 /** 446 * Find or guess extension -- ensuring that our extension matches our MIME type. 447 * Since these files are constructed from php tempnames they may not start off 448 * with an extension. 449 * XXX this is somewhat redundant with the checks that ApiUpload.php does with incoming 450 * uploads versus the desired filename. Maybe we can get that passed to us... 451 * @param string $path 452 * @throws UploadStashFileException 453 * @return string 454 */ 455 public static function getExtensionForPath( $path ) { 456 global $wgFileBlacklist; 457 // Does this have an extension? 458 $n = strrpos( $path, '.' ); 459 $extension = null; 460 if ( $n !== false ) { 461 $extension = $n ? substr( $path, $n + 1 ) : ''; 462 } else { 463 // If not, assume that it should be related to the MIME type of the original file. 464 $magic = MimeMagic::singleton(); 465 $mimeType = $magic->guessMimeType( $path ); 466 $extensions = explode( ' ', MimeMagic::singleton()->getExtensionsForType( $mimeType ) ); 467 if ( count( $extensions ) ) { 468 $extension = $extensions[0]; 469 } 470 } 471 472 if ( is_null( $extension ) ) { 473 throw new UploadStashFileException( "extension is null" ); 474 } 475 476 $extension = File::normalizeExtension( $extension ); 477 if ( in_array( $extension, $wgFileBlacklist ) ) { 478 // The file should already be checked for being evil. 479 // However, if somehow we got here, we definitely 480 // don't want to give it an extension of .php and 481 // put it in a web accesible directory. 482 return ''; 483 } 484 485 return $extension; 486 } 487 488 /** 489 * Helper function: do the actual database query to fetch file metadata. 490 * 491 * @param string $key 492 * @param int $readFromDB Constant (default: DB_SLAVE) 493 * @return bool 494 */ 495 protected function fetchFileMetadata( $key, $readFromDB = DB_SLAVE ) { 496 // populate $fileMetadata[$key] 497 $dbr = null; 498 if ( $readFromDB === DB_MASTER ) { 499 // sometimes reading from the master is necessary, if there's replication lag. 500 $dbr = $this->repo->getMasterDb(); 501 } else { 502 $dbr = $this->repo->getSlaveDb(); 503 } 504 505 $row = $dbr->selectRow( 506 'uploadstash', 507 '*', 508 array( 'us_key' => $key ), 509 __METHOD__ 510 ); 511 512 if ( !is_object( $row ) ) { 513 // key wasn't present in the database. this will happen sometimes. 514 return false; 515 } 516 517 $this->fileMetadata[$key] = (array)$row; 518 $this->fileMetadata[$key]['us_props'] = $dbr->decodeBlob( $row->us_props ); 519 520 return true; 521 } 522 523 /** 524 * Helper function: Initialize the UploadStashFile for a given file. 525 * 526 * @param string $key Key under which to store the object 527 * @throws UploadStashZeroLengthFileException 528 * @return bool 529 */ 530 protected function initFile( $key ) { 531 $file = new UploadStashFile( $this->repo, $this->fileMetadata[$key]['us_path'], $key ); 532 if ( $file->getSize() === 0 ) { 533 throw new UploadStashZeroLengthFileException( "File is zero length" ); 534 } 535 $this->files[$key] = $file; 536 537 return true; 538 } 539 } 540 541 class UploadStashFile extends UnregisteredLocalFile { 542 private $fileKey; 543 private $urlName; 544 protected $url; 545 546 /** 547 * A LocalFile wrapper around a file that has been temporarily stashed, 548 * so we can do things like create thumbnails for it. Arguably 549 * UnregisteredLocalFile should be handling its own file repo but that 550 * class is a bit retarded currently. 551 * 552 * @param FileRepo $repo Repository where we should find the path 553 * @param string $path Path to file 554 * @param string $key Key to store the path and any stashed data under 555 * @throws UploadStashBadPathException 556 * @throws UploadStashFileNotFoundException 557 */ 558 public function __construct( $repo, $path, $key ) { 559 $this->fileKey = $key; 560 561 // resolve mwrepo:// urls 562 if ( $repo->isVirtualUrl( $path ) ) { 563 $path = $repo->resolveVirtualUrl( $path ); 564 } else { 565 // check if path appears to be sane, no parent traversals, 566 // and is in this repo's temp zone. 567 $repoTempPath = $repo->getZonePath( 'temp' ); 568 if ( ( !$repo->validateFilename( $path ) ) || 569 ( strpos( $path, $repoTempPath ) !== 0 ) 570 ) { 571 wfDebug( "UploadStash: tried to construct an UploadStashFile " 572 . "from a file that should already exist at '$path', but path is not valid\n" ); 573 throw new UploadStashBadPathException( 'path is not valid' ); 574 } 575 576 // check if path exists! and is a plain file. 577 if ( !$repo->fileExists( $path ) ) { 578 wfDebug( "UploadStash: tried to construct an UploadStashFile from " 579 . "a file that should already exist at '$path', but path is not found\n" ); 580 throw new UploadStashFileNotFoundException( 'cannot find path, or not a plain file' ); 581 } 582 } 583 584 parent::__construct( false, $repo, $path, false ); 585 586 $this->name = basename( $this->path ); 587 } 588 589 /** 590 * A method needed by the file transforming and scaling routines in File.php 591 * We do not necessarily care about doing the description at this point 592 * However, we also can't return the empty string, as the rest of MediaWiki 593 * demands this (and calls to imagemagick convert require it to be there) 594 * 595 * @return string Dummy value 596 */ 597 public function getDescriptionUrl() { 598 return $this->getUrl(); 599 } 600 601 /** 602 * Get the path for the thumbnail (actually any transformation of this file) 603 * The actual argument is the result of thumbName although we seem to have 604 * buggy code elsewhere that expects a boolean 'suffix' 605 * 606 * @param string $thumbName Name of thumbnail (e.g. "120px-123456.jpg" ), 607 * or false to just get the path 608 * @return string Path thumbnail should take on filesystem, or containing 609 * directory if thumbname is false 610 */ 611 public function getThumbPath( $thumbName = false ) { 612 $path = dirname( $this->path ); 613 if ( $thumbName !== false ) { 614 $path .= "/$thumbName"; 615 } 616 617 return $path; 618 } 619 620 /** 621 * Return the file/url base name of a thumbnail with the specified parameters. 622 * We override this because we want to use the pretty url name instead of the 623 * ugly file name. 624 * 625 * @param array $params Handler-specific parameters 626 * @param int $flags Bitfield that supports THUMB_* constants 627 * @return string Base name for URL, like '120px-12345.jpg', or null if there is no handler 628 */ 629 function thumbName( $params, $flags = 0 ) { 630 return $this->generateThumbName( $this->getUrlName(), $params ); 631 } 632 633 /** 634 * Helper function -- given a 'subpage', return the local URL, 635 * e.g. /wiki/Special:UploadStash/subpage 636 * @param string $subPage 637 * @return string Local URL for this subpage in the Special:UploadStash space. 638 */ 639 private function getSpecialUrl( $subPage ) { 640 return SpecialPage::getTitleFor( 'UploadStash', $subPage )->getLocalURL(); 641 } 642 643 /** 644 * Get a URL to access the thumbnail 645 * This is required because the model of how files work requires that 646 * the thumbnail urls be predictable. However, in our model the URL is 647 * not based on the filename (that's hidden in the db) 648 * 649 * @param string $thumbName Basename of thumbnail file -- however, we don't 650 * want to use the file exactly 651 * @return string URL to access thumbnail, or URL with partial path 652 */ 653 public function getThumbUrl( $thumbName = false ) { 654 wfDebug( __METHOD__ . " getting for $thumbName \n" ); 655 656 return $this->getSpecialUrl( 'thumb/' . $this->getUrlName() . '/' . $thumbName ); 657 } 658 659 /** 660 * The basename for the URL, which we want to not be related to the filename. 661 * Will also be used as the lookup key for a thumbnail file. 662 * 663 * @return string Base url name, like '120px-123456.jpg' 664 */ 665 public function getUrlName() { 666 if ( !$this->urlName ) { 667 $this->urlName = $this->fileKey; 668 } 669 670 return $this->urlName; 671 } 672 673 /** 674 * Return the URL of the file, if for some reason we wanted to download it 675 * We tend not to do this for the original file, but we do want thumb icons 676 * 677 * @return string Url 678 */ 679 public function getUrl() { 680 if ( !isset( $this->url ) ) { 681 $this->url = $this->getSpecialUrl( 'file/' . $this->getUrlName() ); 682 } 683 684 return $this->url; 685 } 686 687 /** 688 * Parent classes use this method, for no obvious reason, to return the path 689 * (relative to wiki root, I assume). But with this class, the URL is 690 * unrelated to the path. 691 * 692 * @return string Url 693 */ 694 public function getFullUrl() { 695 return $this->getUrl(); 696 } 697 698 /** 699 * Getter for file key (the unique id by which this file's location & 700 * metadata is stored in the db) 701 * 702 * @return string File key 703 */ 704 public function getFileKey() { 705 return $this->fileKey; 706 } 707 708 /** 709 * Remove the associated temporary file 710 * @return status Success 711 */ 712 public function remove() { 713 if ( !$this->repo->fileExists( $this->path ) ) { 714 // Maybe the file's already been removed? This could totally happen in UploadBase. 715 return true; 716 } 717 718 return $this->repo->freeTemp( $this->path ); 719 } 720 721 public function exists() { 722 return $this->repo->fileExists( $this->path ); 723 } 724 } 725 726 class UploadStashException extends MWException { 727 } 728 729 class UploadStashNotAvailableException extends UploadStashException { 730 } 731 732 class UploadStashFileNotFoundException extends UploadStashException { 733 } 734 735 class UploadStashBadPathException extends UploadStashException { 736 } 737 738 class UploadStashFileException extends UploadStashException { 739 } 740 741 class UploadStashZeroLengthFileException extends UploadStashException { 742 } 743 744 class UploadStashNotLoggedInException extends UploadStashException { 745 } 746 747 class UploadStashWrongOwnerException extends UploadStashException { 748 } 749 750 class UploadStashNoSuchKeyException extends UploadStashException { 751 } 752
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |