0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-12-22 16:31:53 +00:00

[2.1.2] Refactory merge-library.php script

git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1396 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2007-08-26 17:04:31 +00:00
parent 85cdea0120
commit e45cc503a2
4 changed files with 305 additions and 111 deletions

2
NEWS
View File

@ -32,6 +32,8 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
the $config and $context member variables the $config and $context member variables
. HTML wrapper in DOMLex now takes DTD identifiers into account; doesn't . HTML wrapper in DOMLex now takes DTD identifiers into account; doesn't
really make a difference, but is good for completeness sake really make a difference, but is good for completeness sake
. merge-library.php script refactored for greater code reusability and
PHP4 compatibility
2.1.1, released 2007-08-04 2.1.1, released 2007-08-04
- Fix show-stopper bug in %URI.MakeAbsolute functionality - Fix show-stopper bug in %URI.MakeAbsolute functionality

View File

@ -1,5 +1,7 @@
<?php <?php
require_once 'compat-function-file-put-contents.php';
function assertCli() { function assertCli() {
if (php_sapi_name() != 'cli' && !getenv('PHP_IS_CLI')) { if (php_sapi_name() != 'cli' && !getenv('PHP_IS_CLI')) {
echo 'Script cannot be called from web-browser (if you are calling via cli, echo 'Script cannot be called from web-browser (if you are calling via cli,
@ -7,3 +9,135 @@ set environment variable PHP_IS_CLI to work around this).';
exit; exit;
} }
} }
/**
* Filesystem tools not provided by default; can recursively create, copy
* and delete folders. Some template methods are provided for extensibility.
* @note This class must be instantiated to be used, although it does
* not maintain state.
*/
class FSTools
{
/**
* Recursively creates a directory
* @param string $folder Name of folder to create
* @note Adapted from the PHP manual comment 76612
*/
function mkdir($folder) {
$folders = preg_split("#[\\\\/]#", $folder);
$base = '';
for($i = 0, $c = count($folders); $i < $c; $i++) {
if(empty($folders[$i])) {
if (!$i) {
// special case for root level
$base .= DIRECTORY_SEPARATOR;
}
continue;
}
$base .= $folders[$i];
if(!is_dir($base)){
mkdir($base);
}
$base .= DIRECTORY_SEPARATOR;
}
}
/**
* Copy a file, or recursively copy a folder and its contents; modified
* so that copied files, if PHP, have includes removed
*
* @author Aidan Lister <aidan@php.net>
* @version 1.0.1-modified
* @link http://aidanlister.com/repos/v/function.copyr.php
* @param string $source Source path
* @param string $dest Destination path
* @return bool Returns TRUE on success, FALSE on failure
*/
function copyr($source, $dest) {
// Simple copy for a file
if (is_file($source)) {
return $this->copy($source, $dest);
}
// Make destination directory
if (!is_dir($dest)) {
mkdir($dest);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
if (!$this->copyable($entry)) {
continue;
}
// Deep copy directories
if ($dest !== "$source/$entry") {
$this->copyr("$source/$entry", "$dest/$entry");
}
}
// Clean up
$dir->close();
return true;
}
/**
* Stub for PHP's built-in copy function, can be used to overload
* functionality
*/
function copy($source, $dest) {
return copy($source, $dest);
}
/**
* Overloadable function that tests a filename for copyability. By
* default, everything should be copied; you can restrict things to
* ignore hidden files, unreadable files, etc.
*/
function copyable($file) {
return true;
}
/**
* Delete a file, or a folder and its contents
*
* @author Aidan Lister <aidan@php.net>
* @version 1.0.3
* @link http://aidanlister.com/repos/v/function.rmdirr.php
* @param string $dirname Directory to delete
* @return bool Returns TRUE on success, FALSE on failure
*/
function rmdirr($dirname)
{
// Sanity check
if (!file_exists($dirname)) {
return false;
}
// Simple delete for a file
if (is_file($dirname) || is_link($dirname)) {
return unlink($dirname);
}
// Loop through the folder
$dir = dir($dirname);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Recurse
$this->rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
}
// Clean up
$dir->close();
return rmdir($dirname);
}
}

View File

