Commit bc66d5c1 authored by Son Nguyen's avatar Son Nguyen
Browse files

Enable Unicode filename for exporting HTML


(Bug #996172)

+ Using utf-8 string as file/folder name:
+ Setting the maximum of file/folder name length to 80. (Max filename
length on many OS is limited to 256 bytes)
+ Percent encoding URL. It is a non human-readable string. However, the
modern web browsers (Firefox3, Chrome, >IE7) will automatically display
it into human readable URL.

Change-Id: Ibb0d4e5d5fbe01bc49b5ad9ba68e4bc483938016
Signed-off-by: default avatarSon Nguyen <son.nguyen@catalyst.net.nz>
parent 57ad8a36
......@@ -56,7 +56,7 @@ class HtmlExportBlog extends HtmlExportArtefactPlugin {
foreach ($this->exporter->get('artefacts') as $artefact) {
if ($artefact->get('artefacttype') == 'blog') {
$blogs[] = array(
'link' => 'files/blog/' . PluginExportHtml::text_to_path($artefact->get('title')) . '/index.html',
'link' => 'files/blog/' . PluginExportHtml::text_to_URLpath(PluginExportHtml::text_to_filename($artefact->get('title'))) . '/index.html',
'title' => $artefact->get('title'),
);
}
......
......@@ -53,7 +53,7 @@ class HtmlExportPlans extends HtmlExportArtefactPlugin {
foreach ($this->exporter->get('artefacts') as $artefact) {
if ($artefact instanceof ArtefactTypePlan) {
$plans[] = array(
'link' => 'files/plans/' . PluginExportHtml::text_to_path($artefact->get('title')) . '/index.html',
'link' => 'files/plans/' . PluginExportHtml::text_to_URLpath(PluginExportHtml::text_to_filename($artefact->get('title'))) . '/index.html',
'title' => $artefact->get('title'),
);
}
......
......@@ -70,7 +70,7 @@ class PluginExportHtml extends PluginExport {
public function __construct(User $user, $views, $artefacts, $progresscallback=null) {
global $THEME;
parent::__construct($user, $views, $artefacts, $progresscallback);
$this->rootdir = 'portfolio-for-' . self::text_to_path($user->get('username'));
$this->rootdir = 'portfolio-for-' . self::text_to_filename($user->get('username'));
// Create basic required directories
foreach (array('files', 'views', 'static', 'static/smilies', 'static/profileicons') as $directory) {
......@@ -289,13 +289,30 @@ class PluginExportHtml extends PluginExport {
}
/**
* Converts the passed text into a a form that could be used in a URL.
* Converts the UTF-8 passed text into a a form that could be used in a file name.
*
* @param string $text The text to convert
* @return string The converted text
*/
public static function text_to_path($text) {
return substr(preg_replace('#[^a-zA-Z0-9_-]+#', '-', $text), 0, 255);
public static function text_to_filename($text) {
// truncates the text and replaces NOT allowed characters to hyphens
return preg_replace('#["*/:<>?\\| ]+#', '-', mb_substr($text, 0, parent::MAX_FILENAME_LENGTH, 'utf-8'));
}
/**
* Converts the UTF-8 passed text into a a form that could be used in a URL.
*
* @param string $text The text to convert
* @return string The converted text
*/
public static function text_to_URLpath($text) {
$tab_text = str_split($text);
$output = '';
foreach ($tab_text as $id=>$char){
$hex = dechex(ord($char));
$output .= '%' . $hex;
}
return $output;
}
/**
......@@ -327,7 +344,7 @@ class PluginExportHtml extends PluginExport {
$title = $this->views[$viewid]->get('title');
$menus[$collectionid][] = array(
'id' => $viewid,
'url' => self::text_to_path($title) . '/index.html',
'url' => self::text_to_URLpath(self::text_to_filename($title)) . '/index.html',
'text' => $title,
);
}
......@@ -360,7 +377,7 @@ class PluginExportHtml extends PluginExport {
array('text' => get_string('Views', 'view')),
array('text' => $view->get('title'), 'path' => 'index.html'),
));
$directory = $this->exportdir . '/' . $this->rootdir . '/views/' . self::text_to_path($view->get('title'));
$directory = $this->exportdir . '/' . $this->rootdir . '/views/' . self::text_to_filename($view->get('title'));
if (!check_dir_exists($directory)) {
throw new SystemException("Could not create directory for view $viewid");
}
......@@ -409,7 +426,7 @@ class PluginExportHtml extends PluginExport {
if ($view->get('type') != 'profile') {
$item = array(
'title' => $view->get('title'),
'folder' => self::text_to_path($view->get('title')),
'folder' => self::text_to_filename($view->get('title')),
);
if (isset($this->viewcollection[$id])) {
$list['c' . $this->viewcollection[$id]]['views'][] = $item;
......@@ -522,7 +539,7 @@ abstract class HtmlExportArtefactPlugin {
public function paginate($artefact) {
// Create directory for storing the artefact
$dirname = PluginExportHtml::text_to_path(trim($artefact->get('title')));
$dirname = PluginExportHtml::text_to_filename(trim($artefact->get('title')));
if (!check_dir_exists($this->fileroot . $dirname)) {
throw new SystemException("Couldn't create artefact directory {$this->fileroot}{$dirname}");
}
......@@ -692,7 +709,7 @@ class HtmlExportOutputFilter {
return $matches[0];
}
if (!isset($this->viewtitles[$viewid])) {
$this->viewtitles[$viewid] = PluginExportHtml::text_to_path(get_field('view', 'title', 'id', $viewid));
$this->viewtitles[$viewid] = PluginExportHtml::text_to_URLpath(PluginExportHtml::text_to_filename(get_field('view', 'title', 'id', $viewid)));
}
return $this->basepath . '/views/' . $this->viewtitles[$viewid] . '/index.html';
}
......@@ -717,7 +734,7 @@ class HtmlExportOutputFilter {
$dir = $artefacttype == 'plan' ? 'plans' : $artefacttype;
$offset = ($matches[4]) ? intval(substr($matches[4], strlen('&amp;offset='))) : 0;
$offset = ($offset == 0) ? 'index' : $offset;
return '<a href="' . $this->basepath . "/files/$dir/" . PluginExportHtml::text_to_path($artefact->get('title')) . '/' . $offset . '.html">' . $matches[5] . '</a>';
return '<a href="' . $this->basepath . "/files/$dir/" . PluginExportHtml::text_to_URLpath(PluginExportHtml::text_to_filename($artefact->get('title'))) . '/' . $offset . '.html">' . $matches[5] . '</a>';
case 'file':
case 'folder':
case 'image':
......
......@@ -70,6 +70,13 @@ abstract class PluginExport extends Plugin {
*/
const EXPORT_LIST_OF_ARTEFACTS = -5;
/**
* Maximum filename length in UTF-8 encoding characters
* Most file systems (FAT, FAT32, NTFS, ext2, ext3, ext4) support the filename length of 255 bytes
* UTF-8 needs at most 3 bytes to encode
*/
const MAX_FILENAME_LENGTH = 80;
/**
* A human-readable title for the export
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment