1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 11:30:55 +01:00

Use PEAR Text_Figlet to render figlet fonts

Summary:
Ref T7785. Makes Figlet available without installing the `figlet` package.

The PEAR Text_Figlet code is really sketchy and includes this API, which is quite marvelous:

```
    function loadFont($filename, $loadgerman = true)
```

At some point, this should probably be rewritten into a modern style, but it's not trivial since the figlet file format and rendering engine are somewhat complicated. I made some adjustments:

  - Broke the dependency on the PEAR core.
  - Prevented it from doing any wrong HTML escaping.
  - Looked through it for any glaring security or correctness problems.

This code isn't very pretty or modern, but as far as I can tell it's safe and does render Figlet fonts in a reasonable way.

Test Plan: {F803268}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9408, T7785

Differential Revision: https://secure.phabricator.com/D14102
This commit is contained in:
epriestley 2015-09-13 12:31:07 -07:00
parent 935ced1edd
commit 6bd8ee861c
2 changed files with 56 additions and 48 deletions

View file

@ -15,7 +15,6 @@
* @version CVS: $Id$ * @version CVS: $Id$
* @link http://pear.php.net/package/Text_Figlet * @link http://pear.php.net/package/Text_Figlet
*/ */
require_once 'PEAR.php';
/** /**
* ASCII art text creation * ASCII art text creation
@ -113,23 +112,10 @@ class Text_Figlet
{ {
$this->font = array(); $this->font = array();
if (!file_exists($filename)) { if (!file_exists($filename)) {
//if it does not exist, try the Text_Figlet data directory return self::raiseError('Figlet font file "'
include_once 'PEAR/Config.php';
$config = PEAR_Config::singleton();
$fontdir = $config->get('data_dir') . '/Text_Figlet/fonts/';
//only for filenames without path separators
if (strpos($filename, '/') === false
&& file_exists($fontdir . $filename)
) {
$filename = $fontdir . $filename;
} else {
return PEAR::raiseError('Figlet font file "'
. $filename . $filename
. '" cannot be found', 1); . '" cannot be found', 1);
} }
}
$this->font_comment = ''; $this->font_comment = '';
@ -139,7 +125,7 @@ class Text_Figlet
$compressed = true; $compressed = true;
if (!function_exists('gzcompress')) { if (!function_exists('gzcompress')) {
return PEAR::raiseError('Cannot load gzip compressed fonts since' return self::raiseError('Cannot load gzip compressed fonts since'
. ' gzcompress() is not available.', . ' gzcompress() is not available.',
3); 3);
} }
@ -148,14 +134,14 @@ class Text_Figlet
} }
if (!($fp = fopen($filename, 'rb'))) { if (!($fp = fopen($filename, 'rb'))) {
return PEAR::raiseError('Cannot open figlet font file ' . $filename, 2); return self::raiseError('Cannot open figlet font file ' . $filename, 2);
} }
if (!$compressed) { if (!$compressed) {
/* ZIPed font */ /* ZIPed font */
if (fread($fp, 2) == 'PK') { if (fread($fp, 2) == 'PK') {
if (!function_exists('zip_open')) { if (!function_exists('zip_open')) {
return PEAR::raiseError('Cannot load ZIP compressed fonts since' return self::raiseError('Cannot load ZIP compressed fonts since'
. ' ZIP PHP extension is not available.', . ' ZIP PHP extension is not available.',
5); 5);
} }
@ -163,14 +149,14 @@ class Text_Figlet
fclose($fp); fclose($fp);
if (!($fp = zip_open($filename))) { if (!($fp = zip_open($filename))) {
return PEAR::raiseError('Cannot open figlet font file ' . $filename, 2); return self::raiseError('Cannot open figlet font file ' . $filename, 2);
} }
$name = zip_entry_name(zip_read($fp)); $name = zip_entry_name(zip_read($fp));
zip_close($fp); zip_close($fp);
if (!($fp = fopen('zip://' . realpath($filename) . '#' . $name, 'rb'))) { if (!($fp = fopen('zip://' . realpath($filename) . '#' . $name, 'rb'))) {
return PEAR::raiseError('Cannot open figlet font file ' . $filename, 2); return self::raiseError('Cannot open figlet font file ' . $filename, 2);
} }
$compressed = true; $compressed = true;
@ -193,7 +179,7 @@ class Text_Figlet
$header = explode(' ', fgets($fp, 2048)); $header = explode(' ', fgets($fp, 2048));
if (substr($header[0], 0, 5) <> 'flf2a') { if (substr($header[0], 0, 5) <> 'flf2a') {
return PEAR::raiseError('Unknown FIGlet font format.', 4); return self::raiseError('Unknown FIGlet font format.', 4);
} }
@list ($this->hardblank, $this->height,,, @list ($this->hardblank, $this->height,,,
@ -381,9 +367,9 @@ class Text_Figlet
$str = strtr(implode("\n", $out), $trans); $str = strtr(implode("\n", $out), $trans);
if ($inhtml) { if ($inhtml) {
return '<nobr>'. self::raiseError(
nl2br(str_replace(' ', '&nbsp;', htmlspecialchars($str))). 'Do not use the HTML escaping provided by this class in '.
'</nobr>'; 'a Phabricator context.');
} }
return $str; return $str;
@ -506,5 +492,9 @@ class Text_Figlet
return true; return true;
} }
private static function raiseError($message, $code = 1) {
throw new Exception($message);
}
} }
?>

