JI-1062 Add interface function for saving files from .h5p
Make it easier for plugins to override the unpacking of the package files.pull/58/head
parent
d38b3b1e8a
commit
366d8f2a0b
|
@ -357,15 +357,14 @@ class H5PDefaultStorage implements \H5PFileStorage {
|
||||||
* content from the current temporary upload folder to the editor path.
|
* content from the current temporary upload folder to the editor path.
|
||||||
*
|
*
|
||||||
* @param string $source path to source directory
|
* @param string $source path to source directory
|
||||||
* @param string $contentId Id of content
|
* @param string $contentId Id of contentarray
|
||||||
*
|
|
||||||
* @return object Object containing h5p json and content json data
|
|
||||||
*/
|
*/
|
||||||
public function moveContentDirectory($source, $contentId = NULL) {
|
public function moveContentDirectory($source, $contentId = NULL) {
|
||||||
if ($source === NULL) {
|
if ($source === NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove $contentId and never copy temporary files into content folder. JI-366
|
||||||
if ($contentId === NULL || $contentId == 0) {
|
if ($contentId === NULL || $contentId == 0) {
|
||||||
$target = $this->getEditorPath();
|
$target = $this->getEditorPath();
|
||||||
}
|
}
|
||||||
|
@ -385,14 +384,7 @@ class H5PDefaultStorage implements \H5PFileStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Successfully loaded content json of file into editor
|
// TODO: Return list of all files so that they can be marked as temporary. JI-366
|
||||||
$h5pJson = $this->getContent($source . DIRECTORY_SEPARATOR . 'h5p.json');
|
|
||||||
$contentJson = $this->getContent($contentSource . DIRECTORY_SEPARATOR . 'content.json');
|
|
||||||
|
|
||||||
return (object) array(
|
|
||||||
'h5pJson' => $h5pJson,
|
|
||||||
'contentJson' => $contentJson
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -476,6 +468,26 @@ class H5PDefaultStorage implements \H5PFileStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the given stream into the given file.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param string $file
|
||||||
|
* @param resource $stream
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveFileFromZip($path, $file, $stream) {
|
||||||
|
$filePath = $path . '/' . $file;
|
||||||
|
|
||||||
|
// Make sure the directory exists first
|
||||||
|
$matches = array();
|
||||||
|
preg_match('/(.+)\/[^\/]*$/', $filePath, $matches);
|
||||||
|
self::dirReady($matches[1]);
|
||||||
|
|
||||||
|
// Store in local storage folder
|
||||||
|
return file_put_contents($filePath, $stream);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursive function for copying directories.
|
* Recursive function for copying directories.
|
||||||
*
|
*
|
||||||
|
|
|
@ -209,4 +209,14 @@ interface H5PFileStorage {
|
||||||
* @return string Relative path
|
* @return string Relative path
|
||||||
*/
|
*/
|
||||||
public function getUpgradeScript($machineName, $majorVersion, $minorVersion);
|
public function getUpgradeScript($machineName, $majorVersion, $minorVersion);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the given stream into the given file.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param string $file
|
||||||
|
* @param resource $stream
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveFileFromZip($path, $file, $stream);
|
||||||
}
|
}
|
||||||
|
|
357
h5p.classes.php
357
h5p.classes.php
|
@ -755,6 +755,12 @@ class H5PValidator {
|
||||||
// Check dependencies, make sure Zip is present
|
// Check dependencies, make sure Zip is present
|
||||||
if (!class_exists('ZipArchive')) {
|
if (!class_exists('ZipArchive')) {
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Your PHP version does not support ZipArchive.'), 'zip-archive-unsupported');
|
$this->h5pF->setErrorMessage($this->h5pF->t('Your PHP version does not support ZipArchive.'), 'zip-archive-unsupported');
|
||||||
|
unlink($tmpPath);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!extension_loaded('mbstring')) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
|
||||||
|
unlink($tmpPath);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,153 +771,220 @@ class H5PValidator {
|
||||||
// Only allow files with the .h5p extension:
|
// Only allow files with the .h5p extension:
|
||||||
if (strtolower(substr($tmpPath, -3)) !== 'h5p') {
|
if (strtolower(substr($tmpPath, -3)) !== 'h5p') {
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('The file you uploaded is not a valid HTML5 Package (It does not have the .h5p file extension)'), 'missing-h5p-extension');
|
$this->h5pF->setErrorMessage($this->h5pF->t('The file you uploaded is not a valid HTML5 Package (It does not have the .h5p file extension)'), 'missing-h5p-extension');
|
||||||
H5PCore::deleteFileTree($tmpDir);
|
unlink($tmpPath);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract and then remove the package file.
|
// Extract and then remove the package file.
|
||||||
$zip = new ZipArchive;
|
$zip = new ZipArchive;
|
||||||
|
|
||||||
if ($zip->open($tmpPath) === true) {
|
// Open the package
|
||||||
|
if ($zip->open($tmpPath) !== TRUE) {
|
||||||
if (!empty($this->h5pC->maxFileSize) || !empty($this->h5pC->maxTotalSize)) {
|
|
||||||
// We need to check the size of the files inside the zip before continuing
|
|
||||||
|
|
||||||
$total_size = 0;
|
|
||||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
||||||
$file_size = $zip->statIndex($i)['size'];
|
|
||||||
if (!empty($this->h5pC->maxFileSize) && $file_size > $this->h5pC->maxFileSize) {
|
|
||||||
// Error file is too large
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('One of the files inside the package exceeds the maximum file size allowed.'), 'file-size-too-large');
|
|
||||||
H5PCore::deleteFileTree($tmpDir);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
$total_size += $file_size;
|
|
||||||
}
|
|
||||||
if (!empty($this->h5pC->maxTotalSize) && $total_size > $this->h5pC->maxTotalSize) {
|
|
||||||
// Error total size of the zip is too large
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('The total size of the unpacked file exceeds the maximum size allowed.'), 'total-size-too-large');
|
|
||||||
H5PCore::deleteFileTree($tmpDir);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$zip->extractTo($tmpDir);
|
|
||||||
$zip->close();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('The file you uploaded is not a valid HTML5 Package (We are unable to unzip it)'), 'unable-to-unzip');
|
$this->h5pF->setErrorMessage($this->h5pF->t('The file you uploaded is not a valid HTML5 Package (We are unable to unzip it)'), 'unable-to-unzip');
|
||||||
H5PCore::deleteFileTree($tmpDir);
|
unlink($tmpPath);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
unlink($tmpPath);
|
|
||||||
|
|
||||||
// Process content and libraries
|
if ($this->h5pC->disableFileCheck !== TRUE) {
|
||||||
|
list($contentWhitelist, $contentRegExp) = $this->getWhitelistRegExp(FALSE);
|
||||||
|
list($libraryWhitelist, $libraryRegExp) = $this->getWhitelistRegExp(TRUE);
|
||||||
|
}
|
||||||
|
$canInstall = $this->h5pC->mayUpdateLibraries();
|
||||||
|
|
||||||
$valid = TRUE;
|
$valid = TRUE;
|
||||||
$libraries = array();
|
$libraries = array();
|
||||||
$files = scandir($tmpDir);
|
|
||||||
$mainH5pData = null;
|
|
||||||
$libraryJsonData = null;
|
|
||||||
$contentJsonData = null;
|
|
||||||
$mainH5pExists = $contentExists = FALSE;
|
|
||||||
foreach ($files as $file) {
|
|
||||||
if (in_array(substr($file, 0, 1), array('.', '_'))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$filePath = $tmpDir . DIRECTORY_SEPARATOR . $file;
|
|
||||||
// Check for h5p.json file.
|
|
||||||
if (strtolower($file) == 'h5p.json') {
|
|
||||||
if ($skipContent === TRUE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$mainH5pData = $this->getJsonData($filePath);
|
$totalSize = 0;
|
||||||
if ($mainH5pData === FALSE) {
|
$mainH5pExists = FALSE;
|
||||||
|
$contentExists = FALSE;
|
||||||
|
|
||||||
|
// Check for valid file types, JSON files + file sizes before continuing to unpack.
|
||||||
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||||
|
$fileStat = $zip->statIndex($i);
|
||||||
|
|
||||||
|
if (!empty($this->h5pC->maxFileSize) && $fileStat['size'] > $this->h5pC->maxFileSize) {
|
||||||
|
// Error file is too large
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('One of the files inside the package exceeds the maximum file size allowed. (%file %used > %max)', array('%file' => $fileStat['name'], '%used' => ($fileStat['size'] / 1048576) . ' MB', '%max' => ($this->h5pC->maxFileSize / 1048576) . ' MB')), 'file-size-too-large');
|
||||||
|
$valid = FALSE;
|
||||||
|
}
|
||||||
|
$totalSize += $fileStat['size'];
|
||||||
|
|
||||||
|
$fileName = mb_strtolower($fileStat['name']);
|
||||||
|
if (preg_match('/(^[\._]|\/[\._])/', $fileName) !== 0) {
|
||||||
|
continue; // Skip any file or folder starting with a . or _
|
||||||
|
}
|
||||||
|
elseif ($fileName === 'h5p.json') {
|
||||||
|
$mainH5pExists = TRUE;
|
||||||
|
}
|
||||||
|
elseif ($fileName === 'content/content.json') {
|
||||||
|
$contentExists = TRUE;
|
||||||
|
}
|
||||||
|
elseif (substr($fileName, 0, 8) === 'content/') {
|
||||||
|
// This is a content file, check that the file type is allowed
|
||||||
|
if ($skipContent === FALSE && $this->h5pC->disableFileCheck !== TRUE && !preg_match($contentRegExp, $fileName)) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $fileStat['name'], '%files-allowed' => $contentWhitelist)), 'not-in-whitelist');
|
||||||
$valid = FALSE;
|
$valid = FALSE;
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Could not parse the main h5p.json file'), 'invalid-h5p-json-file');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$validH5p = $this->isValidH5pData($mainH5pData, $file, $this->h5pRequired, $this->h5pOptional);
|
|
||||||
if ($validH5p) {
|
|
||||||
$mainH5pExists = TRUE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$valid = FALSE;
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('The main h5p.json file is not valid'), 'invalid-h5p-json-file');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Content directory holds content.
|
elseif ($canInstall && strpos($fileName, '/') !== FALSE) {
|
||||||
elseif ($file == 'content') {
|
// This is a library file, check that the file type is allowed
|
||||||
// We do a separate skipContent check to avoid having the content folder being treated as a library
|
if ($this->h5pC->disableFileCheck !== TRUE && !preg_match($libraryRegExp, $fileName)) {
|
||||||
if ($skipContent) {
|
$this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $fileStat['name'], '%files-allowed' => $libraryWhitelist)), 'not-in-whitelist');
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!is_dir($filePath)) {
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Invalid content folder'), 'invalid-content-folder');
|
|
||||||
$valid = FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$contentJsonData = $this->getJsonData($filePath . DIRECTORY_SEPARATOR . 'content.json');
|
|
||||||
if ($contentJsonData === FALSE) {
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Could not find or parse the content.json file'), 'invalid-content-json-file');
|
|
||||||
$valid = FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$contentExists = TRUE;
|
|
||||||
// In the future we might let the libraries provide validation functions for content.json
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->h5pCV->validateContentFiles($filePath)) {
|
|
||||||
// validateContentFiles adds potential errors to the queue
|
|
||||||
$valid = FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The rest should be library folders
|
|
||||||
elseif ($this->h5pC->mayUpdateLibraries()) {
|
|
||||||
if (!is_dir($filePath)) {
|
|
||||||
// Ignore this. Probably a file that shouldn't have been included.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$libraryH5PData = $this->getLibraryData($file, $filePath, $tmpDir);
|
|
||||||
|
|
||||||
if ($libraryH5PData !== FALSE) {
|
|
||||||
// Library's directory name must be:
|
|
||||||
// - <machineName>
|
|
||||||
// - or -
|
|
||||||
// - <machineName>-<majorVersion>.<minorVersion>
|
|
||||||
// where machineName, majorVersion and minorVersion is read from library.json
|
|
||||||
if ($libraryH5PData['machineName'] !== $file && H5PCore::libraryToString($libraryH5PData, TRUE) !== $file) {
|
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('Library directory name must match machineName or machineName-majorVersion.minorVersion (from library.json). (Directory: %directoryName , machineName: %machineName, majorVersion: %majorVersion, minorVersion: %minorVersion)', array(
|
|
||||||
'%directoryName' => $file,
|
|
||||||
'%machineName' => $libraryH5PData['machineName'],
|
|
||||||
'%majorVersion' => $libraryH5PData['majorVersion'],
|
|
||||||
'%minorVersion' => $libraryH5PData['minorVersion'])), 'library-directory-name-mismatch');
|
|
||||||
$valid = FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$libraryH5PData['uploadDirectory'] = $filePath;
|
|
||||||
$libraries[H5PCore::libraryToString($libraryH5PData)] = $libraryH5PData;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$valid = FALSE;
|
$valid = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Further library validation happens after the files are extracted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($this->h5pC->maxTotalSize) && $totalSize > $this->h5pC->maxTotalSize) {
|
||||||
|
// Error total size of the zip is too large
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('The total size of the unpacked files exceeds the maximum size allowed. (%used > %max)', array('%used' => ($totalSize / 1048576) . ' MB', '%max' => ($this->h5pC->maxTotalSize / 1048576) . ' MB')), 'total-size-too-large');
|
||||||
|
$valid = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if ($skipContent === FALSE) {
|
if ($skipContent === FALSE) {
|
||||||
|
// Not skipping content, require two valid JSON files from the package
|
||||||
if (!$contentExists) {
|
if (!$contentExists) {
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('A valid content folder is missing'), 'invalid-content-folder');
|
$this->h5pF->setErrorMessage($this->h5pF->t('A valid content folder is missing'), 'invalid-content-folder');
|
||||||
$valid = FALSE;
|
$valid = FALSE;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$contentJsonData = $this->getJson($tmpPath, $zip, 'content/content.json'); // TODO: Is this case-senstivie?
|
||||||
|
if ($contentJsonData === NULL) {
|
||||||
|
return FALSE; // Breaking error when reading from the archive.
|
||||||
|
}
|
||||||
|
elseif ($contentJsonData === FALSE) {
|
||||||
|
$valid = FALSE; // Validation error when parsing JSON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$mainH5pExists) {
|
if (!$mainH5pExists) {
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('A valid main h5p.json file is missing'), 'invalid-h5p-json-file');
|
$this->h5pF->setErrorMessage($this->h5pF->t('A valid main h5p.json file is missing'), 'invalid-h5p-json-file');
|
||||||
$valid = FALSE;
|
$valid = FALSE;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$mainH5pData = $this->getJson($tmpPath, $zip, 'h5p.json');
|
||||||
|
if ($mainH5pData === NULL) {
|
||||||
|
return FALSE; // Breaking error when reading from the archive.
|
||||||
|
}
|
||||||
|
elseif ($mainH5pData === FALSE) {
|
||||||
|
$valid = FALSE; // Validation error when parsing JSON
|
||||||
|
}
|
||||||
|
elseif (!$this->isValidH5pData($mainH5pData, 'h5p.json', $this->h5pRequired, $this->h5pOptional)) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('The main h5p.json file is not valid'), 'invalid-h5p-json-file'); // Is this message a bit redundant?
|
||||||
|
$valid = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$valid) {
|
||||||
|
// If something has failed during the initial checks of the package
|
||||||
|
// we will not unpack it or continue validation.
|
||||||
|
$zip->close();
|
||||||
|
unlink($tmpPath);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the files from the package
|
||||||
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||||
|
$fileName = $zip->statIndex($i)['name'];
|
||||||
|
|
||||||
|
if (preg_match('/(^[\._]|\/[\._])/', $fileName) !== 0) {
|
||||||
|
continue; // Skip any file or folder starting with a . or _
|
||||||
|
}
|
||||||
|
|
||||||
|
$isContentFile = (substr($fileName, 0, 8) === 'content/');
|
||||||
|
$isFolder = (strpos($fileName, '/') !== FALSE);
|
||||||
|
|
||||||
|
if ($skipContent !== FALSE && $isContentFile) {
|
||||||
|
continue; // Skipping any content files
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($isContentFile || ($canInstall && $isFolder))) {
|
||||||
|
continue; // Not something we want to unpack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get file stream
|
||||||
|
$fileStream = $zip->getStream($fileName);
|
||||||
|
if (!$fileStream) {
|
||||||
|
// This is a breaking error, there's no need to continue. (the rest of the files will fail as well)
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('Unable to read file from the package: %fileName', array('%fileName' => $fileName)), 'unable-to-read-package-file');
|
||||||
|
$zip->close();
|
||||||
|
unlink($path);
|
||||||
|
H5PCore::deleteFileTree($tmpDir);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use file interface to allow overrides
|
||||||
|
$this->h5pC->fs->saveFileFromZip($tmpDir, $fileName, $fileStream);
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
if (is_resource($fileStream)) {
|
||||||
|
fclose($fileStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're done with the zip file, clean up the stuff
|
||||||
|
$zip->close();
|
||||||
|
unlink($tmpPath);
|
||||||
|
|
||||||
|
if ($canInstall) {
|
||||||
|
// Process and validate libraries using the unpacked library folders
|
||||||
|
$files = scandir($tmpDir);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$filePath = $tmpDir . DIRECTORY_SEPARATOR . $file;
|
||||||
|
|
||||||
|
if ($file === '.' || $file === '..' || $file === 'content' || !is_dir($filePath)) {
|
||||||
|
continue; // Skip
|
||||||
|
}
|
||||||
|
|
||||||
|
$libraryH5PData = $this->getLibraryData($file, $filePath, $tmpDir);
|
||||||
|
if ($libraryH5PData === FALSE) {
|
||||||
|
$valid = FALSE;
|
||||||
|
continue; // Failed, but continue validating the rest of the libraries
|
||||||
|
}
|
||||||
|
|
||||||
|
// Library's directory name must be:
|
||||||
|
// - <machineName>
|
||||||
|
// - or -
|
||||||
|
// - <machineName>-<majorVersion>.<minorVersion>
|
||||||
|
// where machineName, majorVersion and minorVersion is read from library.json
|
||||||
|
if ($libraryH5PData['machineName'] !== $file && H5PCore::libraryToString($libraryH5PData, TRUE) !== $file) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('Library directory name must match machineName or machineName-majorVersion.minorVersion (from library.json). (Directory: %directoryName , machineName: %machineName, majorVersion: %majorVersion, minorVersion: %minorVersion)', array(
|
||||||
|
'%directoryName' => $file,
|
||||||
|
'%machineName' => $libraryH5PData['machineName'],
|
||||||
|
'%majorVersion' => $libraryH5PData['majorVersion'],
|
||||||
|
'%minorVersion' => $libraryH5PData['minorVersion'])), 'library-directory-name-mismatch');
|
||||||
|
$valid = FALSE;
|
||||||
|
continue; // Failed, but continue validating the rest of the libraries
|
||||||
|
}
|
||||||
|
|
||||||
|
$libraryH5PData['uploadDirectory'] = $filePath;
|
||||||
|
$libraries[H5PCore::libraryToString($libraryH5PData)] = $libraryH5PData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the data from h5p.json
|
||||||
|
if ($skipContent === FALSE) {
|
||||||
|
$frameworkValidation = $this->h5pF->validateLibrary($mainH5pData);
|
||||||
|
if (!$frameworkValidation->valid) {
|
||||||
|
$message = $this->h5pF->t('Validation of the main library failed.');
|
||||||
|
$code = null;
|
||||||
|
|
||||||
|
if (isset($frameworkValidation->message)) {
|
||||||
|
$message = $frameworkValidation->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($frameworkValidation->code)) {
|
||||||
|
$code = $frameworkValidation->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->h5pF->setErrorMessage($message, $code);
|
||||||
|
$valid = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
if ($upgradeOnly) {
|
if ($upgradeOnly) {
|
||||||
// When upgrading, we only add the already installed libraries, and
|
// When upgrading, we only add the already installed libraries, and
|
||||||
|
@ -982,6 +1055,54 @@ class H5PValidator {
|
||||||
return $valid;
|
return $valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Help read JSON from the archive
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param ZipArchive $zip
|
||||||
|
* @param string $file
|
||||||
|
* @return mixed JSON content if valid, FALSE for invalid, NULL for breaking error.
|
||||||
|
*/
|
||||||
|
private function getJson($path, $zip, $file) {
|
||||||
|
// Get stream
|
||||||
|
$stream = $zip->getStream($file);
|
||||||
|
if (!$stream) {
|
||||||
|
// Breaking error, no need to continue validating.
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('Unable to read file from the package: %fileName', array('%fileName' => $file)), 'unable-to-read-package-file');
|
||||||
|
$zip->close();
|
||||||
|
unlink($path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read data
|
||||||
|
$contents = '';
|
||||||
|
while (!feof($stream)) {
|
||||||
|
$contents .= fread($stream, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the data
|
||||||
|
$json = json_decode($contents, TRUE);
|
||||||
|
if ($json === NULL) {
|
||||||
|
// JSON cannot be decoded or the recursion limit has been reached.
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('Unable to parse JSON from the package: %fileName', array('%fileName' => $file)), 'unable-to-parse-package');
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All OK
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Help retrieve file type regexp whitelist from plugin.
|
||||||
|
*
|
||||||
|
* @param bool $isLibrary Separate list with more allowed file types
|
||||||
|
* @return string RegExp
|
||||||
|
*/
|
||||||
|
private function getWhitelistRegExp($isLibrary) {
|
||||||
|
$whitelist = $this->h5pF->getWhitelist($isLibrary, H5PCore::$defaultContentWhitelist, H5PCore::$defaultLibraryWhitelistExtras);
|
||||||
|
return array($whitelist, '/\.(' . preg_replace('/ +/i', '|', preg_quote($whitelist)) . ')$/i');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a H5P library
|
* Validates a H5P library
|
||||||
*
|
*
|
||||||
|
@ -1046,7 +1167,7 @@ class H5PValidator {
|
||||||
|
|
||||||
$validLibrary = $this->isValidH5pData($h5pData, $file, $this->libraryRequired, $this->libraryOptional);
|
$validLibrary = $this->isValidH5pData($h5pData, $file, $this->libraryRequired, $this->libraryOptional);
|
||||||
|
|
||||||
$validLibrary = $this->h5pCV->validateContentFiles($filePath, TRUE) && $validLibrary;
|
//$validLibrary = $this->h5pCV->validateContentFiles($filePath, TRUE) && $validLibrary;
|
||||||
|
|
||||||
if (isset($h5pData['preloadedJs'])) {
|
if (isset($h5pData['preloadedJs'])) {
|
||||||
$validLibrary = $this->isExistingFiles($h5pData['preloadedJs'], $tmpDir, $file) && $validLibrary;
|
$validLibrary = $this->isExistingFiles($h5pData['preloadedJs'], $tmpDir, $file) && $validLibrary;
|
||||||
|
|
Loading…
Reference in New Issue