PK JO embed.phpnu W+A
PK JOW= = h5p-default-storage.class.phpnu W+A path = $path;
$this->alteditorpath = $alteditorpath;
}
/**
* Store the library folder.
*
* @param array $library
* Library properties
*/
public function saveLibrary($library) {
$dest = $this->path . '/libraries/' . \H5PCore::libraryToString($library, TRUE);
// Make sure destination dir doesn't exist
\H5PCore::deleteFileTree($dest);
// Move library folder
self::copyFileTree($library['uploadDirectory'], $dest);
}
/**
* Store the content folder.
*
* @param string $source
* Path on file system to content directory.
* @param array $content
* Content properties
*/
public function saveContent($source, $content) {
$dest = "{$this->path}/content/{$content['id']}";
// Remove any old content
\H5PCore::deleteFileTree($dest);
self::copyFileTree($source, $dest);
}
/**
* Remove content folder.
*
* @param array $content
* Content properties
*/
public function deleteContent($content) {
\H5PCore::deleteFileTree("{$this->path}/content/{$content['id']}");
}
/**
* Creates a stored copy of the content folder.
*
* @param string $id
* Identifier of content to clone.
* @param int $newId
* The cloned content's identifier
*/
public function cloneContent($id, $newId) {
$path = $this->path . '/content/';
if (file_exists($path . $id)) {
self::copyFileTree($path . $id, $path . $newId);
}
}
/**
* Get path to a new unique tmp folder.
*
* @return string
* Path
*/
public function getTmpPath() {
$temp = "{$this->path}/temp";
self::dirReady($temp);
return "{$temp}/" . uniqid('h5p-');
}
/**
* Fetch content folder and save in target directory.
*
* @param int $id
* Content identifier
* @param string $target
* Where the content folder will be saved
*/
public function exportContent($id, $target) {
$source = "{$this->path}/content/{$id}";
if (file_exists($source)) {
// Copy content folder if it exists
self::copyFileTree($source, $target);
}
else {
// No contnet folder, create emty dir for content.json
self::dirReady($target);
}
}
/**
* Fetch library folder and save in target directory.
*
* @param array $library
* Library properties
* @param string $target
* Where the library folder will be saved
* @param string $developmentPath
* Folder that library resides in
*/
public function exportLibrary($library, $target, $developmentPath=NULL) {
$folder = \H5PCore::libraryToString($library, TRUE);
$srcPath = ($developmentPath === NULL ? "/libraries/{$folder}" : $developmentPath);
self::copyFileTree("{$this->path}{$srcPath}", "{$target}/{$folder}");
}
/**
* Save export in file system
*
* @param string $source
* Path on file system to temporary export file.
* @param string $filename
* Name of export file.
* @throws Exception Unable to save the file
*/
public function saveExport($source, $filename) {
$this->deleteExport($filename);
if (!self::dirReady("{$this->path}/exports")) {
throw new Exception("Unable to create directory for H5P export file.");
}
if (!copy($source, "{$this->path}/exports/{$filename}")) {
throw new Exception("Unable to save H5P export file.");
}
}
/**
* Removes given export file
*
* @param string $filename
*/
public function deleteExport($filename) {
$target = "{$this->path}/exports/{$filename}";
if (file_exists($target)) {
unlink($target);
}
}
/**
* Check if the given export file exists
*
* @param string $filename
* @return boolean
*/
public function hasExport($filename) {
$target = "{$this->path}/exports/{$filename}";
return file_exists($target);
}
/**
* Will concatenate all JavaScrips and Stylesheets into two files in order
* to improve page performance.
*
* @param array $files
* A set of all the assets required for content to display
* @param string $key
* Hashed key for cached asset
*/
public function cacheAssets(&$files, $key) {
foreach ($files as $type => $assets) {
if (empty($assets)) {
continue; // Skip no assets
}
$content = '';
foreach ($assets as $asset) {
// Get content from asset file
$assetContent = file_get_contents($this->path . $asset->path);
$cssRelPath = preg_replace('/[^\/]+$/', '', $asset->path);
// Get file content and concatenate
if ($type === 'scripts') {
$content .= $assetContent . ";\n";
}
else {
// Rewrite relative URLs used inside stylesheets
$content .= preg_replace_callback(
'/url\([\'"]?([^"\')]+)[\'"]?\)/i',
function ($matches) use ($cssRelPath) {
if (preg_match("/^(data:|([a-z0-9]+:)?\/)/i", $matches[1]) === 1) {
return $matches[0]; // Not relative, skip
}
return 'url("../' . $cssRelPath . $matches[1] . '")';
},
$assetContent) . "\n";
}
}
self::dirReady("{$this->path}/cachedassets");
$ext = ($type === 'scripts' ? 'js' : 'css');
$outputfile = "/cachedassets/{$key}.{$ext}";
file_put_contents($this->path . $outputfile, $content);
$files[$type] = array((object) array(
'path' => $outputfile,
'version' => ''
));
}
}
/**
* Will check if there are cache assets available for content.
*
* @param string $key
* Hashed key for cached asset
* @return array
*/
public function getCachedAssets($key) {
$files = array();
$js = "/cachedassets/{$key}.js";
if (file_exists($this->path . $js)) {
$files['scripts'] = array((object) array(
'path' => $js,
'version' => ''
));
}
$css = "/cachedassets/{$key}.css";
if (file_exists($this->path . $css)) {
$files['styles'] = array((object) array(
'path' => $css,
'version' => ''
));
}
return empty($files) ? NULL : $files;
}
/**
* Remove the aggregated cache files.
*
* @param array $keys
* The hash keys of removed files
*/
public function deleteCachedAssets($keys) {
foreach ($keys as $hash) {
foreach (array('js', 'css') as $ext) {
$path = "{$this->path}/cachedassets/{$hash}.{$ext}";
if (file_exists($path)) {
unlink($path);
}
}
}
}
/**
* Read file content of given file and then return it.
*
* @param string $file_path
* @return string
*/
public function getContent($file_path) {
return file_get_contents($file_path);
}
/**
* Save files uploaded through the editor.
* The files must be marked as temporary until the content form is saved.
*
* @param \H5peditorFile $file
* @param int $contentid
*/
public function saveFile($file, $contentId) {
// Prepare directory
if (empty($contentId)) {
// Should be in editor tmp folder
$path = $this->getEditorPath();
}
else {
// Should be in content folder
$path = $this->path . '/content/' . $contentId;
}
$path .= '/' . $file->getType() . 's';
self::dirReady($path);
// Add filename to path
$path .= '/' . $file->getName();
copy($_FILES['file']['tmp_name'], $path);
return $file;
}
/**
* Copy a file from another content or editor tmp dir.
* Used when copy pasting content in H5P Editor.
*
* @param string $file path + name
* @param string|int $fromid Content ID or 'editor' string
* @param int $toid Target Content ID
*/
public function cloneContentFile($file, $fromId, $toId) {
// Determine source path
if ($fromId === 'editor') {
$sourcepath = $this->getEditorPath();
}
else {
$sourcepath = "{$this->path}/content/{$fromId}";
}
$sourcepath .= '/' . $file;
// Determine target path
$filename = basename($file);
$filedir = str_replace($filename, '', $file);
$targetpath = "{$this->path}/content/{$toId}/{$filedir}";
// Make sure it's ready
self::dirReady($targetpath);
$targetpath .= $filename;
// Check to see if source exist and if target doesn't
if (!file_exists($sourcepath) || file_exists($targetpath)) {
return; // Nothing to copy from or target already exists
}
copy($sourcepath, $targetpath);
}
/**
* Copy a content from one directory to another. Defaults to cloning
* content from the current temporary upload folder to the editor path.
*
* @param string $source path to source directory
* @param string $contentId Id of contentarray
*/
public function moveContentDirectory($source, $contentId = NULL) {
if ($source === NULL) {
return NULL;
}
// TODO: Remove $contentId and never copy temporary files into content folder. JI-366
if ($contentId === NULL || $contentId == 0) {
$target = $this->getEditorPath();
}
else {
// Use content folder
$target = "{$this->path}/content/{$contentId}";
}
$contentSource = $source . '/' . 'content';
$contentFiles = array_diff(scandir($contentSource), array('.','..', 'content.json'));
foreach ($contentFiles as $file) {
if (is_dir("{$contentSource}/{$file}")) {
self::copyFileTree("{$contentSource}/{$file}", "{$target}/{$file}");
}
else {
copy("{$contentSource}/{$file}", "{$target}/{$file}");
}
}
// TODO: Return list of all files so that they can be marked as temporary. JI-366
}
/**
* Checks to see if content has the given file.
* Used when saving content.
*
* @param string $file path + name
* @param int $contentId
* @return string File ID or NULL if not found
*/
public function getContentFile($file, $contentId) {
$path = "{$this->path}/content/{$contentId}/{$file}";
return file_exists($path) ? $path : NULL;
}
/**
* Checks to see if content has the given file.
* Used when saving content.
*
* @param string $file path + name
* @param int $contentid
* @return string|int File ID or NULL if not found
*/
public function removeContentFile($file, $contentId) {
$path = "{$this->path}/content/{$contentId}/{$file}";
if (file_exists($path)) {
unlink($path);
// Clean up any empty parent directories to avoid cluttering the file system
$parts = explode('/', $path);
while (array_pop($parts) !== NULL) {
$dir = implode('/', $parts);
if (is_dir($dir) && count(scandir($dir)) === 2) { // empty contains '.' and '..'
rmdir($dir); // Remove empty parent
}
else {
return; // Not empty
}
}
}
}
/**
* Check if server setup has write permission to
* the required folders
*
* @return bool True if site can write to the H5P files folder
*/
public function hasWriteAccess() {
return self::dirReady($this->path);
}
/**
* Check if the file presave.js exists in the root of the library
*
* @param string $libraryFolder
* @param string $developmentPath
* @return bool
*/
public function hasPresave($libraryFolder, $developmentPath = null) {
$path = is_null($developmentPath) ? 'libraries' . '/' . $libraryFolder : $developmentPath;
$filePath = realpath($this->path . '/' . $path . '/' . 'presave.js');
return file_exists($filePath);
}
/**
* Check if upgrades script exist for library.
*
* @param string $machineName
* @param int $majorVersion
* @param int $minorVersion
* @return string Relative path
*/
public function getUpgradeScript($machineName, $majorVersion, $minorVersion) {
$upgrades = "/libraries/{$machineName}-{$majorVersion}.{$minorVersion}/upgrades.js";
if (file_exists($this->path . $upgrades)) {
return $upgrades;
}
else {
return NULL;
}
}
/**
* 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.
*
* @param string $source
* From path
* @param string $destination
* To path
* @return boolean
* Indicates if the directory existed.
*
* @throws Exception Unable to copy the file
*/
private static function copyFileTree($source, $destination) {
if (!self::dirReady($destination)) {
throw new \Exception('unabletocopy');
}
$ignoredFiles = self::getIgnoredFiles("{$source}/.h5pignore");
$dir = opendir($source);
if ($dir === FALSE) {
trigger_error('Unable to open directory ' . $source, E_USER_WARNING);
throw new \Exception('unabletocopy');
}
while (false !== ($file = readdir($dir))) {
if (($file != '.') && ($file != '..') && $file != '.git' && $file != '.gitignore' && !in_array($file, $ignoredFiles)) {
if (is_dir("{$source}/{$file}")) {
self::copyFileTree("{$source}/{$file}", "{$destination}/{$file}");
}
else {
copy("{$source}/{$file}", "{$destination}/{$file}");
}
}
}
closedir($dir);
}
/**
* Retrieve array of file names from file.
*
* @param string $file
* @return array Array with files that should be ignored
*/
private static function getIgnoredFiles($file) {
if (file_exists($file) === FALSE) {
return array();
}
$contents = file_get_contents($file);
if ($contents === FALSE) {
return array();
}
return preg_split('/\s+/', $contents);
}
/**
* Recursive function that makes sure the specified directory exists and
* is writable.
*
* @param string $path
* @return bool
*/
private static function dirReady($path) {
if (!file_exists($path)) {
$parent = preg_replace("/\/[^\/]+\/?$/", '', $path);
if (!self::dirReady($parent)) {
return FALSE;
}
mkdir($path, 0777, true);
}
if (!is_dir($path)) {
trigger_error('Path is not a directory ' . $path, E_USER_WARNING);
return FALSE;
}
if (!is_writable($path)) {
trigger_error('Unable to write to ' . $path . ' – check directory permissions –', E_USER_WARNING);
return FALSE;
}
return TRUE;
}
/**
* Easy helper function for retrieving the editor path
*
* @return string Path to editor files
*/
private function getEditorPath() {
return ($this->alteditorpath !== NULL ? $this->alteditorpath : "{$this->path}/editor");
}
}
PK JO1z! ! h5p-metadata.class.phpnu W+A array(
'type' => 'text',
'maxLength' => 255
),
'authors' => array(
'type' => 'json'
),
'changes' => array(
'type' => 'json'
),
'source' => array(
'type' => 'text',
'maxLength' => 255
),
'license' => array(
'type' => 'text',
'maxLength' => 32
),
'licenseVersion' => array(
'type' => 'text',
'maxLength' => 10
),
'licenseExtras' => array(
'type' => 'text',
'maxLength' => 5000
),
'authorComments' => array(
'type' => 'text',
'maxLength' => 5000
),
'yearFrom' => array(
'type' => 'int'
),
'yearTo' => array(
'type' => 'int'
),
'defaultLanguage' => array(
'type' => 'text',
'maxLength' => 32,
)
);
/**
* JSON encode metadata
*
* @param object $content
* @return string
*/
public static function toJSON($content) {
// Note: deliberatly creating JSON string "manually" to improve performance
return
'{"title":' . (isset($content->title) ? json_encode($content->title) : 'null') .
',"authors":' . (isset($content->authors) ? $content->authors : 'null') .
',"source":' . (isset($content->source) ? '"' . $content->source . '"' : 'null') .
',"license":' . (isset($content->license) ? '"' . $content->license . '"' : 'null') .
',"licenseVersion":' . (isset($content->license_version) ? '"' . $content->license_version . '"' : 'null') .
',"licenseExtras":' . (isset($content->license_extras) ? json_encode($content->license_extras) : 'null') .
',"yearFrom":' . (isset($content->year_from) ? $content->year_from : 'null') .
',"yearTo":' . (isset($content->year_to) ? $content->year_to : 'null') .
',"changes":' . (isset($content->changes) ? $content->changes : 'null') .
',"defaultLanguage":' . (isset($content->default_language) ? '"' . $content->default_language . '"' : 'null') .
',"authorComments":' . (isset($content->author_comments) ? json_encode($content->author_comments) : 'null') . '}';
}
/**
* Make the metadata into an associative array keyed by the property names
* @param mixed $metadata Array or object containing metadata
* @param bool $include_title
* @param bool $include_missing For metadata fields not being set, skip 'em.
* Relevant for content upgrade
* @param array $types
* @return array
*/
public static function toDBArray($metadata, $include_title = true, $include_missing = true, &$types = array()) {
$fields = array();
if (!is_array($metadata)) {
$metadata = (array) $metadata;
}
foreach (self::$fields as $key => $config) {
// Ignore title?
if ($key === 'title' && !$include_title) {
continue;
}
$exists = array_key_exists($key, $metadata);
// Don't include missing fields
if (!$include_missing && !$exists) {
continue;
}
$value = $exists ? $metadata[$key] : null;
// lowerCamelCase to snake_case
$db_field_name = strtolower(preg_replace('/(? $config['maxLength']) {
$value = mb_substr($value, 0, $config['maxLength']);
}
$types[] = '%s';
break;
case 'int':
$value = ($value !== null) ? intval($value) : null;
$types[] = '%d';
break;
case 'json':
$value = ($value !== null) ? json_encode($value) : null;
$types[] = '%s';
break;
}
$fields[$db_field_name] = $value;
}
return $fields;
}
/**
* The metadataSettings field in libraryJson uses 1 for true and 0 for false.
* Here we are converting these to booleans, and also doing JSON encoding.
* This is invoked before the library data is beeing inserted/updated to DB.
*
* @param array $metadataSettings
* @return string
*/
public static function boolifyAndEncodeSettings($metadataSettings) {
// Convert metadataSettings values to boolean
if (isset($metadataSettings['disable'])) {
$metadataSettings['disable'] = $metadataSettings['disable'] === 1;
}
if (isset($metadataSettings['disableExtraTitleField'])) {
$metadataSettings['disableExtraTitleField'] = $metadataSettings['disableExtraTitleField'] === 1;
}
return json_encode($metadataSettings);
}
}
PK JOa
|
README.txtnu W+A This folder contains the general H5P library. The files within this folder are not specific to any framework.
Any interaction with an LMS, CMS or other frameworks is done through interfaces. Platforms need to implement
the H5PFrameworkInterface(in h5p.classes.php) and also do the following:
- Provide a form for uploading H5P packages.
- Place the uploaded H5P packages in a temporary directory
+++
See existing implementations for details. For instance the Drupal H5P module located at drupal.org/project/h5p
We will make available documentation and tutorials for creating platform integrations in the future.
The H5P PHP library is GPL licensed due to GPL code being used for purifying HTML provided by authors.
PK JO!־ .travis.ymlnu W+A language: php
# At present the only jobs to run are a php lint.
# Run this against all supported versions of PHP.
jobs:
include:
# Bionic supports PHP 7.1, 7.2, 7.3, and 7.4.
# https://docs.travis-ci.com/user/reference/bionic/#php-support
- php: 7.4
dist: bionic
- php: 7.3
dist: bionic
- php: 7.2
dist: bionic
- php: 7.1
dist: bionic
# Xenial was the last Travis distribution to support PHP 5.6, and 7.0.
# https://docs.travis-ci.com/user/reference/xenial/#php-support
- php: 7.0
dist: xenial
- php: 5.6
dist: xenial
# Trusty was the last Travis distribution to support PHP 5.4, and 5.5.
# https://docs.travis-ci.com/user/languages/php/#php-54x---55x-support-is-available-on-precise-and-trusty-only
- php: 5.5
dist: trusty
- php: 5.4
dist: trusty
# Precise was the last Travis distribution to support PHP 5.2, and 5.3.
# https://docs.travis-ci.com/user/languages/php/#php-52x---53x-support-is-available-on-precise-only
- php: 5.3
dist: precise
script:
# Run a php lint across all PHP files.
- find . -type f -name '*\.php' -print0 | xargs -0 -n1 php -l
PK JOJ&