@ -0,0 +1,107 @@
<?php
// $Id: file_put_contents.php,v 1.27 2007/04/17 10:09:56 arpad Exp $
if (!defined('FILE_USE_INCLUDE_PATH')) {
define('FILE_USE_INCLUDE_PATH', 1);
}
if (!defined('LOCK_EX')) {
define('LOCK_EX', 2);
}
if (!defined('FILE_APPEND')) {
define('FILE_APPEND', 8);
}
/**
* Replace file_put_contents()
*
* @category PHP
* @package PHP_Compat
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
* @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
* @link http://php.net/function.file_put_contents
* @author Aidan Lister <aidan@php.net>
* @version $Revision: 1.27 $
* @internal resource_context is not supported
* @since PHP 5
* @require PHP 4.0.0 (user_error)
*/
function php_compat_file_put_contents($filename, $content, $flags = null, $resource_context = null)
{
// If $content is an array, convert it to a string
if (is_array($content)) {
$content = implode('', $content);
}
// If we don't have a string, throw an error
if (!is_scalar($content)) {
user_error('file_put_contents() The 2nd parameter should be either a string or an array',
E_USER_WARNING);
return false;
}
// Get the length of data to write
$length = strlen($content);
// Check what mode we are using
$mode = ($flags & FILE_APPEND) ?
'a' :
'wb';
// Check if we're using the include path
$use_inc_path = ($flags & FILE_USE_INCLUDE_PATH) ?
true :
false;
// Open the file for writing
if (($fh = @fopen($filename, $mode, $use_inc_path)) === false) {
user_error('file_put_contents() failed to open stream: Permission denied',
E_USER_WARNING);
return false;
}
// Attempt to get an exclusive lock
$use_lock = ($flags & LOCK_EX) ? true : false ;
if ($use_lock === true) {
if (!flock($fh, LOCK_EX)) {
return false;
}
}
// Write to the file
$bytes = 0;
if (($bytes = @fwrite($fh, $content)) === false) {
$errormsg = sprintf('file_put_contents() Failed to write %d bytes to %s',
$length,
$filename);
user_error($errormsg, E_USER_WARNING);
return false;
}
// Close the handle
@fclose($fh);
// Check all the data was written
if ($bytes != $length) {
$errormsg = sprintf('file_put_contents() Only %d of %d bytes written, possibly out of free disk space.',
$bytes,
$length);
user_error($errormsg, E_USER_WARNING);
return false;
}
// Return length
return $bytes;
}
// Define
if (!function_exists('file_put_contents')) {
function file_put_contents($filename, $content, $flags = null, $resource_context = null)
{
return php_compat_file_put_contents($filename, $content, $flags, $resource_context);
}
}

View File

@ -19,7 +19,29 @@ assertCli();
$GLOBALS['loaded'] = array('HTMLPurifier.php' => true); $GLOBALS['loaded'] = array('HTMLPurifier.php' => true);
/** /**
* @param $text Text to replace includes from * Custom FSTools for this script that overloads some behavior
* @warning The overloading of copy() is not necessarily global for
* this script. Watch out!
*/
class MergeLibraryFSTools extends FSTools
{
function copyable($entry) {
// Skip hidden files
if ($entry[0] == '.') {
return false;
}
return true;
}
function copy($source, $dest) {
copy_and_remove_includes($source, $dest);
}
}
$FS = new MergeLibraryFSTools();
/**
* Replaces the includes inside PHP source code with the corresponding
* source.
* @param string $text PHP source code to replace includes from
*/ */
function replace_includes($text) { function replace_includes($text) {
return preg_replace_callback( return preg_replace_callback(
@ -32,6 +54,8 @@ function replace_includes($text) {
/** /**
* Removes leading PHP tags from included files. Assumes that there is * Removes leading PHP tags from included files. Assumes that there is
* no trailing tag. * no trailing tag.
* @note This is safe for files that have internal <?php
* @param string $text Text to have leading PHP tag from
*/ */
function remove_php_tags($text) { function remove_php_tags($text) {
return substr($text, 5); return substr($text, 5);
@ -40,128 +64,44 @@ function remove_php_tags($text) {
/** /**
* Creates an appropriate blank file, recursively generating directories * Creates an appropriate blank file, recursively generating directories
* if necessary * if necessary
* @param string $file Filename to create blank for
*/ */
function create_blank($file) { function create_blank($file) {
global $FS;
$dir = dirname($file); $dir = dirname($file);
$base = realpath('../tests/blanks/') . DIRECTORY_SEPARATOR ; $base = realpath('../tests/blanks/') . DIRECTORY_SEPARATOR ;
if ($dir != '.') mkdir_deep($base . $dir); if ($dir != '.') {
$FS->mkdir($base . $dir);
}
file_put_contents($base . $file, ''); file_put_contents($base . $file, '');
} }
/**
* Recursively creates a directory
* @note Adapted from the PHP manual comment 76612
*/
function mkdir_deep($folder) {
$folders = preg_split("#[\\\\/]#", $folder);
$base = '';
for($i = 0, $c = count($folders); $i < $c; $i++) {
if(empty($folders[$i])) {
if (!$i) {
// special case for root level
$base .= DIRECTORY_SEPARATOR;
}
continue;
}
$base .= $folders[$i];
if(!is_dir($base)){
mkdir($base);
}
$base .= DIRECTORY_SEPARATOR;
}
}
/**
* Copy a file, or recursively copy a folder and its contents
*
* @author Aidan Lister <aidan@php.net>
* @version 1.0.1
* @link http://aidanlister.com/repos/v/function.copyr.php
* @param string $source Source path
* @param string $dest Destination path
* @return bool Returns TRUE on success, FALSE on failure
*/
function copyr($source, $dest) {
// Simple copy for a file
if (is_file($source)) {
return copy_and_remove_includes($source, $dest);
}
// Make destination directory
if (!is_dir($dest)) {
mkdir($dest);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Skip hidden files
if ($entry[0] == '.') {
continue;
}
// Deep copy directories
if ($dest !== "$source/$entry") {
copyr("$source/$entry", "$dest/$entry");
}
}
// Clean up
$dir->close();
return true;
}
/**
* Delete a file, or a folder and its contents
*
* @author Aidan Lister <aidan@php.net>
* @version 1.0.3
* @link http://aidanlister.com/repos/v/function.rmdirr.php
* @param string $dirname Directory to delete
* @return bool Returns TRUE on success, FALSE on failure
*/
function rmdirr($dirname)
{
// Sanity check
if (!file_exists($dirname)) {
return false;
}
// Simple delete for a file
if (is_file($dirname) || is_link($dirname)) {
return unlink($dirname);
}
// Loop through the folder
$dir = dir($dirname);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Recurse
rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
}
// Clean up
$dir->close();
return rmdir($dirname);
}
/** /**
* Copies the contents of a directory to the standalone directory * Copies the contents of a directory to the standalone directory
* @param string $dir Directory to copy
*/ */
function make_dir_standalone($dir) { function make_dir_standalone($dir) {
return copyr($dir, 'standalone/' . $dir); global $FS;
return $FS->copyr($dir, 'standalone/' . $dir);
} }
/**
* Copies the contents of a file to the standalone directory
* @param string $file File to copy
*/
function make_file_standalone($file) { function make_file_standalone($file) {
mkdir_deep('standalone/' . dirname($file)); global $FS;
$FS->mkdir('standalone/' . dirname($file));
copy_and_remove_includes($file, 'standalone/' . $file); copy_and_remove_includes($file, 'standalone/' . $file);
return true; return true;
} }
/**
* Copies a file to another location recursively, if it is a PHP file
* remove includes
* @param string $file Original file
* @param string $sfile New location of file
*/
function copy_and_remove_includes($file, $sfile) { function copy_and_remove_includes($file, $sfile) {
$contents = file_get_contents($file); $contents = file_get_contents($file);
if (strrchr($file, '.') === '.php') $contents = replace_includes($contents); if (strrchr($file, '.') === '.php') $contents = replace_includes($contents);
@ -174,8 +114,13 @@ function copy_and_remove_includes($file, $sfile) {
*/ */
function replace_includes_callback($matches) { function replace_includes_callback($matches) {
$file = $matches[1]; $file = $matches[1];
// PHP 5 only file / PEAR files $preserve = array(
$preserve = array('HTMLPurifier/Lexer/DOMLex.php'=>1, 'HTMLPurifier/Printer.php'=>1, 'XML/HTMLSax3.php'=>1); // PHP 5 only
'HTMLPurifier/Lexer/DOMLex.php' => 1,
'HTMLPurifier/Printer.php' => 1,
// PEAR (external)
'XML/HTMLSax3.php' => 1
);
if (isset($preserve[$file])) { if (isset($preserve[$file])) {
return $matches[0]; return $matches[0];
} }
@ -200,16 +145,22 @@ file_put_contents('HTMLPurifier.standalone.php', $contents);
echo ' done!' . PHP_EOL; echo ' done!' . PHP_EOL;
echo 'Creating standalone directory...'; echo 'Creating standalone directory...';
rmdirr('standalone'); // ensure a clean copy $FS->rmdirr('standalone'); // ensure a clean copy
mkdir_deep('standalone/HTMLPurifier/DefinitionCache/Serializer');
// data files
$FS->mkdir('standalone/HTMLPurifier/DefinitionCache/Serializer');
make_dir_standalone('HTMLPurifier/EntityLookup'); make_dir_standalone('HTMLPurifier/EntityLookup');
// non-standard inclusion setup
make_dir_standalone('HTMLPurifier/Language'); make_dir_standalone('HTMLPurifier/Language');
// optional components
make_file_standalone('HTMLPurifier/Printer.php'); make_file_standalone('HTMLPurifier/Printer.php');
make_dir_standalone('HTMLPurifier/Printer'); make_dir_standalone('HTMLPurifier/Printer');
make_dir_standalone('HTMLPurifier/Filter'); make_dir_standalone('HTMLPurifier/Filter');
make_file_standalone('HTMLPurifier/Lexer/PEARSax3.php'); // not incl by default make_file_standalone('HTMLPurifier/Lexer/PEARSax3.php');
// PHP 5 only files // PHP 5 only files
make_file_standalone('HTMLPurifier/Lexer/DOMLex.php'); make_file_standalone('HTMLPurifier/Lexer/DOMLex.php');
make_file_standalone('HTMLPurifier/Lexer/PH5P.php'); make_file_standalone('HTMLPurifier/Lexer/PH5P.php');
echo ' done!' . PHP_EOL; echo ' done!' . PHP_EOL;