2012-11-21 14:14:07 +01:00
< ? php
2013-01-14 23:47:50 +01:00
/**
* Interface defining functions the h5p library needs the framework to implement
*/
2013-02-17 15:39:26 +01:00
interface H5PFrameworkInterface {
2013-01-14 23:47:50 +01:00
/**
* Show the user an error message
*
* @ param string $message
* The error message
*/
2012-11-22 14:00:06 +01:00
public function setErrorMessage ( $message );
2013-01-14 23:47:50 +01:00
/**
* Show the user an information message
*
* @ param string $message
* The error message
*/
2012-11-22 14:00:06 +01:00
public function setInfoMessage ( $message );
2013-01-14 23:47:50 +01:00
/**
* Translation function
*
* @ param string $message
* The english string to be translated .
* @ param type $replacements
* An associative array of replacements to make after translation . Incidences
* of any key in this array are replaced with the corresponding value . Based
* on the first character of the key , the value is escaped and / or themed :
* - ! variable : inserted as is
* - @ variable : escape plain text to HTML
* - % variable : escape text and theme as a placeholder for user - submitted
* content
* @ return string Translated string
*/
2012-12-03 00:19:25 +01:00
public function t ( $message , $replacements = array ());
2013-01-14 23:47:50 +01:00
/**
* Get the Path to the last uploaded h5p
*
* @ return string Path to the folder where the last uploaded h5p for this session is located .
*/
2012-11-30 15:51:39 +01:00
public function getUploadedH5pFolderPath ();
2013-01-14 23:47:50 +01:00
/**
* @ return string Path to the folder where all h5p files are stored
*/
2012-11-30 15:51:39 +01:00
public function getH5pPath ();
2013-01-14 23:47:50 +01:00
/**
* Get the path to the last uploaded h5p file
*
* @ return string Path to the last uploaded h5p
*/
2012-11-22 14:00:06 +01:00
public function getUploadedH5pPath ();
2013-01-14 23:47:50 +01:00
/**
* Get id to an excisting library
*
2013-03-07 12:34:29 +01:00
* @ param string $name
2013-01-14 23:47:50 +01:00
* The librarys machine name
* @ param int $majorVersion
* The librarys major version
* @ param int $minorVersion
* The librarys minor version
* @ return int
* The id of the specified library or FALSE
*/
2013-03-07 12:34:29 +01:00
public function getLibraryId ( $name , $majorVersion , $minorVersion );
2013-01-14 23:47:50 +01:00
/**
* Is the library a patched version of an excisting library ?
*
* @ param object $library
* The library data for a library we are checking
* @ return boolean
* TRUE if the library is a patched version of an excisting library
* FALSE otherwise
*/
2012-12-22 06:35:16 +01:00
public function isPatchedLibrary ( $library );
2013-01-14 23:47:50 +01:00
/**
* Store data about a library
*
* Also fills in the libraryId in the libraryData object if the object is new
*
* @ param object $libraryData
* Object holding the information that is to be stored
*/
2013-02-17 14:05:02 +01:00
public function saveLibraryData ( & $libraryData );
2013-01-14 23:47:50 +01:00
/**
2013-02-15 11:38:49 +01:00
* Stores contentData
2013-01-14 23:47:50 +01:00
*
* @ param int $contentId
* Framework specific id identifying the content
* @ param string $contentJson
* The content data that is to be stored
* @ param array $mainJsonData
* The data extracted from the h5p . json file
* @ param int $contentMainId
* Any contentMainId defined by the framework , for instance to support revisioning
*/
2013-03-07 04:12:59 +01:00
public function saveContentData ( $contentId , $contentJson , $mainJsonData , $mainLibraryId , $contentMainId = NULL );
2013-02-15 11:38:49 +01:00
/**
2013-03-07 05:31:30 +01:00
* Copies library usage
2013-02-15 11:38:49 +01:00
*
* @ param int $contentId
* Framework specific id identifying the content
* @ param int $copyFromId
* Framework specific id identifying the content to be copied
* @ param int $contentMainId
* Framework specific main id for the content , typically used in frameworks
* That supports versioning . ( In this case the content id will typically be
* the version id , and the contentMainId will be the frameworks content id
*/
2013-03-07 05:31:30 +01:00
public function copyLibraryUsage ( $contentId , $copyFromId , $contentMainId = NULL );
2013-02-15 11:38:49 +01:00
/**
* Deletes content data
*
* @ param int $contentId
* Framework specific id identifying the content
*/
2012-12-22 07:09:17 +01:00
public function deleteContentData ( $contentId );
2013-02-15 11:38:49 +01:00
/**
* Saves what libraries the content uses
*
* @ param int $contentId
* Framework specific id identifying the content
* @ param array $librariesInUse
* List of libraries the content uses . Libraries consist of arrays with :
* - libraryId stored in $librariesInUse [ < place > ][ 'library' ][ 'libraryId' ]
* - libraryId stored in $librariesInUse [ < place > ][ 'preloaded' ]
*/
2012-11-30 15:51:39 +01:00
public function saveLibraryUsage ( $contentId , $librariesInUse );
2013-02-15 11:38:49 +01:00
/**
* Loads a library
*
2013-03-07 12:34:29 +01:00
* @ param string $name
2013-02-15 11:38:49 +01:00
* @ param int $majorVersion
* @ param int $minorVersion
* @ return array | FALSE
* Array representing the library with dependency descriptions
* FALSE if the library doesn ' t exist
*/
2013-03-07 12:34:29 +01:00
public function loadLibrary ( $name , $majorVersion , $minorVersion );
2012-11-21 14:14:07 +01:00
}
2013-02-17 15:04:30 +01:00
class H5PValidator {
2012-11-22 14:00:06 +01:00
public $h5pF ;
2012-11-29 22:52:41 +01:00
public $h5pC ;
2013-01-16 19:39:49 +01:00
2012-11-24 01:09:25 +01:00
// Schemas used to validate the h5p files
private $h5pRequired = array (
2012-11-28 14:06:55 +01:00
'title' => '/^.{1,255}$/' ,
'language' => '/^[a-z]{1,5}$/' ,
2012-11-24 01:09:25 +01:00
'preloadedDependencies' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2012-12-04 22:26:20 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
'minorVersion' => '/^[0-9]{1,5}$/' ,
2012-11-24 01:09:25 +01:00
),
2013-03-07 12:34:29 +01:00
'library_name' => '/^[a-z0-9\-]{1,255}$/' ,
2012-11-24 01:09:25 +01:00
'embedTypes' => array ( 'iframe' , 'div' ),
);
2013-01-16 19:39:49 +01:00
2012-11-24 01:09:25 +01:00
private $h5pOptional = array (
2012-11-28 14:06:55 +01:00
'contentType' => '/^.{1,255}$/' ,
2012-12-02 21:55:51 +01:00
'description' => '/^.{1,}$/' ,
2012-11-28 14:06:55 +01:00
'author' => '/^.{1,255}$/' ,
2013-01-16 19:39:49 +01:00
'license' => '/^(cc-by|cc-by-sa|cc-by-nd|cc-by-nc|cc-by-nc-sa|cc-by-nc-nd|pd|cr|MIT)$/' ,
2012-11-24 01:09:25 +01:00
'dynamicDependencies' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2012-12-04 22:26:20 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
'minorVersion' => '/^[0-9]{1,5}$/' ,
2012-11-24 01:09:25 +01:00
),
2013-01-17 23:39:24 +01:00
'externalResources' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2013-01-17 23:39:24 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
'minorVersion' => '/^[0-9]{1,5}$/' ,
'url' => '/^http:\/\/[a-z_\-\.0-9]+\.[a-z]{2, 10}$/i' ,
'type' => '/^(css|js)$/' ,
),
2013-03-07 12:34:29 +01:00
'width' => '/^[0-9]{1,4}$/' ,
'height' => '/^[0-9]{1,4}$/' ,
'fullscreen' => 'boolean' ,
2012-12-02 21:55:51 +01:00
'metaKeywords' => '/^.{1,}$/' ,
'metaDescription' => '/^.{1,}$/k' ,
);
2013-01-14 23:47:50 +01:00
// Schemas used to validate the library files
2012-12-02 21:55:51 +01:00
private $libraryRequired = array (
'title' => '/^.{1,255}$/' ,
2012-12-04 20:56:16 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
2012-12-04 22:26:20 +01:00
'minorVersion' => '/^[0-9]{1,5}$/' ,
'patchVersion' => '/^[0-9]{1,5}$/' ,
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
'class' => '/^[a-z0-9\.]{1,255}$/i' ,
2013-01-20 16:13:11 +01:00
'runnable' => '/^(0|1)$/' ,
2012-12-02 21:55:51 +01:00
);
2013-01-16 19:39:49 +01:00
2012-12-02 21:55:51 +01:00
private $libraryOptional = array (
'author' => '/^.{1,255}$/' ,
2013-01-16 19:39:49 +01:00
'license' => '/^(cc-by|cc-by-sa|cc-by-nd|cc-by-nc|cc-by-nc-sa|cc-by-nc-nd|pd|cr|MIT)$/' ,
2012-12-02 21:55:51 +01:00
'description' => '/^.{1,}$/' ,
'dynamicDependencies' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2012-12-04 22:26:20 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
'minorVersion' => '/^[0-9]{1,5}$/' ,
2013-01-16 19:39:49 +01:00
),
2012-12-02 21:55:51 +01:00
'preloadedDependencies' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2012-12-04 22:26:20 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
2012-12-22 06:35:16 +01:00
'minorVersion' => '/^[0-9]{1,5}$/' ,
2012-12-02 21:55:51 +01:00
),
2013-02-06 17:39:45 +01:00
'editorDependencies' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2013-02-06 17:39:45 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
'minorVersion' => '/^[0-9]{1,5}$/' ,
),
2013-01-17 23:39:24 +01:00
'externalResources' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2013-01-17 23:39:24 +01:00
'majorVersion' => '/^[0-9]{1,5}$/' ,
'minorVersion' => '/^[0-9]{1,5}$/' ,
'url' => '/^http:\/\/[a-z_\-\.0-9]+\.[a-z]{2, 10}$/i' ,
'type' => '/^(css|js)$/' ,
),
2012-11-30 15:51:39 +01:00
'preloadedJs' => array (
2012-12-04 15:52:03 +01:00
'path' => '/^((\\\|\/)?[a-z_\-\s0-9]+)+\.js$/i' ,
2012-11-30 15:51:39 +01:00
),
'preloadedCss' => array (
2012-12-04 15:52:03 +01:00
'path' => '/^((\\\|\/)?[a-z_\-\s0-9]+)+\.css$/i' ,
2012-11-30 15:51:39 +01:00
),
2013-02-28 20:06:18 +01:00
'dropLibraryCss' => array (
2013-03-07 12:34:29 +01:00
'name' => '/^[a-z0-9\-]{1,255}$/' ,
2013-02-28 20:06:18 +01:00
),
2013-03-07 12:34:29 +01:00
'width' => '/^[0-9]{1,4}$/' ,
'height' => '/^[0-9]{1,4}$/' ,
'fullscreen' => 'boolean' ,
2012-12-02 21:55:51 +01:00
'embedTypes' => array ( 'iframe' , 'div' ),
2012-11-24 01:09:25 +01:00
);
2012-11-22 14:00:06 +01:00
2012-11-29 15:41:06 +01:00
/**
2013-02-17 15:04:30 +01:00
* Constructor for the H5PValidator
2012-11-29 15:41:06 +01:00
*
2013-02-17 15:04:30 +01:00
* @ param object $H5PFramework
2013-02-17 15:39:26 +01:00
* The frameworks implementation of the H5PFrameworkInterface
2012-11-29 15:41:06 +01:00
*/
2013-02-17 15:04:30 +01:00
public function __construct ( $H5PFramework , $H5PCore ) {
$this -> h5pF = $H5PFramework ;
$this -> h5pC = $H5PCore ;
2012-11-22 14:00:06 +01:00
}
2012-11-29 15:41:06 +01:00
/**
* Validates a . h5p file
*
* @ return boolean
* TRUE if the . h5p file is valid
*/
2012-11-30 15:51:39 +01:00
public function isValidPackage () {
2012-11-22 14:00:06 +01:00
// Create a temporary dir to extract package in.
2012-12-03 00:19:25 +01:00
$tmp_dir = $this -> h5pF -> getUploadedH5pFolderPath ();
$tmp_path = $this -> h5pF -> getUploadedH5pPath ();
2012-11-22 14:00:06 +01:00
2012-11-28 15:21:34 +01:00
$valid = TRUE ;
2012-11-22 14:00:06 +01:00
// Extract and then remove the package file.
2012-12-03 00:19:25 +01:00
$zip = new ZipArchive ;
if ( $zip -> open ( $tmp_path ) === true ) {
$zip -> extractTo ( $tmp_dir );
$zip -> close ();
}
else {
2013-02-28 20:06:18 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'The file you uploaded is not a valid HTML5 Package.' ));
2012-12-22 06:35:16 +01:00
$this -> h5pC -> delTree ( $tmp_dir );
2012-11-22 14:00:06 +01:00
return ;
}
unlink ( $tmp_path );
// Process content and libraries
2012-11-28 15:31:55 +01:00
$libraries = array ();
2012-11-23 17:06:03 +01:00
$files = scandir ( $tmp_dir );
2012-11-29 15:41:06 +01:00
$mainH5pData ;
2012-11-30 15:51:39 +01:00
$libraryJsonData ;
2012-11-29 08:57:01 +01:00
$mainH5pExists = $imageExists = $contentExists = FALSE ;
2012-11-23 17:06:03 +01:00
foreach ( $files as $file ) {
2013-01-16 22:00:12 +01:00
if ( in_array ( substr ( $file , 0 , 1 ), array ( '.' , '_' ))) {
2012-11-23 17:06:03 +01:00
continue ;
}
$file_path = $tmp_dir . DIRECTORY_SEPARATOR . $file ;
2013-01-16 19:39:49 +01:00
// Check for h5p.json file.
2012-11-23 17:06:03 +01:00
if ( strtolower ( $file ) == 'h5p.json' ) {
2012-11-29 15:41:06 +01:00
$mainH5pData = $this -> getJsonData ( $file_path );
if ( $mainH5pData === FALSE ) {
2012-11-29 08:51:36 +01:00
$valid = FALSE ;
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Could not find or parse the main h5p.json file' ));
2012-11-29 08:51:36 +01:00
}
else {
2012-11-29 15:41:06 +01:00
$validH5p = $this -> isValidH5pData ( $mainH5pData , $file , $this -> h5pRequired , $this -> h5pOptional );
2012-11-29 08:51:36 +01:00
if ( $validH5p ) {
$mainH5pExists = TRUE ;
}
else {
$valid = FALSE ;
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Could not find or parse the main h5p.json file' ));
2012-11-29 08:51:36 +01:00
}
}
2012-11-23 17:06:03 +01:00
}
2013-01-16 19:39:49 +01:00
// Check for h5p.jpg?
2012-11-23 17:06:03 +01:00
elseif ( strtolower ( $file ) == 'h5p.jpg' ) {
2012-11-29 08:57:01 +01:00
$imageExists = TRUE ;
2012-11-23 17:06:03 +01:00
}
2013-01-16 19:39:49 +01:00
// Content directory holds content.
2012-11-23 17:06:03 +01:00
elseif ( $file == 'content' ) {
2012-12-22 06:35:16 +01:00
if ( ! is_dir ( $file_path )) {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Invalid content folder' ));
$valid = FALSE ;
continue ;
}
2012-11-30 15:51:39 +01:00
$contentJsonData = $this -> getJsonData ( $file_path . DIRECTORY_SEPARATOR . 'content.json' );
if ( $contentJsonData === FALSE ) {
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Could not find or parse the content.json file' ));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
continue ;
}
2012-11-29 08:51:36 +01:00
else {
2012-11-29 08:57:01 +01:00
$contentExists = TRUE ;
2012-11-29 08:51:36 +01:00
// In the future we might let the librarys provide validation functions for content.json
2012-11-28 15:21:34 +01:00
}
2012-11-23 17:06:03 +01:00
}
2012-11-22 14:00:06 +01:00
2013-01-16 19:39:49 +01:00
// The rest should be library folders
2012-11-23 17:06:03 +01:00
else {
2012-12-22 06:35:16 +01:00
if ( ! is_dir ( $file_path )) {
2013-01-16 19:39:49 +01:00
// Ignore this. Probably a file that shouldn't have been included.
2012-12-22 06:35:16 +01:00
continue ;
}
2013-01-16 19:39:49 +01:00
if ( preg_match ( '/^[\w0-9\-\.]{1,255}$/i' , $file ) === 0 ) {
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Invalid library name: %name' , array ( '%name' => $file )));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
2012-11-22 14:00:06 +01:00
continue ;
}
2012-12-02 21:55:51 +01:00
$h5pData = $this -> getJsonData ( $file_path . DIRECTORY_SEPARATOR . 'library.json' );
2012-11-29 08:51:36 +01:00
if ( $h5pData === FALSE ) {
2012-12-02 21:55:51 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Could not find library.json file with valid json format for library %name' , array ( '%name' => $file )));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
2012-11-22 14:00:06 +01:00
continue ;
}
2013-01-25 15:14:29 +01:00
2013-01-27 23:08:48 +01:00
// validate json if a semantics file is provided
$semanticsPath = $file_path . DIRECTORY_SEPARATOR . 'semantics.json' ;
if ( file_exists ( $semanticsPath )) {
$semantics = $this -> getJsonData ( $semanticsPath , TRUE );
if ( $semantics === FALSE ) {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Invalid semantics.json file has been included in the library %name' , array ( '%name' => $file )));
2013-01-25 15:14:29 +01:00
$valid = FALSE ;
continue ;
}
else {
2013-01-27 23:08:48 +01:00
$h5pData [ 'semantics' ] = $semantics ;
2013-01-25 15:14:29 +01:00
}
}
2012-11-29 08:51:36 +01:00
2012-12-04 15:52:03 +01:00
$validLibrary = $this -> isValidH5pData ( $h5pData , $file , $this -> libraryRequired , $this -> libraryOptional );
2012-11-28 15:31:55 +01:00
2012-12-04 15:52:03 +01:00
if ( isset ( $h5pData [ 'preloadedJs' ])) {
2013-01-16 19:39:49 +01:00
$validLibrary = $this -> isExistingFiles ( $h5pData [ 'preloadedJs' ], $tmp_dir , $file ) && $validLibrary ;
2012-11-22 14:00:06 +01:00
}
2012-12-04 15:52:03 +01:00
if ( isset ( $h5pData [ 'preloadedCss' ])) {
2013-01-16 19:39:49 +01:00
$validLibrary = $this -> isExistingFiles ( $h5pData [ 'preloadedCss' ], $tmp_dir , $file ) && $validLibrary ;
2012-11-22 14:00:06 +01:00
}
2012-11-28 15:31:55 +01:00
if ( $validLibrary ) {
2012-12-22 06:35:16 +01:00
$libraries [ $file ] = $h5pData ;
2012-11-28 15:31:55 +01:00
}
$valid = $validLibrary && $valid ;
2012-11-22 14:00:06 +01:00
}
}
2012-11-29 15:41:06 +01:00
if ( ! $contentExists ) {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'A valid content folder is missing' ));
$valid = FALSE ;
}
if ( ! $mainH5pExists ) {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'A valid main h5p.json file is missing' ));
$valid = FALSE ;
}
2012-11-28 15:31:55 +01:00
if ( $valid ) {
2012-11-30 15:51:39 +01:00
$this -> h5pC -> librariesJsonData = $libraries ;
$this -> h5pC -> mainJsonData = $mainH5pData ;
$this -> h5pC -> contentJsonData = $contentJsonData ;
2012-12-22 06:35:16 +01:00
$libraries [ 'mainH5pData' ] = $mainH5pData ;
2012-11-28 23:29:22 +01:00
$missingLibraries = $this -> getMissingLibraries ( $libraries );
foreach ( $missingLibraries as $missing ) {
2013-03-07 12:34:29 +01:00
if ( $this -> h5pF -> getLibraryId ( $missing [ 'name' ], $missing [ 'majorVersion' ], $missing [ 'minorVersion' ])) {
unset ( $missingLibraries [ $missing [ 'name' ]]);
2012-11-28 23:29:22 +01:00
}
}
$valid = empty ( $missingLibraries ) && $valid ;
}
if ( ! $valid ) {
2012-12-22 06:35:16 +01:00
$this -> h5pC -> delTree ( $tmp_dir );
2012-11-28 23:29:22 +01:00
}
return $valid ;
}
2012-11-29 15:41:06 +01:00
/**
* Use the dependency declarations to find any missing libraries
*
* @ param array $libraries
2013-03-07 12:34:29 +01:00
* A multidimensional array of libraries keyed with name first and majorVersion second
2012-11-29 15:41:06 +01:00
* @ return array
2013-03-07 12:34:29 +01:00
* A list of libraries that are missing keyed with name and holds objects with
* name , majorVersion and minorVersion properties
2012-11-29 15:41:06 +01:00
*/
2012-11-28 23:29:22 +01:00
private function getMissingLibraries ( $libraries ) {
$missing = array ();
foreach ( $libraries as $library ) {
if ( isset ( $library [ 'preloadedDependencies' ])) {
array_merge ( $missing , $this -> getMissingDependencies ( $library [ 'preloadedDependencies' ], $libraries ));
}
if ( isset ( $library [ 'dynamicDependencies' ])) {
array_merge ( $missing , $this -> getMissingDependencies ( $library [ 'dynamicDependencies' ], $libraries ));
}
2013-02-08 04:38:27 +01:00
if ( isset ( $library [ 'editorDependencies' ])) {
array_merge ( $missing , $this -> getMissingDependencies ( $library [ 'editorDependencies' ], $libraries ));
}
2012-11-28 15:31:55 +01:00
}
2012-11-28 23:29:22 +01:00
return $missing ;
}
2012-11-29 15:41:06 +01:00
/**
* Helper function for getMissingLibraries , searches for dependency required libraries in
* the provided list of libraries
*
* @ param array $dependencies
2013-03-07 12:34:29 +01:00
* A list of objects with name , majorVersion and minorVersion properties
2012-11-29 15:41:06 +01:00
* @ param array $libraries
2013-03-07 12:34:29 +01:00
* An array of libraries keyed with name
2012-11-29 15:41:06 +01:00
* @ return
2013-03-07 12:34:29 +01:00
* A list of libraries that are missing keyed with name and holds objects with
* name , majorVersion and minorVersion properties
2012-11-29 15:41:06 +01:00
*/
2012-11-28 23:29:22 +01:00
private function getMissingDependencies ( $dependencies , $libraries ) {
$missing = array ();
2012-12-04 15:52:03 +01:00
foreach ( $dependencies as $dependency ) {
2013-03-07 12:34:29 +01:00
if ( isset ( $libraries [ $dependency [ 'name' ]])) {
if ( ! $this -> h5pC -> isSameVersion ( $libraries [ $dependency [ 'name' ]], $dependency )) {
$missing [ $dependency [ 'name' ]] = $dependency ;
2012-11-28 23:29:22 +01:00
}
}
else {
2013-03-07 12:34:29 +01:00
$missing [ $dependency [ 'name' ]] = $dependency ;
2012-11-28 23:29:22 +01:00
}
}
return $missing ;
2012-11-26 22:48:51 +01:00
}
2012-11-29 15:41:06 +01:00
/**
* Figure out if the provided file paths exists
*
* Triggers error messages if files doesn ' t exist
*
* @ param array $files
* List of file paths relative to $tmp_dir
* @ param string $tmp_dir
* Path to the directory where the $files are stored .
* @ param string $library
* Name of the library we are processing
* @ return boolean
* TRUE if all the files excists
*/
2013-01-16 19:39:49 +01:00
private function isExistingFiles ( $files , $tmp_dir , $library ) {
2012-12-04 15:52:03 +01:00
foreach ( $files as $file ) {
$path = str_replace ( array ( '/' , '\\' ), DIRECTORY_SEPARATOR , $file [ 'path' ]);
if ( ! file_exists ( $tmp_dir . DIRECTORY_SEPARATOR . $library . DIRECTORY_SEPARATOR . $path )) {
2013-01-16 19:39:49 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'The file "%file" is missing from library: "%name"' , array ( '%file' => $path , '%name' => $library )));
2012-11-26 22:48:51 +01:00
return FALSE ;
2012-11-22 14:00:06 +01:00
}
}
2012-11-26 22:48:51 +01:00
return TRUE ;
}
2012-11-29 15:41:06 +01:00
/**
2012-12-02 21:55:51 +01:00
* Validates h5p . json and library . json data
2012-11-29 15:41:06 +01:00
*
* Error messages are triggered if the data isn ' t valid
*
* @ param array $h5pData
* h5p data
* @ param string $library_name
* Name of the library we are processing
* @ param array $required
* Validation pattern for required properties
* @ param array $optional
* Validation pattern for optional properties
* @ return boolean
* TRUE if the $h5pData is valid
*/
2012-11-29 08:51:36 +01:00
private function isValidH5pData ( $h5pData , $library_name , $required , $optional ) {
$valid = $this -> isValidRequiredH5pData ( $h5pData , $required , $library_name );
$valid = $this -> isValidOptionalH5pData ( $h5pData , $optional , $library_name ) && $valid ;
2012-11-28 15:21:34 +01:00
return $valid ;
2012-11-28 13:56:42 +01:00
}
2012-11-29 15:41:06 +01:00
/**
* Helper function for isValidH5pData
*
* Validates the optional part of the h5pData
*
* Triggers error messages
*
* @ param array $h5pData
* h5p data
* @ param array $requirements
* Validation pattern
* @ param string $library_name
* Name of the library we are processing
* @ return boolean
* TRUE if the optional part of the $h5pData is valid
*/
2012-11-28 15:21:34 +01:00
private function isValidOptionalH5pData ( $h5pData , $requirements , $library_name ) {
$valid = TRUE ;
2012-11-28 13:56:42 +01:00
foreach ( $h5pData as $key => $value ) {
if ( isset ( $requirements [ $key ])) {
2012-12-04 15:52:03 +01:00
$valid = $this -> isValidRequirement ( $value , $requirements [ $key ], $library_name , $key ) && $valid ;
2012-11-28 13:56:42 +01:00
}
// Else: ignore, a package can have parameters that this library doesn't care about, but that library
// specific implementations does care about...
}
2012-11-28 15:21:34 +01:00
return $valid ;
2012-11-28 13:56:42 +01:00
}
2012-11-29 15:41:06 +01:00
/**
*
*
* @ param < type > $h5pData
* @ param < type > $requirement
* @ param < type > $library_name
* @ param < type > $property_name
* @ return boolean
*/
2012-11-28 15:21:34 +01:00
private function isValidRequirement ( $h5pData , $requirement , $library_name , $property_name ) {
$valid = TRUE ;
2012-11-28 13:56:42 +01:00
if ( is_string ( $requirement )) {
2013-02-23 23:29:41 +01:00
if ( $requirement == 'boolean' ) {
if ( ! is_bool ( $h5pData )) {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( " Invalid data provided for %property in %library. Boolean expected. " , array ( '%property' => $property_name , '%library' => $library_name )));
$valid = FALSE ;
2012-11-28 13:56:42 +01:00
}
}
else {
2013-02-23 23:29:41 +01:00
// The requirement is a regexp, match it against the data
if ( is_string ( $h5pData ) || is_int ( $h5pData )) {
if ( preg_match ( $requirement , $h5pData ) === 0 ) {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( " Invalid data provided for %property in %library " , array ( '%property' => $property_name , '%library' => $library_name )));
$valid = FALSE ;
}
}
else {
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( " Invalid data provided for %property in %library " , array ( '%property' => $property_name , '%library' => $library_name )));
$valid = FALSE ;
}
2012-11-28 13:56:42 +01:00
}
}
elseif ( is_array ( $requirement )) {
// We have sub requirements
if ( is_array ( $h5pData )) {
2012-12-04 15:52:03 +01:00
if ( is_array ( current ( $h5pData ))) {
foreach ( $h5pData as $sub_h5pData ) {
$valid = $this -> isValidRequiredH5pData ( $sub_h5pData , $requirement , $library_name ) && $valid ;
}
}
else {
$valid = $this -> isValidRequiredH5pData ( $h5pData , $requirement , $library_name ) && $valid ;
}
2012-11-28 13:56:42 +01:00
}
else {
2012-12-04 09:19:42 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( " Invalid data provided for %property in %library " , array ( '%property' => $property_name , '%library' => $library_name )));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
2012-11-28 13:56:42 +01:00
}
}
else {
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( " Can't read the property %property in %library " , array ( '%property' => $property_name , '%library' => $library_name )));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
2012-11-28 13:56:42 +01:00
}
2012-11-28 15:21:34 +01:00
return $valid ;
2012-11-28 13:56:42 +01:00
}
2012-11-28 15:21:34 +01:00
private function isValidRequiredH5pData ( $h5pData , $requirements , $library_name ) {
$valid = TRUE ;
2012-11-28 13:56:42 +01:00
foreach ( $requirements as $required => $requirement ) {
2012-11-28 14:45:54 +01:00
if ( is_int ( $required )) {
// We have an array of allowed options
2012-12-03 00:19:25 +01:00
return $this -> isValidH5pDataOptions ( $h5pData , $requirements , $library_name );
2012-11-28 14:45:54 +01:00
}
2012-11-28 13:56:42 +01:00
if ( isset ( $h5pData [ $required ])) {
2012-12-03 00:19:25 +01:00
$valid = $this -> isValidRequirement ( $h5pData [ $required ], $requirement , $library_name , $required ) && $valid ;
2012-11-28 13:56:42 +01:00
}
else {
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'The required property %property is missing from %library' , array ( '%property' => $required , '%library' => $library_name )));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
2012-11-28 13:56:42 +01:00
}
}
2012-11-28 15:21:34 +01:00
return $valid ;
2012-11-22 14:00:06 +01:00
}
2012-11-28 15:21:34 +01:00
private function isValidH5pDataOptions ( $selected , $allowed , $library_name ) {
$valid = TRUE ;
2012-11-28 14:45:54 +01:00
foreach ( $selected as $value ) {
if ( ! in_array ( $value , $allowed )) {
2012-11-29 22:52:41 +01:00
$this -> h5pF -> setErrorMessage ( $this -> h5pF -> t ( 'Illegal option %option in %library' , array ( '%option' => $value , '%library' => $library_name )));
2012-11-28 15:21:34 +01:00
$valid = FALSE ;
2012-11-28 14:45:54 +01:00
}
}
2012-11-28 15:21:34 +01:00
return $valid ;
2012-11-28 14:45:54 +01:00
}
2013-01-27 23:08:48 +01:00
private function getJsonData ( $file_path , $return_as_string = FALSE ) {
2012-11-29 08:51:36 +01:00
$json = file_get_contents ( $file_path );
if ( ! $json ) {
return FALSE ;
}
2012-12-03 00:19:25 +01:00
$jsonData = json_decode ( $json , TRUE );
2012-11-29 08:51:36 +01:00
if ( ! $jsonData ) {
return FALSE ;
}
2013-01-27 23:08:48 +01:00
return $return_as_string ? $json : $jsonData ;
2012-11-29 08:51:36 +01:00
}
private function arrayCopy ( array $array ) {
$result = array ();
foreach ( $array as $key => $val ) {
if ( is_array ( $val )) {
$result [ $key ] = arrayCopy ( $val );
}
elseif ( is_object ( $val )) {
$result [ $key ] = clone $val ;
}
else {
$result [ $key ] = $val ;
}
}
return $result ;
}
2012-11-21 14:14:07 +01:00
}
2012-11-29 22:52:41 +01:00
2013-02-17 15:04:30 +01:00
class H5PStorage {
2012-11-29 22:52:41 +01:00
public $h5pF ;
public $h5pC ;
/**
2013-02-17 15:04:30 +01:00
* Constructor for the H5PStorage
2012-11-29 22:52:41 +01:00
*
2013-02-17 15:04:30 +01:00
* @ param object $H5PFramework
2013-02-17 15:39:26 +01:00
* The frameworks implementation of the H5PFrameworkInterface
2012-11-29 22:52:41 +01:00
*/
2013-02-17 15:04:30 +01:00
public function __construct ( $H5PFramework , $H5PCore ) {
$this -> h5pF = $H5PFramework ;
$this -> h5pC = $H5PCore ;
2012-11-29 22:52:41 +01:00
}
2012-12-22 07:09:17 +01:00
public function savePackage ( $contentId , $contentMainId = NULL ) {
2012-12-22 06:35:16 +01:00
foreach ( $this -> h5pC -> librariesJsonData as $key => & $library ) {
$libraryId = $this -> h5pF -> getLibraryId ( $key , $library [ 'majorVersion' ], $library [ 'minorVersion' ]);
if ( ! $libraryId ) {
$new = TRUE ;
2012-11-29 22:52:41 +01:00
}
2012-12-22 06:35:16 +01:00
elseif ( $this -> h5pF -> isPatchedLibrary ( $library )) {
$new = FALSE ;
$library [ 'libraryId' ] = $libraryId ;
}
else {
// We already have the same or a newer version of this library
continue ;
2012-12-15 15:45:29 +01:00
}
2013-02-17 14:05:02 +01:00
$this -> h5pF -> saveLibraryData ( $library , $new );
2012-12-22 06:36:42 +01:00
2012-12-22 06:35:16 +01:00
$current_path = $this -> h5pF -> getUploadedH5pFolderPath () . DIRECTORY_SEPARATOR . $key ;
$destination_path = $this -> h5pF -> getH5pPath () . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . $library [ 'libraryId' ];
$this -> h5pC -> delTree ( $destination_path );
rename ( $current_path , $destination_path );
2012-11-30 15:51:39 +01:00
}
2013-02-24 00:12:57 +01:00
foreach ( $this -> h5pC -> librariesJsonData as $key => & $library ) {
// All libraries have been saved, we now save all the dependencies
if ( isset ( $library [ 'preloadedDependencies' ])) {
$this -> h5pF -> saveLibraryDependencies ( $library [ 'libraryId' ], $library [ 'preloadedDependencies' ], 'preloaded' );
}
if ( isset ( $library [ 'dynamicDependencies' ])) {
$this -> h5pF -> saveLibraryDependencies ( $library [ 'libraryId' ], $library [ 'dynamicDependencies' ], 'dynamic' );
}
if ( isset ( $library [ 'editorDependencies' ])) {
$this -> h5pF -> saveLibraryDependencies ( $library [ 'libraryId' ], $library [ 'editorDependencies' ], 'editor' );
}
}
2012-11-30 15:51:39 +01:00
$current_path = $this -> h5pF -> getUploadedH5pFolderPath () . DIRECTORY_SEPARATOR . 'content' ;
$destination_path = $this -> h5pF -> getH5pPath () . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . $contentId ;
rename ( $current_path , $destination_path );
$librariesInUse = array ();
$this -> getLibraryUsage ( $librariesInUse , $this -> h5pC -> mainJsonData );
$this -> h5pF -> saveLibraryUsage ( $contentId , $librariesInUse );
2012-12-22 06:35:16 +01:00
$this -> h5pC -> delTree ( $this -> h5pF -> getUploadedH5pFolderPath ());
2013-03-07 04:12:59 +01:00
$contentJson = file_get_contents ( $destination_path . DIRECTORY_SEPARATOR . 'content.json' );
$mainLibraryId = $librariesInUse [ $this -> h5pC -> mainJsonData [ 'mainLibrary' ]][ 'library' ][ 'libraryId' ];
$this -> h5pF -> saveContentData ( $contentId , $contentJson , $this -> h5pC -> mainJsonData , $mainLibraryId , $contentMainId );
2012-11-30 15:51:39 +01:00
}
2012-12-22 07:09:17 +01:00
public function deletePackage ( $contentId ) {
$this -> h5pC -> delTree ( $this -> h5pF -> getH5pPath () . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . $contentId );
$this -> h5pF -> deleteContentData ( $contentId );
}
2012-12-22 08:04:09 +01:00
public function updatePackage ( $contentId , $contentMainId = NULL ) {
$this -> deletePackage ( $contentId );
$this -> savePackage ( $contentId , $contentMainId );
}
public function copyPackage ( $contentId , $copyFromId , $contentMainId = NULL ) {
$source_path = $this -> h5pF -> getH5pPath () . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . $copyFromId ;
$destination_path = $this -> h5pF -> getH5pPath () . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . $contentId ;
$this -> h5pC -> copyTree ( $source_path , $destination_path );
2013-03-07 05:31:30 +01:00
$this -> h5pF -> copyLibraryUsage ( $contentId , $copyFromId , $contentMainId );
2012-12-22 08:04:09 +01:00
}
2012-11-30 15:51:39 +01:00
public function getLibraryUsage ( & $librariesInUse , $jsonData , $dynamic = FALSE ) {
if ( isset ( $jsonData [ 'preloadedDependencies' ])) {
foreach ( $jsonData [ 'preloadedDependencies' ] as $preloadedDependency ) {
2013-03-07 12:34:29 +01:00
$library = $this -> h5pF -> loadLibrary ( $preloadedDependency [ 'name' ], $preloadedDependency [ 'majorVersion' ], $preloadedDependency [ 'minorVersion' ]);
$librariesInUse [ $preloadedDependency [ 'name' ]] = array (
2012-12-01 22:18:48 +01:00
'library' => $library ,
2012-11-30 15:51:39 +01:00
'preloaded' => $dynamic ? 0 : 1 ,
);
2012-12-01 22:18:48 +01:00
$this -> getLibraryUsage ( $librariesInUse , $library , $dynamic );
2012-11-30 15:51:39 +01:00
}
}
if ( isset ( $jsonData [ 'dynamicDependencies' ])) {
foreach ( $jsonData [ 'dynamicDependencies' ] as $dynamicDependency ) {
2013-03-07 12:34:29 +01:00
if ( ! isset ( $librariesInUse [ $dynamicDependency [ 'name' ]])) {
$library = $this -> h5pF -> loadLibrary ( $dynamicDependency [ 'name' ], $dynamicDependency [ 'majorVersion' ], $dynamicDependency [ 'minorVersion' ]);
$librariesInUse [ $dynamicDependency [ 'name' ]] = array (
2012-12-01 22:18:48 +01:00
'library' => $library ,
2012-11-30 15:51:39 +01:00
'preloaded' => 0 ,
);
}
2012-12-01 22:18:48 +01:00
$this -> getLibraryUsage ( $librariesInUse , $library , TRUE );
2012-11-29 22:52:41 +01:00
}
}
}
}
2013-02-17 15:04:30 +01:00
class H5PCore {
2012-11-29 22:52:41 +01:00
public $h5pF ;
2012-11-30 15:51:39 +01:00
public $librariesJsonData ;
public $contentJsonData ;
public $mainJsonData ;
2012-11-29 22:52:41 +01:00
/**
2013-02-17 15:04:30 +01:00
* Constructor for the H5PCore
2012-11-29 22:52:41 +01:00
*
2013-02-17 15:04:30 +01:00
* @ param object $H5PFramework
2013-02-17 15:39:26 +01:00
* The frameworks implementation of the H5PFrameworkInterface
2012-11-29 22:52:41 +01:00
*/
2013-02-17 15:04:30 +01:00
public function __construct ( $H5PFramework ) {
$this -> h5pF = $H5PFramework ;
2012-11-29 22:52:41 +01:00
}
2012-12-04 22:26:20 +01:00
public function isSameVersion ( $library , $dependency ) {
if ( $library [ 'majorVersion' ] != $dependency [ 'majorVersion' ]) {
return FALSE ;
}
if ( $library [ 'minorVersion' ] != $dependency [ 'minorVersion' ]) {
return FALSE ;
}
return TRUE ;
}
2012-12-22 06:35:16 +01:00
/**
* Recursive function for removing directories .
*
* @ param string $dir Directory .
* @ return boolean Indicates if the directory existed .
*/
public function delTree ( $dir ) {
if ( ! is_dir ( $dir )) {
return ;
}
$files = array_diff ( scandir ( $dir ), array ( '.' , '..' ));
foreach ( $files as $file ) {
( is_dir ( " $dir / $file " )) ? $this -> delTree ( " $dir / $file " ) : unlink ( " $dir / $file " );
}
return rmdir ( $dir );
}
2012-12-22 08:04:09 +01:00
public function copyTree ( $source , $destination ) {
$dir = opendir ( $source );
@ mkdir ( $destination );
while ( false !== ( $file = readdir ( $dir ))) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir ( $source . '/' . $file )) {
2013-02-05 15:36:39 +01:00
$this -> copyTree ( $source . '/' . $file , $destination . '/' . $file );
2012-12-22 08:04:09 +01:00
}
else {
2013-02-05 15:36:39 +01:00
copy ( $source . '/' . $file , $destination . '/' . $file );
2012-12-22 08:04:09 +01:00
}
}
}
closedir ( $dir );
}
2012-11-29 22:52:41 +01:00
}
?>