- <html>
- <head>
- <link href="/css/html4strict.css" rel="stylesheet" type="text/css" media="screen" />
- <title>Geshi</title>
- </head>
- <body>
- <p>
- <?php
- define('ROOT_DIR', dirname(__FILE__));
- set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'library');
- set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'includes');
- require_once 'prettyfile.php';
- echo pretty_file('geshitest.php', 'html4strict');
- ?>
- </p>
- </body>
- </html>
Syntax coloring of source files
Pretty printing source files by coloring them makes them more readable and more attractive. Nothing more simple with GeSHi and a little piece of code in PHP.
Download GeSHi - Generic Syntax Highlighter. Open the archive geshi-*.bz2.
Organize the content of your site by creating at the root of the site the folders includes for included files and library for your own PHP code. Copy the geshi directory and the geshi.php file from the archive in /includes.
- /
- includes
- geshi
- geshi.php
- library
- prettyfile.php
- includes
Copy the following code in a file called prettyfile.php in /library.
prettyfile.php defines two functions: read_file
and pretty_file
.
read_file
reads an entire file, or a part of it, in a string.
pretty_file
returns the content of a file, or a part of it, properly enhanced for a given computer language.
- require_once 'geshi.php';
The code starts by loading functions from geshi.php. NOTE: Configure your site so the directories /includes and /library are listed in the PHP include path. Add the following lines in your code in the root directory of the site:
define('ROOT_DIR', dirname(__FILE__));
set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'library');
set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'includes');
read_file
- function read_file($file, $startline=0, $endline=0) {
- if ($startline or $endline) {
- $lines=@file($file);
- if (false === $lines) {
- return false;
- }
- $offset=$startline ? $startline-1 : 0;
- if ($endline) {
- $length=$startline ? $endline - $startline + 1 : $endline;
- $lines = array_slice($lines, $offset, $length);
- }
- else {
- $lines = array_slice($lines, $offset);
- }
- $s=implode('', $lines);
- }
- else {
- $s=@file_get_contents($file);
- if (false === $s) {
- return false;
- }
- }
- $s=rtrim($s);
- return $s;
- }
If $startline
and $endline
are both 0, we read the entire file with file_get_contents
.
To extract a part of the file, we read it with file
which returns all the lines in an array. Each line in $lines
includes the end of line character, except maybe the last one.
$lines
is reduced with array_slice
to the wanted portion of the file.
If $startline
is 0, the first $endline
lines are extracted.
If $endline
is 0, all the lines from $startline
to the end of the file are extracted.
If $startline
and $endline
are different from 0, the lines between $startline
and $endline
are extracted.
The resulting array is changed into a single character string with implode
.
Finally, empty lines at the end of the text are removed.
read_file
returns the lines read in $file
in a string or false
in case of error.
pretty_file
- function pretty_file($file, $language, $startline=0, $endline=0) {
- $s=read_file($file, $startline, $endline);
- if (!$s) {
- return false;
- }
- if (!$language) {
- return $s;
- }
- $output = false;
- switch ($language) {
- case 'plain':
- $s = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $s);
- $s = htmlentities($s, ENT_COMPAT, 'UTF-8');
- $output = '<pre class="plain">' . PHP_EOL . $s . '</pre>' . PHP_EOL;
- break;
- default:
- $geshi = new GeSHi($s, $language);
- $geshi->enable_classes(true);
- $geshi->set_header_type(GESHI_HEADER_DIV);
- $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
- $geshi->start_line_numbers_at($startline > 0 ? $startline : 1);
- $geshi->enable_keyword_links(false);
- $geshi->set_tab_width(4);
- // echo '<pre>' . PHP_EOL .$geshi->get_stylesheet( ). '</pre>' . PHP_EOL;
- $output = $geshi->parse_code();
- if ($geshi->error()) {
- return false;
- }
- }
- return $output;
- }
pretty_file
starts by calling read_line
to read $file
from $startline
to $endline
. In case of error, it returns false
.
If $language
is not specified, the content of $file
is returned unformatted. NOTE: Avoid reading a file whose content can be interpreted by a navigator.
If $language
is 'plain'
, the content of $file
is returned in a <pre>
block with its class
attribute set to plain for CSS.
Newlines and indents are neaten and HTML entities are rewritten with htmlentities
. Note that the text if expected to be encoded in UTF-8.
All other values of $language
will call GeSHi.
$geshi
is initialized with the lines to format and the computer language.
Then, before calling parse_code
, the object is configured in order to obtain the smallest output without any CCS code.
pretty_file
returns $output
or false
in case of error.
Write a short document which will test pretty_file
by coloring itself. Save the following code in a file called geshitest.php in the root directory of the site.
- <html>
- <head>
- <link href="/css/html4strict.css" rel="stylesheet" type="text/css" media="screen" />
- <title>Geshi</title>
- </head>
- <body>
- <p>
- <?php
- define('ROOT_DIR', dirname(__FILE__));
- set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'library');
- set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'includes');
- require_once 'prettyfile.php';
- echo pretty_file('geshitest.php', 'html4strict');
- ?>
- </p>
- </body>
- </html>
If we access the document with a navigator, we don't exactly see the expected result.
Notice the <link>
tag which tries to include a style sheet file named /css/html4strict.css. We need to build this file.
Styling
The HTML returned by pretty_file
doesn't contain any CSS. To properly style your pages, ask GeSHi to generate the style sheet and save it in a separate file which you will include in the document. pretty_file
can do it. Just uncomment the line which outputs the style sheet.
- // echo '<pre>' . PHP_EOL .$geshi->get_stylesheet( ). '</pre>' . PHP_EOL;
Reload geshitest.php in your navigator. The source of the style sheet is displayed at the beginning.
/**
* GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
* (http://qbnz.com/highlighter/ and http://geshi.org/)
*/
.html4strict {font-family:"Courier New", Courier, monospace; font-size:10pt;}
.html4strict .de1, .html4strict .de2 {margin:0; padding:0; background:none; vertical-align:top;}
.html4strict .imp {font-weight: bold; color: red;}
.html4strict li, .html4strict .li1 {font-weight: normal; vertical-align:top;}
.html4strict .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.html4strict .kw2 {color: #000000; font-weight: bold;}
.html4strict .kw3 {color: #000066;}
.html4strict .es0 {color: #000099; font-weight: bold;}
.html4strict .br0 {color: #66cc66;}
.html4strict .sy0 {color: #66cc66;}
.html4strict .st0 {color: #ff0000;}
.html4strict .nu0 {color: #cc66cc;}
.html4strict .sc-1 {color: #808080; font-style: italic;}
.html4strict .sc0 {color: #00bbdd;}
.html4strict .sc1 {color: #ddbb00;}
.html4strict .sc2 {color: #009900;}
.html4strict span.xtra { display:block; }
1. <html>
2. <head>
3. <link href="/css/html4strict.css" rel="stylesheet" type="text/css" media="screen" />
4. <title>Geshi</title>
5. </head>
6. <body>
7. <p>
8. <?php
9. define('ROOT_DIR', dirname(__FILE__));
10.
11. set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'library');
12. set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'includes');
13.
14. require_once 'prettyfile.php';
15.
16. echo pretty_file('geshiexample.php', 'html4strict');
17. ?>
18. </p>
19. </body>
20. </html>
The output might differ depending on the version of GeSHi which is installed. Feel free to change some properties like font-family
or font-size
.
Copy the CSS and paste it in a file named after the language of the code, html4strict.css in the example. Save the file in a css folder under the root of your site.
- /
- includes
- geshi
- geshi.php
- library
- prettyfile.php
- css
- html4strict.css
- includes
After you have generated and saved all the CSS files for all the different languages you are publishing, comment out the line in pretty_file
which outputs the stylesheet.
Now, if you reload the document, the CSS file is found and the source code looks fine.
- <html>
- <head>
- <link href="/css/html4strict.css" rel="stylesheet" type="text/css" media="screen" />
- <title>Geshi</title>
- </head>
- <body>
- <p>
- <?php
- define('ROOT_DIR', dirname(__FILE__));
- set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'library');
- set_include_path(get_include_path() . PATH_SEPARATOR . ROOT_DIR . DIRECTORY_SEPARATOR . 'includes');
- require_once 'prettyfile.php';
- echo pretty_file('geshitest.php', 'html4strict');
- ?>
- </p>
- </body>
- </html>
Application
The function from iZend which formats comments with some help from GeSHi:
- require_once 'geshi.php';
- function bbcode($s) {
- static $bbcode = array(
- '#\[br\]#is' => '<br />',
- // '#\[(h[1-6])\](.+?)\[/\1\]#is' => '<\1>\2</\1>',
- '#\[(b|i|u|s)\](.+?)\[/\1\]#is' => '<\1>\2</\1>',
- '#\[(p|pre)\](.+?)\[/\1\]#is' => '<\1>\2</\1>',
- '#\[quote\](.+?)\[/quote\]#is' => '<blockquote>\1</blockquote>',
- '#\[(url)\=(.+?)\](.*?)\[/\1\]#ise' => "filter_var('\\2', FILTER_VALIDATE_URL) ? '<a href=\"\\2\" target=\"_blank\">\\3</a>' : '\\0'",
- '#\[(url)](.*?)\[/\1\]#ise' => "filter_var('\\2', FILTER_VALIDATE_URL) ? '<a href=\"\\2\" target=\"_blank\">\\2</a>' : '\\0'",
- '#\[(e?mail)\=(.+?)\](.*?)\[/\1\]#ise' => "filter_var('\\2', FILTER_VALIDATE_EMAIL) ? '<a href=\"mailto:\\2\">\\3</a>' : '\\0'",
- '#\[(e?mail)\](.*?)\[/\1\]#ise' => "filter_var('\\2', FILTER_VALIDATE_EMAIL) ? '<a href=\"mailto:\\2\">\\2</a>' : '\\0'",
- '#\[code\=(.+?)\](.+?)\[/code\]#ise' => "bbcode_highlite('\\2', '\\1')",
- '#\[code\](.+?)\[/code\]#ise' => "bbcode_highlite('\\1')",
- );
- $s = preg_replace('#\[code([^\]]*?)\](.*?)\[/code\]#ise', "'[code\\1]'.bbcode_protect('\\2').'[/code]'", $s);
- $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
- return preg_replace(array_keys($bbcode), array_values($bbcode), $s);
- }
- function bbcode_protect($s) {
- return base64_encode(preg_replace('#\\\"#', '"', $s));
- }
- function bbcode_highlite($s, $language=false) {
- $s = trim(base64_decode($s));
- if (!$language) {
- return '<code>' . htmlspecialchars($s, ENT_COMPAT, 'UTF-8') . '</code>';
- }
- $geshi = new GeSHi($s, $language);
- $geshi->enable_classes(true);
- $geshi->set_header_type(GESHI_HEADER_DIV);
- $geshi->enable_keyword_links(false);
- $geshi->set_tab_width(4);
- $output = $geshi->parse_code();
- if ($geshi->error()) {
- return false;
- }
- head('stylesheet', 'geshi/' . $language, 'screen');
- return '<div class="geshi">' . $output . '</div>';
- }
Comments