filetype - string, type of searched files,
- * meaningful values: 'audioclip', 'webstream', 'playlist', 'all'
- *
operator - string, type of conditions join
- * (any condition matches / all conditions match),
- * meaningful values: 'and', 'or', ''
- * (may be empty or ommited only with less then 2 items in
- * "conditions" field)
- *
- *
orderby : string - metadata category for sorting (optional)
- * or array of strings for multicolumn orderby
- * [default: dc:creator, dc:source, dc:title]
- *
- *
desc : boolean - flag for descending order (optional)
- * or array of boolean for multicolumn orderby
- * (it corresponds to elements of orderby field)
- * [default: all ascending]
- *
- * Format of search/browse results: hash, with following structure:
- *
- *
results : array of gunids have found
- *
cnt : integer - number of matching items
- *
- *
- */
-define('GBERR_DENY', 40);
-define('GBERR_FILEIO', 41);
-define('GBERR_FILENEX', 42);
-define('GBERR_FOBJNEX', 43);
-define('GBERR_WRTYPE', 44);
-define('GBERR_NONE', 45);
-define('GBERR_AOBJNEX', 46);
-define('GBERR_NOTF', 47);
-define('GBERR_SESS', 48);
-define('GBERR_PREF', 49);
-define('GBERR_TOKEN', 50);
-define('GBERR_PUT', 51);
-define('GBERR_LOCK', 52);
-define('GBERR_GUNID', 53);
-define('GBERR_BGERR', 54);
-define('GBERR_NOTIMPL', 69);
-
-require_once(dirname(__FILE__)."/Alib.php");
-require_once(dirname(__FILE__)."/StoredFile.php");
-require_once(dirname(__FILE__)."/Playlist.php");
-
-/**
- * Core of Airtime file storage module
- *
- * @package Airtime
- * @subpackage StorageServer
- * @copyright 2010 Sourcefabric O.P.S.
- * @license http://www.gnu.org/licenses/gpl.txt
- * @see Alib
- */
-class BasicStor {
- public $storId;
- private $fileTypes;
-
- public function __construct()
- {
- $this->filetypes = array(
- 'all'=>NULL,
- 'audioclip'=>'audioclip',
- 'webstream'=>'webstream',
- 'playlist'=>'playlist',
- );
- }
-
-
- /* ----------------------------------------------------- put, access etc. */
- /**
- * Check validity of access/put token
- *
- * @param string $token
- * Access/put token
- * @param string $type
- * 'put'|'access'|'download'
- * @return boolean
- */
- public static function bsCheckToken($token, $type='put')
- {
- global $CC_CONFIG, $CC_DBC;
- $cnt = $CC_DBC->getOne("
- SELECT count(token) FROM ".$CC_CONFIG['accessTable']."
- WHERE token=x'{$token}'::bigint AND type='$type'
- ");
- if (PEAR::isError($cnt)) {
- return FALSE;
- }
- return ($cnt == 1);
- }
-
-
- /**
- * Create and return access link to real file
- *
- * @param string $realFname
- * Local filepath to accessed file
- * (NULL for only increase access counter, no symlink)
- * @param string $ext
- * Useful filename extension for accessed file
- * @param int $gunid
- * Global unique id
- * (NULL for special files such exported playlists)
- * @param string $type
- * 'access'|'download'
- * @param int $parent
- * parent token (recursive access/release)
- * @param int $owner
- * Local user id - owner of token
- * @return array
- * array with: seekable filehandle, access token
- */
- public static function bsAccess($realFname, $ext, $gunid, $type='access',
- $parent='0', $owner=NULL)
- {
- global $CC_CONFIG, $CC_DBC;
- if (!is_null($gunid)) {
- $gunid = StoredFile::NormalizeGunid($gunid);
- }
- $token = StoredFile::CreateGunid();
- if (!is_null($realFname)) {
- $linkFname = $CC_CONFIG['accessDir']."/$token.$ext";
- //broken links are ignored by the player, do not worry about it here
- /* if (!is_file($realFname) && !is_link($realFname)) {
- return PEAR::raiseError(
- "BasicStor::bsAccess: real file not found ($realFname)",
- GBERR_FILEIO);
- }
- */
- if (! @symlink($realFname, $linkFname)) {
- return PEAR::raiseError(
- "BasicStor::bsAccess: symlink create failed ($linkFname)",
- GBERR_FILEIO);
- }
- } else {
- $linkFname = NULL;
- }
- $escapedExt = pg_escape_string($ext);
- $escapedType = pg_escape_string($type);
- $CC_DBC->query("BEGIN");
- $gunidSql = (is_null($gunid) ? "NULL" : "x'{$gunid}'::bigint" );
- $ownerSql = (is_null($owner) ? "NULL" : "$owner" );
- $res = $CC_DBC->query("
- INSERT INTO ".$CC_CONFIG['accessTable']."
- (gunid, token, ext, type, parent, owner, ts)
- VALUES
- ($gunidSql, x'$token'::bigint,
- '$escapedExt', '$escapedType', x'{$parent}'::bigint, $ownerSql, now())
- ");
- if (PEAR::isError($res)) {
- $CC_DBC->query("ROLLBACK");
- return $res;
- }
- if (!is_null($gunid)) {
- $res = $CC_DBC->query("
- UPDATE ".$CC_CONFIG['filesTable']."
- SET currentlyAccessing=currentlyAccessing+1, mtime=now()
- WHERE gunid=x'{$gunid}'::bigint
- ");
- }
- if (PEAR::isError($res)) {
- $CC_DBC->query("ROLLBACK");
- return $res;
- }
- $res = $CC_DBC->query("COMMIT");
- if (PEAR::isError($res)) {
- return $res;
- }
- return array('fname'=>$linkFname, 'token'=>$token);
- }
-
-
- /**
- * Release access link to real file
- *
- * @param string $token
- * Access token
- * @param string $type
- * 'access'|'download'
- * @return array
- * gunid: string, global unique ID or real pathname of special file
- * owner: int, local subject id of token owner
- * realFname: string, real local pathname of accessed file
- */
- public static function bsRelease($token, $type='access')
- {
- global $CC_CONFIG, $CC_DBC;
- if (!BasicStor::bsCheckToken($token, $type)) {
- return PEAR::raiseError(
- "BasicStor::bsRelease: invalid token ($token)"
- );
- }
- $acc = $CC_DBC->getRow("
- SELECT to_hex(gunid)as gunid, ext, owner FROM ".$CC_CONFIG['accessTable']."
- WHERE token=x'{$token}'::bigint AND type='$type'
- ");
- if (PEAR::isError($acc)) {
- return $acc;
- }
- $ext = $acc['ext'];
- $owner = $acc['owner'];
- $linkFname = $CC_CONFIG['accessDir']."/$token.$ext";
- $realFname = readlink($linkFname);
- if (file_exists($linkFname)) {
- if(! @unlink($linkFname)){
- return PEAR::raiseError(
- "BasicStor::bsRelease: unlink failed ($linkFname)",
- GBERR_FILEIO);
- }
- }
- $CC_DBC->query("BEGIN");
- if (!is_null($acc['gunid'])) {
- $gunid = StoredFile::NormalizeGunid($acc['gunid']);
- $res = $CC_DBC->query("
- UPDATE ".$CC_CONFIG['filesTable']."
- SET currentlyAccessing=currentlyAccessing-1, mtime=now()
- WHERE gunid=x'{$gunid}'::bigint AND currentlyAccessing>0
- ");
- if (PEAR::isError($res)) {
- $CC_DBC->query("ROLLBACK");
- return $res;
- }
- }
- $res = $CC_DBC->query("
- DELETE FROM ".$CC_CONFIG['accessTable']." WHERE token=x'$token'::bigint
- ");
- if (PEAR::isError($res)) {
- $CC_DBC->query("ROLLBACK");
- return $res;
- }
- $res = $CC_DBC->query("COMMIT");
- if (PEAR::isError($res)) {
- return $res;
- }
- $res = array(
- 'gunid' => (isset($gunid) ? $gunid : NULL ),
- 'realFname' => $realFname,
- 'owner' => $owner,
- );
- return $res;
- }
-
-
- /* ----------------------------------------------------- metadata methods */
-
- /**
- * Method returning array with where-parts of sql queries
- *
- * @param array $conditions
- * See 'conditions' field in search criteria format
- * definition in class documentation
- * @return array
- * array of strings - WHERE-parts of SQL queries
- */
- private function _makeWhereArr($conditions)
- {
- $ops = array('full'=>"='%s'", 'partial'=>"ILIKE '%%%s%%'",
- 'prefix'=>"ILIKE '%s%%'", '<'=>"< '%s'", '='=>"= '%s'",
- '>'=>"> '%s'", '<='=>"<= '%s'", '>='=>">= '%s'"
- );
- $whereArr = array();
- if (is_array($conditions)) {
- foreach ($conditions as $cond) {
- $columnName = StoredFile::xmlCategoryToDbColumn($cond['cat']);
- $op = strtolower($cond['op']);
- $value = $cond['val'];
- if (!empty($value)) {
- $splittedQn = XML_Util::splitQualifiedName($catQn);
- $catNs = $splittedQn['namespace'];
- $cat = $splittedQn['localPart'];
- $opVal = sprintf($ops[$op], pg_escape_string($value));
- // retype for timestamp value
- if ($cat == 'mtime') {
- switch ($op) {
- case 'partial':
- case 'prefix':
- break;
- default:
- $retype = "::timestamp with time zone";
- $opVal = "$retype $opVal$retype";
- }
- }
- $sqlCond = " {$columnName} {$opVal}\n";
- $whereArr[] = $sqlCond;
- }
- }
- }
- return $whereArr;
- }
-
- /**
- * Search in local metadata database.
- *
- * @param array $criteria
- * has the following structure:
- *
- *
filetype - string, type of searched files,
- * meaningful values: 'audioclip', 'webstream', 'playlist', 'all'
- *
operator - string, type of conditions join
- * (any condition matches / all conditions match),
- * meaningful values: 'and', 'or', ''
- * (may be empty or ommited only with less then 2 items in
- * "conditions" field)
- *
- *
orderby : string - metadata category for sorting (optional)
- * or array of strings for multicolumn orderby
- * [default: dc:creator, dc:source, dc:title]
- *
- *
desc : boolean - flag for descending order (optional)
- * or array of boolean for multicolumn orderby
- * (it corresponds to elements of orderby field)
- * [default: all ascending]
- *