00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 define( 'TABLE_METADATA', 'ezdbfile' );
00035 define( 'TABLE_DATA', 'ezdbfile_data' );
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 require_once( 'lib/ezutils/classes/ezdebugsetting.php' );
00061 require_once( 'lib/ezutils/classes/ezdebug.php' );
00062
00063 class eZDBFileHandlerMysqlBackend
00064 {
00065 function _connect()
00066 {
00067 if ( !isset( $GLOBALS['eZDBFileHandlerMysqlBackend_dbparams'] ) )
00068 {
00069 $fileINI = eZINI::instance( 'file.ini' );
00070
00071 $params['host'] = $fileINI->variable( 'ClusteringSettings', 'DBHost' );
00072 $params['port'] = $fileINI->variable( 'ClusteringSettings', 'DBPort' );
00073 $params['socket'] = $fileINI->variable( 'ClusteringSettings', 'DBSocket' );
00074 $params['dbname'] = $fileINI->variable( 'ClusteringSettings', 'DBName' );
00075 $params['user'] = $fileINI->variable( 'ClusteringSettings', 'DBUser' );
00076 $params['pass'] = $fileINI->variable( 'ClusteringSettings', 'DBPassword' );
00077 $params['chunk_size'] = $fileINI->variable( 'ClusteringSettings', 'DBChunkSize' );
00078
00079 $GLOBALS['eZDBFileHandlerMysqlBackend_dbparams'] = $params;
00080 }
00081 else
00082 $params = $GLOBALS['eZDBFileHandlerMysqlBackend_dbparams'];
00083
00084 $serverString = $params['host'];
00085 if ( $params['socket'] )
00086 $serverString .= ':' . $params['socket'];
00087 elseif ( $params['port'] )
00088 $serverString .= ':' . $params['port'];
00089
00090 if ( !$this->db = mysql_connect( $serverString, $params['user'], $params['pass'] ) )
00091 $this->_die( "Unable to connect to storage server" );
00092
00093 if ( !mysql_select_db( $params['dbname'], $this->db ) )
00094 $this->_die( "Unable to connect to storage database" );
00095
00096 $this->dbparams = $params;
00097 }
00098
00099 function _copy( $srcFilePath, $dstFilePath )
00100 {
00101
00102 $metaData = $this->_fetchMetadata( $srcFilePath );
00103 if ( !$metaData )
00104 return false;
00105
00106 mysql_query( 'BEGIN', $this->db );
00107
00108 if ( $this->_exists( $dstFilePath ) )
00109 $this->_delete( $dstFilePath, true );
00110
00111 $srcFilePath = mysql_real_escape_string( $srcFilePath );
00112 $dstFilePath = mysql_real_escape_string( $dstFilePath );
00113
00114 $datatype = $metaData['datatype'];
00115 $filePathEscaped = $dstFilePath;
00116 $filePathHash = md5( $filePathEscaped );
00117 $scope = $metaData['scope'];
00118 $contentLength = $metaData['size'];
00119 $fileMTime = $metaData['mtime'];
00120
00121
00122 $sql = "INSERT INTO " . TABLE_METADATA . " (datatype, name, name_hash, scope, size, mtime) VALUES";
00123 $sql .= "('$datatype', '$filePathEscaped', '$filePathHash', '$scope', $contentLength, '$fileMTime')";
00124
00125 if ( !$res = mysql_query( $sql, $this->db ) )
00126 {
00127 eZDebug::writeError( $srcFilPath, "Failed to insert file metadata on copying." );
00128 mysql_query( 'ROLLBACK', $this->db );
00129 return false;
00130 }
00131
00132
00133
00134 $srcFileID = $metaData['id'];
00135 $sql = "SELECT filedata FROM " . TABLE_DATA . " WHERE masterid=$srcFileID";
00136 if ( !$res = mysql_query( $sql, $this->db ) )
00137 {
00138 eZDebug::writeError( $srcFilePath, "Failed to fetch source file data on copying." );
00139 mysql_query( 'ROLLBACK', $this->db );
00140 return false;
00141 }
00142
00143 $dstFileID = mysql_insert_id( $this->db );
00144 while ( $row = mysql_fetch_row( $res ) )
00145 {
00146
00147 $binarydata = mysql_real_escape_string( $row[0] );
00148
00149 $sql = "INSERT INTO " . TABLE_DATA . " (masterid, filedata) VALUES ($dstFileID, '$binarydata')";
00150
00151 if ( !mysql_query( $sql, $this->db ) )
00152 {
00153 eZDebug::writeError( "Failed to insert data row while copying file." );
00154 mysql_query( 'ROLLBACK', $this->db );
00155 mysql_free_result( $res );
00156 return false;
00157 }
00158 }
00159
00160 mysql_free_result( $res );
00161 mysql_query( 'COMMIT', $this->db );
00162
00163 return true;
00164 }
00165
00166 function _delete( $filePath, $insideOfTransaction = false )
00167 {
00168 $filePath = mysql_real_escape_string( $filePath );
00169 $sql = "select * from " . TABLE_METADATA . " where name_hash='" . md5( $filePath ) . "'" ;
00170 if ( !$res = mysql_query( $sql, $this->db ) )
00171 {
00172 eZDebug::writeError( "Failed to retrive file metadata before deletion: $filePath.");
00173 return false;
00174 }
00175
00176 if ( mysql_num_rows( $res ) == 0 )
00177 {
00178 mysql_free_result( $res );
00179 return false;
00180 }
00181
00182 if ( !$insideOfTransaction )
00183 mysql_query( 'BEGIN', $this->db );
00184
00185 $result = true;
00186
00187 while ( $row = mysql_fetch_row( $res ) )
00188 {
00189 $fileID = (int) $row[0];
00190 if ( !mysql_query( "DELETE FROM " . TABLE_DATA . " WHERE masterid=$fileID", $this->db ) )
00191 {
00192 eZDebug::writeError( "Failed to delete file data: $filePath: " . mysql_error( $this->db ) );
00193 $result = false;
00194 break;
00195 }
00196 }
00197
00198 if ( !mysql_query( "DELETE FROM " . TABLE_METADATA . " WHERE id=$fileID", $this->db ) )
00199 {
00200 eZDebug::writeError( "Failed to delete file metadata: $filePath: " . mysql_error( $this->db ) );
00201 $result = false;
00202 }
00203
00204 mysql_free_result( $res );
00205
00206 if ( !$insideOfTransaction )
00207 {
00208 if ( $result )
00209 mysql_query( 'COMMIT', $this->db );
00210 else
00211 mysql_query( 'ROLLBACK', $this->db );
00212 }
00213
00214 return $result;
00215 }
00216
00217 function _deleteByLike( $like )
00218 {
00219 $like = mysql_real_escape_string( $like );
00220 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name like '$like'" ;
00221 if ( !$res = mysql_query( $sql, $this->db ) )
00222 {
00223 eZDebug::writeError( "Failed to delete files by like: '$like'" );
00224 return false;
00225 }
00226
00227 if ( !mysql_num_rows( $res ) )
00228 {
00229 mysql_free_result( $res );
00230 return true;
00231 }
00232
00233 while ( $row = mysql_fetch_row( $res ) )
00234 {
00235 $deleteFilename = $row[0];
00236 $this->_delete( $deleteFilename );
00237 }
00238
00239 mysql_free_result( $res );
00240 return true;
00241 }
00242
00243 function _deleteByRegex( $regex )
00244 {
00245 $regex = mysql_real_escape_string( $regex );
00246 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name REGEXP '$regex'" ;
00247 if ( !$res = mysql_query( $sql, $this->db ) )
00248 {
00249 eZDebug::writeError( "Failed to delete files by regex: '$regex'" );
00250 return false;
00251 }
00252
00253 if ( !mysql_num_rows( $res ) )
00254 {
00255 mysql_free_result( $res );
00256 return true;
00257 }
00258
00259 while ( $row = mysql_fetch_row( $res ) )
00260 {
00261 $deleteFilename = $row[0];
00262 $this->_delete( $deleteFilename );
00263 }
00264
00265 mysql_free_result( $res );
00266 return true;
00267 }
00268
00269 function _deleteByWildcard( $wildcard )
00270 {
00271
00272 $regex = '^' . mysql_real_escape_string( $wildcard ) . '$';
00273
00274 $regex = str_replace( array( '.' ),
00275 array( '\.' ),
00276 $regex );
00277
00278 $regex = str_replace( array( '?', '*', '{', '}', ',' ),
00279 array( '.', '.*', '(', ')', '|' ),
00280 $regex );
00281
00282 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name REGEXP '$regex'" ;
00283 if ( !$res = mysql_query( $sql, $this->db ) )
00284 {
00285 eZDebug::writeError( "Failed to delete files by wildcard: '$wildcard'" );
00286 return false;
00287 }
00288
00289 if ( !mysql_num_rows( $res ) )
00290 {
00291 mysql_free_result( $res );
00292 return true;
00293 }
00294
00295 while ( $row = mysql_fetch_row( $res ) )
00296 {
00297 $deleteFilename = $row[0];
00298 $this->_delete( $deleteFilename );
00299 }
00300
00301 mysql_free_result( $res );
00302 return true;
00303 }
00304
00305 function _deleteByDirList( $dirList, $commonPath, $commonSuffix )
00306 {
00307
00308 foreach ( $dirList as $dirItem )
00309 {
00310 $sql = "SELECT name FROM " . TABLE_METADATA . " WHERE name like '$commonPath/$dirItem/$commonSuffix%'" ;
00311 if ( !$res = mysql_query( $sql, $this->db ) )
00312 {
00313 eZDebug::writeError( "Failed to delete files in dir: '$commonPath/$dirItem/$commonSuffix%'" );
00314 return false;
00315 }
00316
00317 if ( !mysql_num_rows( $res ) )
00318 {
00319 mysql_free_result( $res );
00320 continue;
00321 }
00322
00323 while ( $row = mysql_fetch_row( $res ) )
00324 {
00325 $deleteFilename = $row[0];
00326 $this->_delete( $deleteFilename );
00327 }
00328
00329 mysql_free_result( $res );
00330 }
00331 return true;
00332 }
00333
00334
00335 function _exists( $filePath )
00336 {
00337 $filePath = mysql_real_escape_string( $filePath );
00338 $filePathHash = md5( $filePath );
00339 $rslt = mysql_query( "SELECT COUNT(*) FROM " . TABLE_METADATA . " WHERE name_hash='$filePathHash' ", $this->db );
00340 if ( !$rslt )
00341 {
00342 eZDebug::writeError( "Failed to check file '$filePath' existance: " . mysql_error( $this->db ) );
00343 return false;
00344 }
00345 $row = mysql_fetch_row( $rslt );
00346 mysql_free_result( $rslt );
00347 $rc = (int) $row[0];
00348 return $rc;
00349 }
00350
00351 function __mkdir_p( $dir )
00352 {
00353
00354 $dirElements = explode( '/', $dir );
00355 if ( count( $dirElements ) == 0 )
00356 return true;
00357
00358 $result = true;
00359 $currentDir = $dirElements[0];
00360
00361 if ( $currentDir != '' && !file_exists( $currentDir ) && !mkdir( $currentDir, '0777' ))
00362 return false;
00363
00364 for ( $i = 1; $i < count( $dirElements ); ++$i )
00365 {
00366 $dirElement = $dirElements[$i];
00367 if ( strlen( $dirElement ) == 0 )
00368 continue;
00369
00370 $currentDir .= '/' . $dirElement;
00371
00372 if ( !file_exists( $currentDir ) && !mkdir( $currentDir, 0777 ) )
00373 return false;
00374
00375 $result = true;
00376 }
00377
00378 return $result;
00379 }
00380
00381 function _fetch( $filePath, $uniqueName = false )
00382 {
00383 $metaData = $this->_fetchMetadata( $filePath );
00384 if ( !$metaData )
00385 {
00386 eZDebug::writeNotice( "File '$filePath' does not exists while trying to fetch." );
00387 return false;
00388 }
00389
00390 $fileID = $metaData['id'];
00391 $sql = "SELECT filedata FROM " . TABLE_DATA . " WHERE masterid=$fileID ORDER BY id";
00392 if ( !$res = mysql_query( $sql, $this->db ) )
00393 {
00394 eZDebug::writeError( $srcFilePath, "Failed to fetch file data." );
00395 return false;
00396 }
00397
00398 if( !mysql_num_rows( $res ) )
00399 {
00400 eZDebug::writeNotice( "No rows in file '$filePath' (#$fileID) being fetched." );
00401 mysql_free_result( $res );
00402 return false;
00403 }
00404
00405
00406 if ( strrpos( $filePath, '.' ) > 0 )
00407 $tmpFilePath = substr_replace( $filePath, getmypid().'tmp', strrpos( $filePath, '.' ), 0 );
00408 else
00409 $tmpFilePath = $filePath . '.' . getmypid().'tmp';
00410
00411 $this->__mkdir_p( dirname( $tmpFilePath ) );
00412 if ( !( $fp = fopen( $tmpFilePath, 'wb' ) ) )
00413 {
00414 eZDebug::writeError( "Cannot write to '$tmpFilePath' while fetching file." );
00415 return false;
00416 }
00417
00418 while ( $row = mysql_fetch_row( $res ) )
00419 fwrite( $fp, $row[0] );
00420
00421 fclose( $fp );
00422
00423 if ( ! $uniqueName === true )
00424 {
00425 include_once( 'lib/ezfile/classes/ezfile.php' );
00426 eZFile::rename( $tmpFilePath, $filePath );
00427 }
00428 else
00429 {
00430 $filePath = $tmpFilePath;
00431 }
00432 mysql_free_result( $res );
00433
00434 return $filePath;
00435 }
00436
00437 function _fetchContents( $filePath )
00438 {
00439 $metaData = $this->_fetchMetadata( $filePath );
00440 if ( !$metaData )
00441 {
00442 eZDebug::writeNotice( "File '$filePath' does not exists while trying to fetch its contents." );
00443 return false;
00444 }
00445
00446 $fileID = $metaData['id'];
00447 $sql = "SELECT filedata FROM " . TABLE_DATA . " WHERE masterid=$fileID ORDER BY id";
00448 if ( !$res = mysql_query( $sql, $this->db ) )
00449 {
00450 eZDebug::writeError( $srcFilePath, "Failed to fetch file data." );
00451 return false;
00452 }
00453
00454 $contents = '';
00455 while ( $row = mysql_fetch_row( $res ) )
00456 {
00457 $contents .= $row[0];
00458 }
00459
00460 mysql_free_result( $res );
00461 return $contents;
00462 }
00463
00464
00465
00466
00467 function _fetchMetadata( $filePath )
00468 {
00469 $filePath = mysql_real_escape_string( $filePath );
00470 $sql = "SELECT * FROM " . TABLE_METADATA . " WHERE name_hash='" . md5( $filePath ) . "'" ;
00471 if ( !$res = mysql_query( $sql, $this->db ) )
00472 $this->_die( "Failed to retrive file metadata: $filePath", $sql );
00473
00474 $nRows = mysql_num_rows( $res );
00475 $metaData = false;
00476
00477 switch ( $nRows )
00478 {
00479 case 0;
00480 break;
00481
00482 default:
00483 eZDebug::writeError( "Duplicate file '$filePath' found." );
00484
00485
00486 case 1:
00487 $row = mysql_fetch_array( $res, MYSQL_ASSOC );
00488 $metaData = $row;
00489 }
00490
00491 mysql_free_result( $res );
00492 return $metaData;
00493 }
00494
00495 function _linkCopy( $srcPath, $dstPath )
00496 {
00497 return $this->_copy( $srcPath, $dstPath );
00498 }
00499
00500 function _passThrough( $filePath )
00501 {
00502 $metaData = $this->_fetchMetadata( $filePath );
00503 if ( !$metaData )
00504 return false;
00505
00506 $fileID = $metaData['id'];
00507 $sql = "SELECT filedata FROM " . TABLE_DATA . " WHERE masterid=$fileID";
00508 if ( !$res = mysql_query( $sql, $this->db ) )
00509 {
00510 eZDebug::writeError( $srcFilePath, "Failed to fetch file data." );
00511 return false;
00512 }
00513
00514 while ( $row = mysql_fetch_row( $res ) )
00515 echo $row[0];
00516
00517 mysql_free_result( $res );
00518 return true;
00519 }
00520
00521 function _rename( $srcFilePath, $dstFilePath )
00522 {
00523
00524 $metaData = $this->_fetchMetadata( $srcFilePath );
00525 if ( !$metaData )
00526 return false;
00527
00528 mysql_query( 'BEGIN', $this->db );
00529
00530 if ( $this->_exists( $dstFilePath ) )
00531 $this->_delete( $dstFilePath, true );
00532
00533 $srcFilePath = mysql_real_escape_string( $srcFilePath );
00534 $dstFilePath = mysql_real_escape_string( $dstFilePath );
00535
00536 $srcFilePathHash = $metaData['name_hash'];
00537 $dstFilePathHash = md5( $dstFilePath );
00538
00539 $sql = "UPDATE " . TABLE_METADATA . " SET name='$dstFilePath', name_hash='$dstFilePathHash' ";
00540 $sql .= "WHERE name_hash='$srcFilePathHash'";
00541 if ( !mysql_query( $sql, $this->db ) )
00542 {
00543 eZDebug::writeError( "Failed renaming file '$srcFilePath' to '$dstFilePath'" );
00544 mysql_query( 'ROLLBACK', $this->db );
00545 return false;
00546 }
00547
00548 mysql_query( 'COMMIT', $this->db );
00549
00550 return true;
00551 }
00552
00553 function _store( $filePath, $datatype, $scope )
00554 {
00555 if ( !is_readable( $filePath ) )
00556 {
00557 eZDebug::writeError( "Unable to store file '$filePath' since it is not readable.", 'ezdbfilehandlermysqlbackend' );
00558 return;
00559 }
00560
00561
00562 mysql_query( 'BEGIN', $this->db );
00563
00564
00565 if ( $this->_exists( $filePath ) )
00566 $this->_delete( $filePath, true );
00567
00568 if ( $this->_exists( $filePath ) )
00569 eZDebug::writeNotice( "File '$filePath' still exists after deletion." );
00570
00571
00572 clearstatcache();
00573 $fileMTime = filemtime( $filePath );
00574 $contentLength = filesize( $filePath );
00575 $filePathEscaped = mysql_real_escape_string( $filePath );
00576 $filePathHash = md5( $filePathEscaped );
00577 $sql = "INSERT INTO " . TABLE_METADATA . " (datatype, name, name_hash, scope, size, mtime) VALUES";
00578 $sql .= "('$datatype', '$filePathEscaped', '$filePathHash', '$scope', $contentLength, '$fileMTime')";
00579
00580 if ( !$res = mysql_query( $sql, $this->db ) )
00581 {
00582 eZDebug::writeNotice( "Failed to insert file metadata while storing. Possible race condition: " . $sql );
00583 mysql_query( 'ROLLBACK', $this->db );
00584 return;
00585 }
00586
00587 $fileID = mysql_insert_id( $this->db );
00588
00589
00590 if ( !$fp = @fopen( $filePath, 'rb' ) )
00591 {
00592 eZDebug::writeError( "Cannot read '$filePath'.", 'ezdbfilehandlermysqlbackend' );
00593 mysql_query( 'ROLLBACK', $this->db );
00594 return;
00595 }
00596
00597 $chunkSize = $this->dbparams['chunk_size'];
00598 while ( !feof( $fp ) )
00599 {
00600
00601 $binarydata = mysql_real_escape_string( fread( $fp, $chunkSize ) );
00602
00603 $sql = "INSERT INTO " . TABLE_DATA . " (masterid, filedata) VALUES ($fileID, '$binarydata')";
00604
00605 if ( !mysql_query( $sql, $this->db ) )
00606 {
00607 eZDebug::writeNotice( "Failed to insert file data row while storing. Possible race condition: " . $sql );
00608 mysql_query( 'ROLLBACK', $this->db );
00609 return;
00610 }
00611 }
00612
00613
00614 mysql_query( 'COMMIT', $this->db );
00615
00616 fclose( $fp );
00617 }
00618
00619 function _storeContents( $filePath, $contents, $scope, $datatype )
00620 {
00621
00622 mysql_query( 'BEGIN', $this->db );
00623
00624
00625 if ( $this->_exists( $filePath ) )
00626 $this->_delete( $filePath, true );
00627
00628
00629 $contentLength = strlen( $contents );
00630 $filePath = mysql_real_escape_string( $filePath );
00631 $filePathHash = md5( $filePath );
00632 $curTime = time();
00633 $sql = "INSERT INTO " . TABLE_METADATA . " (datatype, name, name_hash, scope, size, mtime) VALUES";
00634 $sql .= "('$datatype', '$filePath', '$filePathHash', '$scope', $contentLength, '$curTime')";
00635
00636 if ( !$res = mysql_query( $sql, $this->db ) )
00637 {
00638 eZDebug::writeNotice( "Failed to insert file metadata while storing contents. Possible race condition: " . $sql );
00639 mysql_query( 'ROLLBACK', $this->db );
00640 return;
00641 }
00642 $fileID = mysql_insert_id( $this->db );
00643
00644
00645 $chunkSize = $this->dbparams['chunk_size'];
00646 for ( $pos = 0; $pos < $contentLength; $pos += $chunkSize )
00647 {
00648 $chunk = substr( $contents, $pos, $chunkSize );
00649
00650 $sql = "INSERT INTO " . TABLE_DATA . " ( masterid, filedata ) VALUES (";
00651 $sql .= $fileID . ", '" . mysql_real_escape_string( $chunk ) . "')";
00652
00653 if ( !mysql_query( $sql, $this->db ) )
00654 {
00655 eZDebug::writeNotice( "Failed to insert file data row while storing contents. Possible race condition: " . $sql );
00656 mysql_query( 'ROLLBACK', $this->db );
00657 return;
00658 }
00659 }
00660
00661
00662 mysql_query( 'COMMIT', $this->db );
00663 }
00664
00665 function _getFileList( $skipBinaryFiles, $skipImages )
00666 {
00667 $query = 'SELECT name FROM ' . TABLE_METADATA;
00668
00669
00670 $filters = array();
00671 if ( $skipBinaryFiles )
00672 $filters[] = "'binaryfile'";
00673 if ( $skipImages )
00674 $filters[] = "'image'";
00675 if ( $filters )
00676 $query .= ' WHERE scope NOT IN (' . join( ', ', $filters ) . ')';
00677
00678 $rslt = mysql_query( $query, $this->db );
00679 if ( !$rslt )
00680 {
00681 eZDebug::writeError( mysql_error( $this->db ) );
00682 return false;
00683 }
00684
00685 $filePathList = array();
00686 while ( $row = mysql_fetch_row( $rslt ) )
00687 $filePathList[] = $row[0];
00688
00689 mysql_free_result( $rslt );
00690
00691 return $filePathList;
00692 }
00693
00694 function _die( $msg, $sql = null )
00695 {
00696 if ( $this->db )
00697 eZDebug::writeError( $sql, "$msg" . mysql_error( $this->db ) );
00698 else
00699 eZDebug::writeError( $sql, "$msg: " . mysql_error() );
00700
00701 if( @include_once( '../bt.php' ) )
00702 {
00703 bt();
00704 die( $msg );
00705 }
00706 }
00707
00708 var $db = null;
00709 }
00710
00711 ?>