[ Index ] |
|
Code source de eZ Publish 3.9.0 |
1 <?php 2 // 3 // Definition of eZDBFileHandlerPgsqlBackend class 4 // 5 // Created on: <19-Apr-2006 16:15:17 vs> 6 // 7 // SOFTWARE NAME: eZ publish 8 // SOFTWARE RELEASE: 3.9.0 9 // BUILD VERSION: 17785 10 // COPYRIGHT NOTICE: Copyright (C) 1999-2006 eZ systems AS 11 // SOFTWARE LICENSE: GNU General Public License v2.0 12 // NOTICE: > 13 // This program is free software; you can redistribute it and/or 14 // modify it under the terms of version 2.0 of the GNU General 15 // Public License as published by the Free Software Foundation. 16 // 17 // This program is distributed in the hope that it will be useful, 18 // but WITHOUT ANY WARRANTY; without even the implied warranty of 19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 // GNU General Public License for more details. 21 // 22 // You should have received a copy of version 2.0 of the GNU General 23 // Public License along with this program; if not, write to the Free 24 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 25 // MA 02110-1301, USA. 26 // 27 // 28 29 /*! \file ezdbfilehandlerpgsqlbackend.php 30 */ 31 32 define( 'TABLE_METADATA', 'ezdbfile' ); 33 34 /* 35 CREATE TABLE ezdbfile ( 36 id SERIAL PRIMARY KEY, 37 name VARCHAR(255) NOT NULL UNIQUE, 38 name_hash VARCHAR(34) NOT NULL UNIQUE, 39 datatype VARCHAR(60) NOT NULL DEFAULT 'application/octet-stream', 40 scope VARCHAR(20) NOT NULL DEFAULT 'UNKNOWN', 41 size BIGINT NOT NULL DEFAULT 0, 42 mtime INT NOT NULL DEFAULT 0, 43 lob_id OID NOT NULL 44 ); 45 */ 46 47 require_once ( 'lib/ezutils/classes/ezdebugsetting.php' ); 48 require_once ( 'lib/ezutils/classes/ezdebug.php' ); 49 50 class eZDBFileHandlerPgsqlBackend 51 { 52 function _connect() 53 { 54 if ( !isset( $GLOBALS['eZDBFileHandlerPgsqlBackend_dbparams'] ) ) 55 { 56 $fileINI = eZINI::instance( 'file.ini' ); 57 58 $params['host'] = $fileINI->variable( 'ClusteringSettings', 'DBHost' ); 59 $params['port'] = $fileINI->variable( 'ClusteringSettings', 'DBPort' ); 60 $params['dbname'] = $fileINI->variable( 'ClusteringSettings', 'DBName' ); 61 $params['user'] = $fileINI->variable( 'ClusteringSettings', 'DBUser' ); 62 $params['pass'] = $fileINI->variable( 'ClusteringSettings', 'DBPassword' ); 63 $params['chunk_size'] = $fileINI->variable( 'ClusteringSettings', 'DBChunkSize' ); 64 65 $GLOBALS['eZDBFileHandlerPgsqlBackend_dbparams'] = $params; 66 } 67 else 68 $params = $GLOBALS['eZDBFileHandlerPgsqlBackend_dbparams']; 69 70 $connStr = "host=$params[host] "; 71 $connStr .= "port=$params[port] "; 72 $connStr .= "dbname=$params[dbname] "; 73 $connStr .= "user=$params[user] "; 74 $connStr .= "password=$params[pass]"; 75 if ( !$this->db = pg_connect( $connStr ) ) 76 $this->_die( "Unable to connect to storage server." ); 77 78 $this->dbparams = $params; 79 } 80 81 function _delete( $filePath, $insideOfTransaction = false ) 82 { 83 if ( !$metaData = $this->_fetchMetadata( $filePath ) ) 84 return false; 85 86 $result = true; 87 88 $insideOfTransaction || pg_query( $this->db, 'BEGIN' ); 89 90 if ( !pg_query( "DELETE FROM " . TABLE_METADATA . " WHERE id=" . $metaData['id'] ) ) 91 { 92 eZDebug::writeError( "Failed to delete file metadata: $filePath: " . pg_last_error( $this->db ) ); 93 $result = false; 94 } 95 96 if ( !pg_lo_unlink( $metaData['lob_id'] ) ) 97 { 98 eZDebug::writeError( "Failed to remove large object while deleting file '$filePath': " . pg_last_error( $this->db ) ); 99 $result = false; 100 } 101 102 $insideOfTransaction || pg_query( $this->db, $result ? 'COMMIT' : 'ROLLBACK' ); 103 104 return $result; 105 } 106 107 function _deleteByRegex( $regex ) 108 { 109 $regex = pg_escape_string( $regex ); 110 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name ~ '$regex'"; 111 if ( !$res = pg_query( $this->db, $sql ) ) 112 { 113 eZDebug::writeError( "Failed to delete files by regex: '$regex'" ); 114 return false; 115 } 116 117 if ( !pg_num_rows( $res ) ) 118 { 119 pg_free_result( $res ); 120 return true; 121 } 122 123 while ( $row = pg_fetch_row( $res ) ) 124 { 125 $deleteFilename = $row[0]; 126 $this->_delete( $deleteFilename ); 127 } 128 129 pg_free_result( $res ); 130 return true; 131 } 132 133 function _deleteByWildcard( $wildcard ) 134 { 135 // Convert wildcard to regexp. 136 $regex = '^' . pg_escape_string( $wildcard ) . '$'; 137 138 $regex = str_replace( array( '.' ), 139 array( '\.' ), 140 $regex ); 141 142 $regex = str_replace( array( '?', '*', '{', '}', ',' ), 143 array( '.', '.*', '(', ')', '|' ), 144 $regex ); 145 146 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name ~ '$regex'" ; 147 if ( !$res = pg_query( $this->db, $sql ) ) 148 { 149 eZDebug::writeError( "Failed to delete files by wildcard: '$wildcard'" ); 150 return false; 151 } 152 153 if ( !pg_num_rows( $res ) ) 154 { 155 pg_free_result( $res ); 156 return true; 157 } 158 159 while ( $row = pg_fetch_row( $res ) ) 160 { 161 $deleteFilename = $row[0]; 162 $this->_delete( $deleteFilename ); 163 } 164 165 pg_free_result( $res ); 166 return true; 167 } 168 169 function _deleteByLike( $like ) 170 { 171 $like = pg_escape_string( $like ); 172 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name like '$like'" ; 173 if ( !$res = pg_query( $this->db, $sql ) ) 174 { 175 eZDebug::writeError( "Failed to delete files by like: '$like'" ); 176 return false; 177 } 178 179 if ( !pg_num_rows( $res ) ) 180 { 181 pg_free_result( $res ); 182 return true; 183 } 184 185 while ( $row = pg_fetch_row( $res ) ) 186 { 187 $deleteFilename = $row[0]; 188 $this->_delete( $deleteFilename ); 189 } 190 191 pg_free_result( $res ); 192 return true; 193 } 194 195 function _deleteByDirList( $dirList, $commonPath, $commonSuffix ) 196 { 197 198 foreach ( $dirList as $dirItem ) 199 { 200 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name like '$commonPath/$dirItem/$commonSuffix%'" ; 201 if ( !$res = pg_query( $this->db, $sql ) ) 202 { 203 eZDebug::writeError( "Failed to delete files in dir: '$commonPath/$dirItem/$commonSuffix%'" ); 204 return false; 205 } 206 207 if ( !pg_num_rows( $res ) ) 208 { 209 pg_free_result( $res ); 210 continue; 211 } 212 213 while ( $row = pg_fetch_row( $res ) ) 214 { 215 $deleteFilename = $row[0]; 216 $this->_delete( $deleteFilename ); 217 } 218 219 pg_free_result( $res ); 220 } 221 return true; 222 } 223 224 function _exists( $filePath ) 225 { 226 $filePathHash = md5( $filePath ); 227 $res = pg_query( "SELECT COUNT(*) AS count FROM " . TABLE_METADATA . " WHERE name_hash='$filePathHash'" ); 228 $row = pg_fetch_row( $res ); 229 $count = $row[0]; 230 pg_free_result( $res ); 231 return $count; 232 } 233 234 function __mkdir_p( $dir ) 235 { 236 // create parent directories 237 $dirElements = explode( '/', $dir ); 238 if ( count( $dirElements ) == 0 ) 239 return true; 240 241 $result = true; 242 $currentDir = $dirElements[0]; 243 244 if ( $currentDir != '' && !file_exists( $currentDir ) && !mkdir( $currentDir, '0777' )) 245 return false; 246 247 for ( $i = 1; $i < count( $dirElements ); ++$i ) 248 { 249 $dirElement = $dirElements[$i]; 250 if ( strlen( $dirElement ) == 0 ) 251 continue; 252 253 $currentDir .= '/' . $dirElement; 254 255 if ( !file_exists( $currentDir ) && !mkdir( $currentDir, 0777 ) ) 256 return false; 257 258 $result = true; 259 } 260 261 return $result; 262 } 263 264 function _fetch( $filePath ) 265 { 266 $metaData = $this->_fetchMetadata( $filePath ); 267 if ( !$metaData ) 268 { 269 eZDebug::writeNotice( "File '$filePath' does not exists while trying to fetch." ); 270 return false; 271 } 272 273 // create temporary file 274 $tmpFilePath = $filePath.getmypid().'tmp'; 275 $this->__mkdir_p( dirname( $tmpFilePath ) ); 276 if ( !( $fp = fopen( $tmpFilePath, 'wb' ) ) ) 277 { 278 eZDebug::writeError( "Cannot write to '$tmpFilePath' while fetching file." ); 279 return false; 280 } 281 282 // copy large object contents to the file 283 pg_query( $this->db, "BEGIN" ); 284 $chunkSize = $this->dbparams['chunk_size']; 285 $lobHandle = pg_lo_open( $this->db, $metaData['lob_id'], 'r' ); 286 while ( $chunk = pg_lo_read( $lobHandle, $chunkSize ) ) 287 fwrite( $fp, $chunk ); 288 pg_lo_close( $lobHandle ); 289 pg_query( $this->db, "COMMIT" ); 290 291 // rename temporary file to the target one 292 fclose( $fp ); 293 rename( $tmpFilePath, $filePath ); 294 295 return true; 296 } 297 298 function _fetchContents( $filePath ) 299 { 300 $metaData = $this->_fetchMetadata( $filePath ); 301 if ( !$metaData ) 302 { 303 eZDebug::writeNotice( "File '$filePath' does not exists while trying to fetch its contents." ); 304 return false; 305 } 306 307 // fetch large object contents 308 $contents = ''; 309 $chunkSize = $this->dbparams['chunk_size']; 310 pg_query( $this->db, "BEGIN" ); 311 $lobHandle = pg_lo_open( $this->db, $metaData['lob_id'], 'r' ); 312 while ( $chunk = pg_lo_read( $lobHandle, $chunkSize ) ) 313 $contents .= $chunk; 314 pg_lo_close( $lobHandle ); 315 pg_query( $this->db, "COMMIT" ); 316 317 return $contents; 318 } 319 320 function _fetchMetadata( $filePath ) 321 { 322 $filePathHash = md5( $filePath ); 323 if( !( $res = pg_query( $this->db, "SELECT * FROM " . TABLE_METADATA . " WHERE name_hash='$filePathHash'" ) ) ) 324 { 325 eZDebug::writeError( "Error fetching file metadata: " . pg_last_error( $this->db ) ); 326 return false; 327 } 328 if ( ( $nrows = pg_num_rows( $res ) ) > 1 ) 329 eZDebug::writeError( "Duplicate file '$filePath' found." ); 330 elseif ( $nrows == 0 ) 331 return false; 332 $row = pg_fetch_array( $res, null, PGSQL_ASSOC ); 333 pg_free_result( $res ); 334 335 return $row; 336 } 337 338 function _store( $filePath, $datatype, $scope ) 339 { 340 if ( !is_readable( $filePath ) ) 341 { 342 eZDebug::writeError( "Unable to store file '$filePath' since it is not readable.", 'ezdbfilehandlerpgsqlbackend' ); 343 return; 344 } 345 346 if ( !$fp = @fopen( $filePath, 'rb' ) ) 347 { 348 eZDebug::writeError( "Cannot read '$filePath'.", 'ezdbfilehandlerpgsqlbackend' ); 349 return; 350 } 351 352 // Prepare file metadata for storing. 353 $filePathHash = md5( $filePath ); 354 $filePathEscaped = pg_escape_string( $filePath ); 355 $datatype = pg_escape_string( $datatype ); 356 $scope = pg_escape_string( $scope ); 357 $fileMTime = (int) filemtime( $filePath ); 358 $contentLength = (int) filesize( $filePath ); 359 360 // Start DB transaction. 361 pg_query( $this->db, 'BEGIN' ); 362 363 // Create new large object 364 $lobOid = pg_lo_create( $this->db ); 365 $lobHandle = pg_lo_open( $this->db, $lobOid, 'w'); 366 $chunkSize = $this->dbparams['chunk_size']; 367 while ( !feof( $fp ) ) 368 { 369 $chunk = fread( $fp, $chunkSize ); 370 371 if ( pg_lo_write( $lobHandle, $chunk ) === false ) 372 { 373 eZDebug::writeNotice( "Failed to insert file data chunk while storing. Possible race condition: " . $sql ); 374 pg_query( $this->db, 'ROLLBACK' ); 375 return; 376 } 377 } 378 pg_lo_close( $lobHandle ); 379 fclose( $fp ); 380 381 // Check if a file with the same name already exists in db. 382 if ( $row = $this->_fetchMetadata( $filePath ) ) // if it does 383 { 384 // re-write the file 385 386 if ( pg_lo_unlink( $row['lob_id'] ) === false ) 387 { 388 eZDebug::writeError( "Error removing large object while storing file: " . pg_last_error( $this->db ) ); 389 pg_query( $this->db, 'ROLLBACK' ); 390 return; 391 } 392 393 $sql = "UPDATE " . TABLE_METADATA . " SET "; 394 $sql .= "name='$filePathEscaped', name_hash='$filePathHash', "; 395 $sql .= "datatype='$datatype', scope='$scope', "; 396 $sql .= "size=$contentLength, mtime=$fileMTime, lob_id=$lobOid "; 397 $sql .= "WHERE id=" . $row['id']; 398 } 399 else // else if it doesn't 400 { 401 // create file in db 402 $sql = "INSERT INTO " . TABLE_METADATA . " (name, name_hash, datatype, scope, size, mtime, lob_id) "; 403 $sql .= "VALUES ('$filePathEscaped', '$filePathHash', '$datatype', "; 404 $sql .= "'$scope', '$contentLength', '$fileMTime', $lobOid)"; 405 } 406 407 if ( !pg_query( $this->db, $sql ) ) 408 { 409 eZDebug::writeError( "Error storing file '$filePath': " . pg_last_error( $this->db ), 'ezdbfilehandlerpgsqlbackend' ); 410 pg_query( $this->db, 'ROLLBACK'); 411 return; 412 } 413 414 // Commit DB transaction. 415 pg_query( $this->db, 'COMMIT'); 416 } 417 418 function _storeContents( $filePath, $contents, $scope, $datatype ) 419 { 420 // Mostly cut&pasted from _store(). 421 422 // Prepare file metadata for storing. 423 $filePathHash = md5( $filePath ); 424 $filePathEscaped = pg_escape_string( $filePath ); 425 $datatype = pg_escape_string( $datatype ); 426 $scope = pg_escape_string( $scope ); 427 $fileMTime = time(); 428 $contentLength = strlen( $contents ); 429 430 // Start DB transaction. 431 pg_query( $this->db, 'BEGIN' ); 432 433 // Create new large object 434 $lobOid = pg_lo_create( $this->db ); 435 $lobHandle = pg_lo_open( $this->db, $lobOid, 'w'); 436 $chunkSize = $this->dbparams['chunk_size']; 437 for ( $pos = 0; $pos < $contentLength; $pos += $chunkSize ) 438 { 439 $chunk = substr( $contents, $pos, $chunkSize ); 440 441 if ( pg_lo_write( $lobHandle, $chunk ) === false ) 442 { 443 eZDebug::writeNotice( "Failed to insert file data chunk while storing contents. Possible race condition: " . $sql ); 444 pg_query( $this->db, 'ROLLBACK' ); 445 return; 446 } 447 } 448 pg_lo_close( $lobHandle ); 449 450 // If a file with the same name already exists in db. 451 if ( $row = $this->_fetchMetadata( $filePath ) ) // if it does 452 { 453 // re-write the file 454 455 if ( pg_lo_unlink( $row['lob_id'] ) === false ) 456 { 457 eZDebug::writeError( "Error removing large object while storing file contents: " . pg_last_error( $this->db ) ); 458 pg_query( $this->db, 'ROLLBACK' ); 459 return; 460 } 461 462 $sql = "UPDATE " . TABLE_METADATA . " SET "; 463 $sql .= "name='$filePathEscaped', name_hash='$filePathHash', "; 464 $sql .= "datatype='$datatype', scope='$scope', "; 465 $sql .= "size=$contentLength, mtime=$fileMTime, lob_id=$lobOid "; 466 $sql .= "WHERE id=" . $row['id']; 467 } 468 else // else if it doesn't 469 { 470 // create file in db 471 $sql = "INSERT INTO " . TABLE_METADATA . " (name, name_hash, datatype, scope, size, mtime, lob_id) "; 472 $sql .= "VALUES ('$filePathEscaped', '$filePathHash', '$datatype', "; 473 $sql .= "'$scope', '$contentLength', '$fileMTime', $lobOid)"; 474 } 475 476 if ( !pg_query( $this->db, $sql ) ) 477 { 478 eZDebug::writeError( $sql, "Error storing file '$filePath' contents: " . 479 pg_last_error( $this->db ), 'ezdbfilehandlerpgsqlbackend' ); 480 pg_query( $this->db, 'ROLLBACK'); 481 return; 482 } 483 484 // Commit DB transaction. 485 pg_query( $this->db, 'COMMIT'); 486 } 487 488 function _copy( $srcFilePath, $dstFilePath ) 489 { 490 // fetch source file metadata 491 $srcMetadata = $this->_fetchMetadata( $srcFilePath ); 492 if ( !$srcMetadata ) // if source file does not exist then do nothing. 493 return false; 494 495 pg_query( $this->db, 'BEGIN' ); 496 497 // Delete destination file if exists. 498 // NOTE: check for race conditions and deadlocks here. 499 if ( $this->_exists( $dstFilePath ) ) 500 $this->_delete( $dstFilePath, true ); 501 502 // Copy file data. 503 $dstLobOid = pg_lo_create( $this->db ); 504 $dstLobHandle = pg_lo_open( $this->db, $dstLobOid, 'w'); 505 $srcLobHandle = pg_lo_open( $this->db, $srcMetadata['lob_id'], 'r' ); 506 $chunkSize = $this->dbparams['chunk_size']; 507 while ( $chunk = pg_lo_read( $srcLobHandle, $chunkSize ) ) 508 { 509 if ( pg_lo_write( $dstLobHandle, $chunk ) === false ) 510 { 511 eZDebug::writeError( "Failed to write data chunk while copying file '$srcFilePath': " . 512 pg_last_error( $this->db ), 'ezdbfilehandlerpgsqlbackend' ); 513 pg_lo_close( $srcLobHandle ); 514 pg_lo_close( $dstLobHandle ); 515 pg_query( $this->db, 'ROLLBACK' ); 516 return false; 517 } 518 } 519 pg_lo_close( $srcLobHandle ); 520 pg_lo_close( $dstLobHandle ); 521 522 // Copy file metadata. 523 $sql = "INSERT INTO " . TABLE_METADATA . " (name, name_hash, datatype, scope, size, mtime, lob_id) VALUES"; 524 $sql .= sprintf( "('%s', '%s', '%s', '%s', %d, %d, %d)", 525 526 pg_escape_string( $dstFilePath ), md5( $dstFilePath ), 527 $srcMetadata['datatype'], $srcMetadata['scope'], $srcMetadata['size'], $srcMetadata['mtime'], 528 $dstLobOid ); 529 if ( !$res = pg_query( $this->db, $sql ) ) 530 { 531 eZDebug::writeError( $srcFilePath, "Failed to insert file metadata on copying." ); 532 pg_query( $this->db, 'ROLLBACK' ); 533 return false; 534 } 535 536 pg_query( $this->db, 'COMMIT' ); 537 538 return true; 539 } 540 541 function _linkCopy( $srcPath, $dstPath ) 542 { 543 return $this->_copy( $srcPath, $dstPath ); 544 } 545 546 function _rename( $srcFilePath, $dstFilePath ) 547 { 548 // fetch destination file metadata 549 550 pg_query( $this->db, 'BEGIN' ); 551 552 // check if source file exists 553 $srcMetadata = $this->_fetchMetadata( $srcFilePath ); 554 if ( !$srcMetadata ) 555 { 556 // if doesn't then do nothing 557 pg_query( $this->db, 'ROLLBACK' ); // nothing to rollback, actually 558 eZDebug::writeWarning( "File '$srcFilePath' to rename does not exist", 559 'ezdbfilehandlerpgsqlbackend' ); 560 return false; 561 } 562 563 // delete destination file if exists 564 $dstMetadata = $this->_fetchMetadata( $dstFilePath ); 565 if ( $dstMetadata ) // if destination file exists 566 $this->_delete( $dstFilePath, true ); 567 568 // update source file metadata 569 $sql = sprintf( "UPDATE %s SET name='%s', name_hash='%s' WHERE id=%d", 570 TABLE_METADATA, 571 pg_escape_string( $dstFilePath ), md5( $dstFilePath ), 572 $srcMetadata['id'] ); 573 574 if ( !pg_query( $this->db, $sql ) ) 575 { 576 eZDebug::writeError( "Error renaming file '$srcFilePath': " . 577 pg_last_error( $this->db ), 'ezdbfilehandlerpgsqlbackend' ); 578 pg_query( $this->db, 'ROLLBACK'); 579 return false; 580 } 581 582 pg_query( $this->db, 'COMMIT' ); 583 return true; 584 } 585 586 function _passThrough( $filePath ) 587 { 588 $metaData = $this->_fetchMetadata( $filePath ); 589 if ( !$metaData ) 590 return false; 591 592 pg_query( $this->db, "BEGIN" ); 593 $lobHandle = pg_lo_open( $this->db, $metaData['lob_id'], 'r' ); 594 $chunkSize = $this->dbparams['chunk_size']; 595 while ( $chunk = pg_lo_read( $lobHandle, $chunkSize ) ) 596 echo $chunk; 597 pg_lo_close( $lobHandle ); 598 pg_query( $this->db, "COMMIT" ); 599 600 return true; 601 } 602 603 function _getFileList( $skipBinaryFiles, $skipImages ) 604 { 605 $query = 'SELECT name FROM ' . TABLE_METADATA; 606 607 // omit some file types if needed 608 $filters = array(); 609 if ( $skipBinaryFiles ) 610 $filters[] = "'binaryfile'"; 611 if ( $skipImages ) 612 $filters[] = "'image'"; 613 if ( $filters ) 614 $query .= ' WHERE scope NOT IN (' . join( ', ', $filters ) . ')'; 615 616 $rslt = pg_query( $this->db, $query ); 617 if ( !$rslt ) 618 { 619 eZDebug::writeError( pg_last_error( $this->db ) ); 620 return false; 621 } 622 623 $filePathList = array(); 624 while ( $row = pg_fetch_row( $rslt ) ) 625 $filePathList[] = $row[0]; 626 627 pg_free_result( $rslt ); 628 629 return $filePathList; 630 } 631 632 function _die( $msg, $sql = null ) 633 { 634 eZDebug::writeError( $sql, "$msg: " . pg_last_error( $this->db ) ); 635 636 if( @include_once( '../bt.php' ) ) 637 { 638 bt(); 639 die( $msg ); 640 } 641 } 642 643 var $db = null; 644 } 645 646 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Feb 24 10:30:04 2007 | par Balluche grâce à PHPXref 0.7 |