View file

@ -7,33 +7,28 @@ final class PhabricatorRemarkupFigletBlockInterpreter
return 'figlet'; return 'figlet';
} }
/**
* @phutil-external-symbol class Text_Figlet
*/
public function markupContent($content, array $argv) { public function markupContent($content, array $argv) {
if (!Filesystem::binaryExists('figlet')) { $map = self::getFigletMap();
return $this->markupError(
pht( $font = idx($argv, 'font');
'Unable to locate the `%s` binary. Install figlet.', $font = phutil_utf8_strtolower($font);
'figlet')); if (empty($map[$font])) {
$font = 'standard';
} }
$font = idx($argv, 'font', 'standard'); $root = dirname(phutil_get_library_root('phabricator'));
$safe_font = preg_replace('/[^0-9a-zA-Z-_.]/', '', $font); require_once $root.'/externals/pear-figlet/Text/Figlet.php';
$future = id(new ExecFuture('figlet -f %s', $safe_font))
->setTimeout(15)
->write(trim($content, "\n"));
list($err, $stdout, $stderr) = $future->resolve(); $figlet = new Text_Figlet();
$figlet->loadFont($map[$font]);
if ($err) {
return $this->markupError(
pht(
'Execution of `%s` failed: %s',
'figlet',
$stderr));
}
$result = $figlet->lineEcho($content);
if ($this->getEngine()->isTextMode()) { if ($this->getEngine()->isTextMode()) {
return $stdout; return $result;
} }
return phutil_tag( return phutil_tag(
@ -41,7 +36,30 @@ final class PhabricatorRemarkupFigletBlockInterpreter
array( array(
'class' => 'PhabricatorMonospaced remarkup-figlet', 'class' => 'PhabricatorMonospaced remarkup-figlet',
), ),
$stdout); $result);
}
private static function getFigletMap() {
$root = dirname(phutil_get_library_root('phabricator'));
$dirs = array(
$root.'/externals/figlet/fonts/',
$root.'/externals/pear-figlet/fonts/',
$root.'/resources/figlet/custom/',
);
$map = array();
foreach ($dirs as $dir) {
foreach (Filesystem::listDirectory($dir, false) as $file) {
if (preg_match('/\.flf\z/', $file)) {
$name = phutil_utf8_strtolower($file);
$name = preg_replace('/\.flf\z/', '', $name);
$map[$name] = $dir.$file;
}
}
}
return $map;
} }
} }