From c35d7f8334b49a9a1244a4843e19413678b636ee Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Thu, 12 Mar 2015 14:38:10 +0100 Subject: [PATCH 1/6] Added support for generating human readable H5P file names. --- h5p.classes.php | 55 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 47df2f2..e0c4f5a 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -14,7 +14,7 @@ interface H5PFrameworkInterface { * - h5pVersion: The version of the H5P plugin/module */ public function getPlatformInfo(); - + /** * Fetches a file from a remote server using HTTP GET @@ -527,6 +527,13 @@ interface H5PFrameworkInterface { * @return int */ public function getNumContent($libraryId); + + /** + * Generate an easy human readable identifier for the given content. + * + * @param array $content assoc + */ + public function generateHumanReadableContentIdentifier($content); } /** @@ -1469,7 +1476,7 @@ Class H5PExport { public function createExportFile($content) { $h5pDir = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR; $tempPath = $h5pDir . 'temp' . DIRECTORY_SEPARATOR . $content['id']; - $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['id'] . '.h5p'; + $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['humanId'] . '.h5p'; // Temp dir to put the h5p files in @mkdir($tempPath, 0777, TRUE); @@ -1690,8 +1697,8 @@ class H5PCore { * @param Object $content * @return Object NULL on failure. */ - public function filterParameters($content) { - if (isset($content['filtered']) && $content['filtered'] !== '') { + public function filterParameters(&$content) { + if (isset($content['filtered']) && $content['filtered'] !== '' && $content['humanId']) { return $content['filtered']; } @@ -1713,6 +1720,10 @@ class H5PCore { $this->h5pF->deleteLibraryUsage($content['id']); $this->h5pF->saveLibraryUsage($content['id'], $content['dependencies']); + if (!$content['humanId']) { + $content['humanId'] = $this->h5pF->generateHumanReadableContentIdentifier($content); + } + if ($this->exportEnabled) { // Recreate export file $exporter = new H5PExport($this->h5pF, $this); @@ -1722,7 +1733,7 @@ class H5PCore { } // Cache. - $this->h5pF->setFilteredParameters($content['id'], $params); + $this->h5pF->setFilteredParameters($content['id'], $params, $content['humanId']); } return $params; } @@ -2287,6 +2298,40 @@ class H5PCore { return $libraryIdMap[$libString]; } + + /** + * Convert strings of text to a simple kebab case. + * Very useful for readable urls etc. + * + * @param string $input + * @return string + */ + public static function kebabize($input) { + // Down low + $input = strtolower($input); + + // Replace common chars + $input = str_replace( + array('æ', 'ø', 'ö', 'ó', 'ô', 'œ', 'å', 'ä', 'á', 'à', 'â', 'ç', 'é', 'è', 'ê', 'ë', 'í', 'î', 'ï', 'ú', 'ñ', 'ü', 'ù', 'û', 'ß'), + array('ae', 'oe', 'o', 'o', 'o', 'oe', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'u', 'n', 'u', 'u', 'u', 'es'), + $input); + + // Replace everything else + $input = preg_replace('/[^a-z0-9]/', '-', $input); + + // Prevent double hyphen + $input = preg_replace('/-{2,}/', '-', $input); + + // Prevent hyphen in beginning or end + $input = preg_replace('/^-|-$/', '', $input); + + if ($input === '') { + // Use default string + $input = 'interactive'; + } + + return $input; + } } /** From 6541faf8bad0e5b6f2b0ad62f79dab7d2cee1a62 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Fri, 13 Mar 2015 15:17:19 +0100 Subject: [PATCH 2/6] Renamed humanId => slug. Moved most of the slug generating code out of the framework and into core. Remove old export files. Use old export file until new slug is generated. Added support for converting more special chars. --- h5p.classes.php | 78 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index e0c4f5a..3c1efd7 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -496,12 +496,12 @@ interface H5PFrameworkInterface { public function setOption($name, $value); /** - * This will set the filtered parameters for the given content. + * This will update selected fields on the given content. * - * @param int $content_id - * @param string $parameters filtered + * @param int $id Content identifier + * @param array $fields Content fields, e.g. filtered or slug. */ - public function setFilteredParameters($content_id, $parameters = ''); + public function updateContentFields($id, $fields); /** * Will clear filtered params for all the content that uses the specified @@ -529,11 +529,12 @@ interface H5PFrameworkInterface { public function getNumContent($libraryId); /** - * Generate an easy human readable identifier for the given content. + * Determines if content slug is used. * - * @param array $content assoc + * @param string $slug + * @return boolean */ - public function generateHumanReadableContentIdentifier($content); + public function isContentSlugAvailable($slug); } /** @@ -1476,7 +1477,7 @@ Class H5PExport { public function createExportFile($content) { $h5pDir = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR; $tempPath = $h5pDir . 'temp' . DIRECTORY_SEPARATOR . $content['id']; - $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['humanId'] . '.h5p'; + $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['slug'] . '.h5p'; // Temp dir to put the h5p files in @mkdir($tempPath, 0777, TRUE); @@ -1698,7 +1699,7 @@ class H5PCore { * @return Object NULL on failure. */ public function filterParameters(&$content) { - if (isset($content['filtered']) && $content['filtered'] !== '' && $content['humanId']) { + if (isset($content['filtered']) && $content['filtered'] !== '') { return $content['filtered']; } @@ -1720,8 +1721,14 @@ class H5PCore { $this->h5pF->deleteLibraryUsage($content['id']); $this->h5pF->saveLibraryUsage($content['id'], $content['dependencies']); - if (!$content['humanId']) { - $content['humanId'] = $this->h5pF->generateHumanReadableContentIdentifier($content); + if (!$content['slug']) { + $content['slug'] = $this->generateContentSlug($content); + + // Remove old export file + $oldExport = $this->h5pF->getH5pPath() . '/exports/' . $content['id'] . '.h5p'; + if (file_exists($oldExport)) { + unlink($oldExport); + } } if ($this->exportEnabled) { @@ -1733,11 +1740,41 @@ class H5PCore { } // Cache. - $this->h5pF->setFilteredParameters($content['id'], $params, $content['humanId']); + $this->h5pF->updateContentFields($content['id'], array( + 'filtered' => $params, + 'slug' => $content['slug'] + )); } return $params; } + /** + * Generate content slug + * + * @param array $content object + * @return string unique content slug + */ + private function generateContentSlug($content) { + $slug = H5PCore::slugify($content['title']); + + $available = NULL; + while (!$available) { + if ($available === FALSE) { + // If not available, add number suffix. + $matches = array(); + if (preg_match('/(.+-)([0-9]+)$/', $slug, $matches)) { + $slug = $matches[1] . (intval($matches[2]) + 1); + } + else { + $slug .= '-2'; + } + } + $available = $this->h5pF->isContentSlugAvailable($slug); + } + + return $slug; + } + /** * Find the files required for this content to work. * @@ -2300,20 +2337,20 @@ class H5PCore { } /** - * Convert strings of text to a simple kebab case. + * Convert strings of text into simple kebab case slugs. * Very useful for readable urls etc. * * @param string $input * @return string */ - public static function kebabize($input) { + public static function slugify($input) { // Down low $input = strtolower($input); // Replace common chars $input = str_replace( - array('æ', 'ø', 'ö', 'ó', 'ô', 'œ', 'å', 'ä', 'á', 'à', 'â', 'ç', 'é', 'è', 'ê', 'ë', 'í', 'î', 'ï', 'ú', 'ñ', 'ü', 'ù', 'û', 'ß'), - array('ae', 'oe', 'o', 'o', 'o', 'oe', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'u', 'n', 'u', 'u', 'u', 'es'), + array('æ', 'ø', 'ö', 'ó', 'ô', 'Ò', 'Õ', 'Ý', 'ý', 'ÿ', 'ā', 'ă', 'ą', 'œ', 'å', 'ä', 'á', 'à', 'â', 'ã', 'ç', 'ć', 'ĉ', 'ċ', 'č', 'é', 'è', 'ê', 'ë', 'í', 'ì', 'î', 'ï', 'ú', 'ñ', 'ü', 'ù', 'û', 'ß', 'ď', 'đ', 'ē', 'ĕ', 'ė', 'ę', 'ě', 'ĝ', 'ğ', 'ġ', 'ģ', 'ĥ', 'ħ', 'ĩ', 'ī', 'ĭ', 'į', 'ı', 'ij', 'ĵ', 'ķ', 'ĺ', 'ļ', 'ľ', 'ŀ', 'ł', 'ń', 'ņ', 'ň', 'ʼn', 'ō', 'ŏ', 'ő', 'ŕ', 'ŗ', 'ř', 'ś', 'ŝ', 'ş', 'š', 'ţ', 'ť', 'ŧ', 'ũ', 'ū', 'ŭ', 'ů', 'ű', 'ų', 'ŵ', 'ŷ', 'ź', 'ż', 'ž', 'ſ', 'ƒ', 'ơ', 'ư', 'ǎ', 'ǐ', 'ǒ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'ǻ', 'ǽ', 'ǿ'), + array('ae', 'oe', 'o', 'o', 'o', 'oe', 'o', 'o', 'y', 'y', 'y', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'c', 'c', 'c', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'u', 'n', 'u', 'u', 'u', 'es', 'd', 'd', 'e', 'e', 'e', 'e', 'e', 'g', 'g', 'g', 'g', 'h', 'h', 'i', 'i', 'i', 'i', 'i', 'ij', 'j', 'k', 'l', 'l', 'l', 'l', 'l', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'r', 'r', 'r', 's', 's', 's', 's', 't', 't', 't', 'u', 'u', 'u', 'u', 'u', 'u', 'w', 'y', 'z', 'z', 'z', 's', 'f', 'o', 'u', 'a', 'i', 'o', 'u', 'u', 'u', 'u', 'u', 'a', 'ae', 'oe'), $input); // Replace everything else @@ -2323,10 +2360,15 @@ class H5PCore { $input = preg_replace('/-{2,}/', '-', $input); // Prevent hyphen in beginning or end - $input = preg_replace('/^-|-$/', '', $input); + $input = trim($input, '-'); + // Prevent to long slug + if (strlen($input) > 91) { + $inputsubstr($input, 0, 92); + } + + // Prevent empty slug if ($input === '') { - // Use default string $input = 'interactive'; } From 5adffcaeb82e03c2669c53ede33f4a08449ae6ac Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Tue, 7 Apr 2015 15:36:28 +0200 Subject: [PATCH 3/6] Added content id. --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 3c1efd7..eb02c47 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1477,7 +1477,7 @@ Class H5PExport { public function createExportFile($content) { $h5pDir = $this->h5pF->getH5pPath() . DIRECTORY_SEPARATOR; $tempPath = $h5pDir . 'temp' . DIRECTORY_SEPARATOR . $content['id']; - $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['slug'] . '.h5p'; + $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $content['slug'] . '-' . $content['id'] . '.h5p'; // Temp dir to put the h5p files in @mkdir($tempPath, 0777, TRUE); From ccccec84e715d1370f32449b42624057fb256d3c Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Wed, 22 Apr 2015 15:19:01 +0200 Subject: [PATCH 4/6] Use correct path. --- h5p.classes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 14ed0d0..79212be 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1276,7 +1276,7 @@ class H5PStorage { } $content['params'] = file_get_contents($current_path . DIRECTORY_SEPARATOR . 'content.json'); - + if (isset($options['disable'])) { $content['disable'] = $options['disable']; } @@ -1773,7 +1773,7 @@ class H5PCore { $content['slug'] = $this->generateContentSlug($content); // Remove old export file - $oldExport = $this->h5pF->getH5pPath() . '/exports/' . $content['id'] . '.h5p'; + $oldExport = $this->path . '/exports/' . $content['id'] . '.h5p'; if (file_exists($oldExport)) { unlink($oldExport); } From 4683e61fa77fd3c752136d8ff49e968922f99818 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 27 Apr 2015 13:13:00 +0200 Subject: [PATCH 5/6] Delete correct export file. --- h5p.classes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/h5p.classes.php b/h5p.classes.php index 79212be..326e516 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1585,7 +1585,7 @@ Class H5PExport { */ public function deleteExport($contentId) { $h5pDir = $this->h5pC->path . DIRECTORY_SEPARATOR; - $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . $contentId . '.h5p'; + $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . ($content['slug'] ? $content['slug'] . '-' : '') . $content['id'] . '.h5p'; if (file_exists($zipPath)) { unlink($zipPath); } From 31872111ebac0a0fac30ab6219c435a40b400fb8 Mon Sep 17 00:00:00 2001 From: Frode Petterson Date: Mon, 27 Apr 2015 15:20:40 +0200 Subject: [PATCH 6/6] Use content. --- h5p.classes.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/h5p.classes.php b/h5p.classes.php index 326e516..4dd3c20 100644 --- a/h5p.classes.php +++ b/h5p.classes.php @@ -1580,10 +1580,9 @@ Class H5PExport { /** * Delete .h5p file * - * @param int/string $contentId - * Identifier for the H5P + * @param array $content object */ - public function deleteExport($contentId) { + public function deleteExport($content) { $h5pDir = $this->h5pC->path . DIRECTORY_SEPARATOR; $zipPath = $h5pDir . 'exports' . DIRECTORY_SEPARATOR . ($content['slug'] ? $content['slug'] . '-' : '') . $content['id'] . '.h5p'; if (file_exists($zipPath)) {