Merge branch 'saas' into saas-embed-player
This commit is contained in:
commit
ac2181a52d
40 changed files with 913 additions and 608 deletions
|
@ -80,7 +80,7 @@ class Application_Model_RabbitMq
|
|||
}
|
||||
|
||||
public static function SendMessageToAnalyzer($tmpFilePath, $importedStorageDirectory, $originalFilename,
|
||||
$callbackUrl, $apiKey, $currentStorageBackend, $filePrefix)
|
||||
$callbackUrl, $apiKey, $storageBackend, $filePrefix)
|
||||
{
|
||||
//Hack for Airtime Pro. The RabbitMQ settings for communicating with airtime_analyzer are global
|
||||
//and shared between all instances on Airtime Pro.
|
||||
|
@ -107,7 +107,7 @@ class Application_Model_RabbitMq
|
|||
$queue = 'airtime-uploads';
|
||||
$autoDeleteExchange = false;
|
||||
$data['tmp_file_path'] = $tmpFilePath;
|
||||
$data['current_storage_backend'] = $currentStorageBackend;
|
||||
$data['storage_backend'] = $storageBackend;
|
||||
$data['import_directory'] = $importedStorageDirectory;
|
||||
$data['original_filename'] = $originalFilename;
|
||||
$data['callback_url'] = $callbackUrl;
|
||||
|
|
|
@ -954,7 +954,6 @@ SQL;
|
|||
|
||||
$baseUrl = Application_Common_OsPath::getBaseDir();
|
||||
$filesize = $file->getFileSize();
|
||||
|
||||
self::createFileScheduleEvent($data, $item, $media_id, $uri, $filesize);
|
||||
}
|
||||
|
||||
|
|
|
@ -392,13 +392,15 @@ SQL;
|
|||
Logging::info("User ".$user->getLogin()." is deleting file: ".$this->_file->getDbTrackTitle()." - file id: ".$file_id);
|
||||
|
||||
$filesize = $this->_file->getFileSize();
|
||||
if ($filesize <= 0) {
|
||||
if ($filesize < 0) {
|
||||
throw new Exception("Cannot delete file with filesize ".$filesize);
|
||||
}
|
||||
|
||||
//Delete the physical file from either the local stor directory
|
||||
//or from the cloud
|
||||
$this->_file->deletePhysicalFile();
|
||||
if ($this->_file->getDbImportStatus() == CcFiles::IMPORT_STATUS_SUCCESS) {
|
||||
$this->_file->deletePhysicalFile();
|
||||
}
|
||||
|
||||
//Update the user's disk usage
|
||||
Application_Model_Preference::updateDiskUsage(-1 * $filesize);
|
||||
|
@ -944,19 +946,17 @@ SQL;
|
|||
* The file is actually copied to "stor/organize", which is a staging directory where files go
|
||||
* before they're processed by airtime_analyzer, which then moves them to "stor/imported" in the final
|
||||
* step.
|
||||
*
|
||||
* TODO: Implement better error handling here...
|
||||
*
|
||||
* @param string $tempFilePath
|
||||
* @param string $originalFilename
|
||||
* @param bool $copyFile Copy the file instead of moving it.
|
||||
* @throws Exception
|
||||
* @return Ambigous <unknown, string>
|
||||
*/
|
||||
public static function copyFileToStor($tempFilePath, $originalFilename)
|
||||
public static function moveFileToStor($tempFilePath, $originalFilename, $copyFile=false)
|
||||
{
|
||||
$audio_file = $tempFilePath;
|
||||
Logging::info('copyFileToStor: moving file '.$audio_file);
|
||||
|
||||
|
||||
$storDir = Application_Model_MusicDir::getStorDir();
|
||||
$stor = $storDir->getDirectory();
|
||||
// check if "organize" dir exists and if not create one
|
||||
|
@ -970,57 +970,34 @@ SQL;
|
|||
Logging::info("Warning: couldn't change permissions of $audio_file to 0644");
|
||||
}
|
||||
|
||||
// Check if liquidsoap can play this file
|
||||
// TODO: Move this to airtime_analyzer
|
||||
/*
|
||||
if (!self::liquidsoapFilePlayabilityTest($audio_file)) {
|
||||
return array(
|
||||
"code" => 110,
|
||||
"message" => _("This file appears to be corrupted and will not "
|
||||
."be added to media library."));
|
||||
}*/
|
||||
|
||||
|
||||
// Did all the checks for real, now trying to copy
|
||||
$audio_stor = Application_Common_OsPath::join($stor, "organize",
|
||||
$originalFilename);
|
||||
Logging::info($originalFilename);
|
||||
Logging::info($audio_stor);
|
||||
$user = Application_Model_User::getCurrentUser();
|
||||
if (is_null($user)) {
|
||||
$uid = Application_Model_User::getFirstAdminId();
|
||||
} else {
|
||||
$uid = $user->getId();
|
||||
}
|
||||
/*
|
||||
$id_file = "$audio_stor.identifier";
|
||||
if (file_put_contents($id_file, $uid) === false) {
|
||||
Logging::info("Could not write file to identify user: '$uid'");
|
||||
Logging::info("Id file path: '$id_file'");
|
||||
Logging::info("Defaulting to admin (no identification file was
|
||||
written)");
|
||||
} else {
|
||||
Logging::info("Successfully written identification file for
|
||||
uploaded '$audio_stor'");
|
||||
}*/
|
||||
|
||||
//if the uploaded file is not UTF-8 encoded, let's encode it. Assuming source
|
||||
//encoding is ISO-8859-1
|
||||
$audio_stor = mb_detect_encoding($audio_stor, "UTF-8") == "UTF-8" ? $audio_stor : utf8_encode($audio_stor);
|
||||
Logging::info("copyFileToStor: moving file $audio_file to $audio_stor");
|
||||
// Martin K.: changed to rename: Much less load + quicker since this is
|
||||
// an atomic operation
|
||||
if (@rename($audio_file, $audio_stor) === false) {
|
||||
//something went wrong likely there wasn't enough space in .
|
||||
//the audio_stor to move the file too warn the user that .
|
||||
//the file wasn't uploaded and they should check if there .
|
||||
//is enough disk space .
|
||||
unlink($audio_file); //remove the file after failed rename
|
||||
//unlink($id_file); // Also remove the identifier file
|
||||
|
||||
throw new Exception("The file was not uploaded, this error can occur if the computer "
|
||||
."hard drive does not have enough disk space or the stor "
|
||||
."directory does not have correct write permissions.");
|
||||
if ($copyFile) {
|
||||
Logging::info("Copying file $audio_file to $audio_stor");
|
||||
if (@copy($audio_file, $audio_stor) === false) {
|
||||
throw new Exception("Failed to copy $audio_file to $audio_stor");
|
||||
}
|
||||
} else {
|
||||
Logging::info("Moving file $audio_file to $audio_stor");
|
||||
|
||||
// Martin K.: changed to rename: Much less load + quicker since this is
|
||||
// an atomic operation
|
||||
if (@rename($audio_file, $audio_stor) === false) {
|
||||
//something went wrong likely there wasn't enough space in .
|
||||
//the audio_stor to move the file too warn the user that .
|
||||
//the file wasn't uploaded and they should check if there .
|
||||
//is enough disk space .
|
||||
unlink($audio_file); //remove the file after failed rename
|
||||
//unlink($id_file); // Also remove the identifier file
|
||||
|
||||
throw new Exception("The file was not uploaded, this error can occur if the computer "
|
||||
. "hard drive does not have enough disk space or the stor "
|
||||
. "directory does not have correct write permissions.");
|
||||
}
|
||||
}
|
||||
return $audio_stor;
|
||||
}
|
||||
|
|
|
@ -11,17 +11,313 @@
|
|||
*
|
||||
* @package propel.generator.campcaster
|
||||
*/
|
||||
|
||||
class InvalidMetadataException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
class FileNotFoundException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
class OverDiskQuotaException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class CcFiles extends BaseCcFiles {
|
||||
|
||||
|
||||
const MUSIC_DIRS_STOR_PK = 1;
|
||||
|
||||
const IMPORT_STATUS_SUCCESS = 0;
|
||||
const IMPORT_STATUS_PENDING = 1;
|
||||
const IMPORT_STATUS_FAILED = 2;
|
||||
|
||||
|
||||
//fields that are not modifiable via our RESTful API
|
||||
private static $blackList = array(
|
||||
'id',
|
||||
'directory',
|
||||
'filepath',
|
||||
'file_exists',
|
||||
'mtime',
|
||||
'utime',
|
||||
'lptime',
|
||||
'silan_check',
|
||||
'soundcloud_id',
|
||||
'is_scheduled',
|
||||
'is_playlist'
|
||||
);
|
||||
|
||||
//fields we should never expose through our RESTful API
|
||||
private static $privateFields = array(
|
||||
'file_exists',
|
||||
'silan_check',
|
||||
'is_scheduled',
|
||||
'is_playlist'
|
||||
'file_exists',
|
||||
'silan_check',
|
||||
'is_scheduled',
|
||||
'is_playlist'
|
||||
);
|
||||
|
||||
public function getCueLength()
|
||||
|
||||
/**
|
||||
* Retrieve a sanitized version of the file metadata, suitable for public access.
|
||||
* @param $fileId
|
||||
*/
|
||||
public static function getSanitizedFileById($fileId)
|
||||
{
|
||||
$file = CcFilesQuery::create()->findPk($fileId);
|
||||
if ($file) {
|
||||
return CcFiles::sanitizeResponse($file);
|
||||
} else {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Used to create a CcFiles object from an array containing metadata and a file uploaded by POST.
|
||||
* This is used by our Media REST API!
|
||||
* @param $fileArray An array containing metadata for a CcFiles object.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createFromUpload($fileArray)
|
||||
{
|
||||
if (Application_Model_Systemstatus::isDiskOverQuota()) {
|
||||
throw new OverDiskQuotaException();
|
||||
}
|
||||
|
||||
/* If full_path is set, the post request came from ftp.
|
||||
* Users are allowed to upload folders via ftp. If this is the case
|
||||
* we need to include the folder name with the file name, otherwise
|
||||
* files won't get removed from the organize folder.
|
||||
*/
|
||||
|
||||
//Extract the original filename, which we set as the temporary title for the track
|
||||
//until it's finished being processed by the analyzer.
|
||||
$originalFilename = $_FILES["file"]["name"];
|
||||
$tempFilePath = $_FILES['file']['tmp_name'];
|
||||
|
||||
try {
|
||||
self::createAndImport($fileArray, $tempFilePath, $originalFilename);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
@unlink($tempFilePath);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Import a music file to the library from a local file on disk (something pre-existing).
|
||||
* This function allows you to copy a file rather than move it, which is useful for importing
|
||||
* static music files (like sample tracks).
|
||||
* @param string $filePath The full path to the audio file to import.
|
||||
* @param bool $copyFile True if you want to just copy the false, false if you want to move it (default false)
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createFromLocalFile($fileArray, $filePath, $copyFile=false)
|
||||
{
|
||||
$info = pathinfo($filePath);
|
||||
$fileName = basename($filePath).'.'.$info['extension'];
|
||||
self::createAndImport($fileArray, $filePath, $fileName, $copyFile);
|
||||
}
|
||||
|
||||
/** Create a new CcFiles object/row and import a file for it.
|
||||
* You shouldn't call this directly. Either use createFromUpload() or createFromLocalFile().
|
||||
* @param array $fileArray Any metadata to pre-fill for the audio file
|
||||
* @param string $filePath The full path to the audio file to import
|
||||
* @param string $originalFilename
|
||||
* @param bool $copyFile
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
* @throws PropelException
|
||||
*/
|
||||
private static function createAndImport($fileArray, $filePath, $originalFilename, $copyFile=false)
|
||||
{
|
||||
$file = new CcFiles();
|
||||
|
||||
try
|
||||
{
|
||||
$fileArray = self::removeBlacklistedFields($fileArray);
|
||||
|
||||
self::validateFileArray($fileArray);
|
||||
|
||||
$file->fromArray($fileArray);
|
||||
$file->setDbOwnerId(self::getOwnerId());
|
||||
$now = new DateTime("now", new DateTimeZone("UTC"));
|
||||
$file->setDbTrackTitle($originalFilename);
|
||||
$file->setDbUtime($now);
|
||||
$file->setDbHidden(true);
|
||||
$file->save();
|
||||
|
||||
//Only accept files with a file extension that we support.
|
||||
$fileExtension = pathinfo($originalFilename, PATHINFO_EXTENSION);
|
||||
if (!in_array(strtolower($fileExtension), explode(",", "ogg,mp3,oga,flac,wav,m4a,mp4,opus"))) {
|
||||
throw new Exception("Bad file extension.");
|
||||
}
|
||||
|
||||
$callbackUrl = Application_Common_HTTPHelper::getStationUrl() . "/rest/media/" . $file->getPrimaryKey();
|
||||
|
||||
Application_Service_MediaService::importFileToLibrary($callbackUrl, $filePath,
|
||||
$originalFilename, self::getOwnerId(), $copyFile);
|
||||
|
||||
return CcFiles::sanitizeResponse($file);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$file->setDbImportStatus(self::IMPORT_STATUS_FAILED);
|
||||
$file->setDbHidden(true);
|
||||
$file->save();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update a file with metadata specified in an array.
|
||||
* @param $fileId string The ID of the file to update in the DB.
|
||||
* @param $fileArray array An associative array containing metadata. Replaces those fields if they exist.
|
||||
* @return array A sanitized version of the file metadata array.
|
||||
* @throws Exception
|
||||
* @throws FileNotFoundException
|
||||
* @throws PropelException
|
||||
*/
|
||||
public static function updateFromArray($fileId, $fileArray)
|
||||
{
|
||||
$file = CcFilesQuery::create()->findPk($fileId);
|
||||
|
||||
$fileArray = self::removeBlacklistedFields($fileArray);
|
||||
$fileArray = self::stripTimeStampFromYearTag($fileArray);
|
||||
|
||||
try {
|
||||
|
||||
self::validateFileArray($fileArray);
|
||||
if ($file && isset($fileArray["resource_id"])) {
|
||||
|
||||
$file->fromArray($fileArray, BasePeer::TYPE_FIELDNAME);
|
||||
|
||||
//store the original filename
|
||||
$file->setDbFilepath($fileArray["filename"]);
|
||||
|
||||
$fileSizeBytes = $fileArray["filesize"];
|
||||
if (!isset($fileSizeBytes) || $fileSizeBytes === false) {
|
||||
throw new FileNotFoundException("Invalid filesize for $fileId");
|
||||
}
|
||||
|
||||
$cloudFile = new CloudFile();
|
||||
$cloudFile->setStorageBackend($fileArray["storage_backend"]);
|
||||
$cloudFile->setResourceId($fileArray["resource_id"]);
|
||||
$cloudFile->setCcFiles($file);
|
||||
$cloudFile->save();
|
||||
|
||||
Application_Model_Preference::updateDiskUsage($fileSizeBytes);
|
||||
|
||||
$now = new DateTime("now", new DateTimeZone("UTC"));
|
||||
$file->setDbMtime($now);
|
||||
$file->save();
|
||||
|
||||
} else if ($file) {
|
||||
|
||||
// Since we check for this value when deleting files, set it first
|
||||
$file->setDbDirectory(self::MUSIC_DIRS_STOR_PK);
|
||||
|
||||
$file->fromArray($fileArray, BasePeer::TYPE_FIELDNAME);
|
||||
|
||||
//Our RESTful API takes "full_path" as a field, which we then split and translate to match
|
||||
//our internal schema. Internally, file path is stored relative to a directory, with the directory
|
||||
//as a foreign key to cc_music_dirs.
|
||||
if (isset($fileArray["full_path"])) {
|
||||
$fileSizeBytes = filesize($fileArray["full_path"]);
|
||||
if (!isset($fileSizeBytes) || $fileSizeBytes === false) {
|
||||
throw new FileNotFoundException("Invalid filesize for $fileId");
|
||||
}
|
||||
Application_Model_Preference::updateDiskUsage($fileSizeBytes);
|
||||
|
||||
$fullPath = $fileArray["full_path"];
|
||||
$storDir = Application_Model_MusicDir::getStorDir()->getDirectory();
|
||||
$pos = strpos($fullPath, $storDir);
|
||||
|
||||
if ($pos !== FALSE) {
|
||||
assert($pos == 0); //Path must start with the stor directory path
|
||||
|
||||
$filePathRelativeToStor = substr($fullPath, strlen($storDir));
|
||||
$file->setDbFilepath($filePathRelativeToStor);
|
||||
}
|
||||
}
|
||||
|
||||
$now = new DateTime("now", new DateTimeZone("UTC"));
|
||||
$file->setDbMtime($now);
|
||||
$file->save();
|
||||
|
||||
} else {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException $e)
|
||||
{
|
||||
$file->setDbImportStatus(self::IMPORT_STATUS_FAILED);
|
||||
$file->setDbHidden(true);
|
||||
$file->save();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return CcFiles::sanitizeResponse($file);
|
||||
}
|
||||
|
||||
/** Delete a file from the database and disk (or cloud).
|
||||
* @param $id The file ID
|
||||
* @throws DeleteScheduledFileException
|
||||
* @throws Exception
|
||||
* @throws FileNoPermissionException
|
||||
* @throws FileNotFoundException
|
||||
* @throws PropelException
|
||||
*/
|
||||
public static function deleteById($id)
|
||||
{
|
||||
$file = CcFilesQuery::create()->findPk($id);
|
||||
if ($file) {
|
||||
$con = Propel::getConnection();
|
||||
$storedFile = Application_Model_StoredFile::RecallById($id, $con);
|
||||
$storedFile->delete();
|
||||
} else {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static function validateFileArray(&$fileArray)
|
||||
{
|
||||
// Sanitize any wildly incorrect metadata before it goes to be validated
|
||||
FileDataHelper::sanitizeData($fileArray);
|
||||
|
||||
// EditAudioMD form is used here for validation
|
||||
$fileForm = new Application_Form_EditAudioMD();
|
||||
$fileForm->startForm(0); //The file ID doesn't matter here
|
||||
$fileForm->populate($fileArray);
|
||||
|
||||
/*
|
||||
* Here we are truncating metadata of any characters greater than the
|
||||
* max string length set in the database. In the rare case a track's
|
||||
* genre is more than 64 chars, for example, we don't want to reject
|
||||
* tracks for that reason
|
||||
*/
|
||||
foreach($fileArray as $tag => &$value) {
|
||||
if ($fileForm->getElement($tag)) {
|
||||
$stringLengthValidator = $fileForm->getElement($tag)->getValidator('StringLength');
|
||||
//$stringLengthValidator will be false if the StringLength validator doesn't exist on the current element
|
||||
//in which case we don't have to truncate the extra characters
|
||||
if ($stringLengthValidator) {
|
||||
$value = substr($value, 0, $stringLengthValidator->getMax());
|
||||
}
|
||||
|
||||
$value = self::stripInvalidUtf8Characters($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fileForm->isValidPartial($fileArray)) {
|
||||
$errors = $fileForm->getErrors();
|
||||
$messages = $fileForm->getMessages();
|
||||
Logging::error($messages);
|
||||
throw new Exception("Data validation failed: $errors - $messages");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function getCueLength()
|
||||
{
|
||||
$cuein = $this->getDbCuein();
|
||||
$cueout = $this->getDbCueout();
|
||||
|
@ -57,7 +353,7 @@ class CcFiles extends BaseCcFiles {
|
|||
/**
|
||||
*
|
||||
* Strips out the private fields we do not want to send back in API responses
|
||||
* @param $file a CcFiles object
|
||||
* @param $file string a CcFiles object
|
||||
*/
|
||||
//TODO: rename this function?
|
||||
public static function sanitizeResponse($file)
|
||||
|
@ -70,7 +366,7 @@ class CcFiles extends BaseCcFiles {
|
|||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the file size in bytes.
|
||||
*/
|
||||
|
@ -78,13 +374,14 @@ class CcFiles extends BaseCcFiles {
|
|||
{
|
||||
return $this->getDbFilesize();
|
||||
}
|
||||
|
||||
|
||||
public function getFilename()
|
||||
{
|
||||
$info = pathinfo($this->getAbsoluteFilePath());
|
||||
return $info['filename'];
|
||||
//filename doesn't contain the extension because PHP is awful
|
||||
return $info['filename'].".".$info['extension'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the file's absolute file path stored on disk.
|
||||
*/
|
||||
|
@ -92,7 +389,7 @@ class CcFiles extends BaseCcFiles {
|
|||
{
|
||||
return $this->getAbsoluteFilePath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the file's absolute file path stored on disk.
|
||||
*/
|
||||
|
@ -100,14 +397,93 @@ class CcFiles extends BaseCcFiles {
|
|||
{
|
||||
$music_dir = Application_Model_MusicDir::getDirByPK($this->getDbDirectory());
|
||||
if (!$music_dir) {
|
||||
throw new Exception("Invalid music_dir for file in database.");
|
||||
throw new Exception("Invalid music_dir for file " . $this->getDbId() . " in database.");
|
||||
}
|
||||
$directory = $music_dir->getDirectory();
|
||||
$filepath = $this->getDbFilepath();
|
||||
|
||||
return Application_Common_OsPath::join($directory, $filepath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Strips out fields from incoming request data that should never be modified
|
||||
* from outside of Airtime
|
||||
* @param array $data
|
||||
*/
|
||||
private static function removeBlacklistedFields($data)
|
||||
{
|
||||
foreach (self::$blackList as $key) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
private static function getOwnerId()
|
||||
{
|
||||
try {
|
||||
if (Zend_Auth::getInstance()->hasIdentity()) {
|
||||
$service_user = new Application_Service_UserService();
|
||||
return $service_user->getCurrentUser()->getDbId();
|
||||
} else {
|
||||
$defaultOwner = CcSubjsQuery::create()
|
||||
->filterByDbType('A')
|
||||
->orderByDbId()
|
||||
->findOne();
|
||||
if (!$defaultOwner) {
|
||||
// what to do if there is no admin user?
|
||||
// should we handle this case?
|
||||
return null;
|
||||
}
|
||||
return $defaultOwner->getDbId();
|
||||
}
|
||||
} catch(Exception $e) {
|
||||
Logging::info($e->getMessage());
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It's possible that the year tag will be a timestamp but Airtime doesn't support this.
|
||||
* The year field in cc_files can only be 16 chars max.
|
||||
*
|
||||
* This functions strips the year field of it's timestamp, if one, and leaves just the year
|
||||
*/
|
||||
private static function stripTimeStampFromYearTag($metadata)
|
||||
{
|
||||
if (isset($metadata["year"])) {
|
||||
if (preg_match("/^(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{2}):(\d{2}):(\d{2}))?$/", $metadata["year"])) {
|
||||
$metadata["year"] = substr($metadata["year"], 0, 4);
|
||||
}
|
||||
}
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
private static function stripInvalidUtf8Characters($string)
|
||||
{
|
||||
//Remove invalid UTF-8 characters
|
||||
//reject overly long 2 byte sequences, as well as characters above U+10000 and replace with ?
|
||||
$string = preg_replace('/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'.
|
||||
'|[\x00-\x7F][\x80-\xBF]+'.
|
||||
'|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'.
|
||||
'|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'.
|
||||
'|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
|
||||
'?', $string );
|
||||
|
||||
//reject overly long 3 byte sequences and UTF-16 surrogates and replace with ?
|
||||
$string = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]'.
|
||||
'|\xED[\xA0-\xBF][\x80-\xBF]/S','?', $string );
|
||||
|
||||
//Do a final encoding conversion to
|
||||
$string = mb_convert_encoding($string, 'UTF-8', 'UTF-8');
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function removeEmptySubFolders($path)
|
||||
{
|
||||
exec("find $path -empty -type d -delete");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the file is a regular file that can be previewed and downloaded.
|
||||
*/
|
||||
|
|
|
@ -5,6 +5,9 @@ require_once 'ProxyStorageBackend.php';
|
|||
/**
|
||||
* Skeleton subclass for representing a row from the 'cloud_file' table.
|
||||
*
|
||||
* This class uses Propel's delegation feature to virtually inherit from CcFile!
|
||||
* You can call any CcFile method on this function and it will work! -- Albert
|
||||
*
|
||||
* Each cloud_file has a corresponding cc_file referenced as a foreign key.
|
||||
* The file's metadata is stored in the cc_file table. This, cloud_file,
|
||||
* table represents files that are stored in the cloud.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue