mirror of
https://github.com/gtbu/Typesetter-5.3-p8.git
synced 2024-11-14 18:59:19 +01:00
1058 lines
23 KiB
PHP
1058 lines
23 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace gp\tool{
|
||
|
|
||
|
defined('is_running') or die('Not an entry point...');
|
||
|
|
||
|
/**
|
||
|
* Contains functions for working with data files and directories
|
||
|
*
|
||
|
*/
|
||
|
class Files{
|
||
|
|
||
|
public static $last_modified; //the modified time of the last file retrieved with gp\tool\Files::Get();
|
||
|
public static $last_version; //the version of the last file retrieved with gp\tool\Files::Get();
|
||
|
public static $last_stats = array(); //the stats of the last file retrieved with gp\tool\Files::Get();
|
||
|
public static $last_meta = array(); //the meta data of the last file retrieved with gp\tool\Files::Get();
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Make sure the $path is a subdirectory of $parent
|
||
|
*
|
||
|
* @param string The file path to check
|
||
|
* @param string The parent file path to check, null to check against $dataDir
|
||
|
* @return bool
|
||
|
*/
|
||
|
public static function CheckPath( $path, $parent = null){
|
||
|
global $dataDir;
|
||
|
|
||
|
if( is_null($parent) ){
|
||
|
$parent = $dataDir;
|
||
|
}
|
||
|
|
||
|
$path = self::Canonicalize($path);
|
||
|
if( strpos($path, $parent) === 0 ){
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return Canonicalized absolute pathname
|
||
|
* Similar to http://php.net/manual/en/function.realpath.php but does not check file existence
|
||
|
*
|
||
|
* @param string $path
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function Canonicalize($path) {
|
||
|
|
||
|
$path = \gp\tool\Editing::Sanitize($path);
|
||
|
$path = str_replace( '\\', '/', $path);
|
||
|
$start_slash = $path[0] == '/' ? '/' : '';
|
||
|
$parts = explode('/', $path);
|
||
|
$parts = array_filter($parts);
|
||
|
$absolutes = array();
|
||
|
|
||
|
foreach( $parts as $part ){
|
||
|
if( '.' == $part ){
|
||
|
continue;
|
||
|
}
|
||
|
if( '..' == $part ){
|
||
|
array_pop($absolutes);
|
||
|
}else{
|
||
|
$absolutes[] = $part;
|
||
|
}
|
||
|
}
|
||
|
return $start_slash . implode('/', $absolutes);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get array from data file
|
||
|
* Example:
|
||
|
* $config = gp\tool\Files::Get('_site/config','config'); or $config = gp\tool\Files::Get('_site/config');
|
||
|
* @since 4.4b1
|
||
|
*
|
||
|
*/
|
||
|
public static function Get( $file, $var_name=null ){
|
||
|
|
||
|
self::$last_modified = null;
|
||
|
self::$last_version = null;
|
||
|
self::$last_stats = array();
|
||
|
self::$last_meta = array();
|
||
|
$file_stats = array();
|
||
|
$fileModTime = time();
|
||
|
$fileVersion = gpversion;
|
||
|
$meta_data = array();
|
||
|
|
||
|
if( !$var_name ){
|
||
|
$var_name = basename($file);
|
||
|
}
|
||
|
|
||
|
$file = self::FilePath($file);
|
||
|
|
||
|
//json
|
||
|
if( gp_data_type === '.json' ){
|
||
|
return self::Get_Json($file,$var_name);
|
||
|
}
|
||
|
|
||
|
if( !file_exists($file) ){
|
||
|
return array();
|
||
|
}
|
||
|
|
||
|
include($file);
|
||
|
if( !isset(${$var_name}) || !is_array(${$var_name}) ){
|
||
|
return array();
|
||
|
}
|
||
|
|
||
|
// For data files older than 3.0
|
||
|
if( !isset($file_stats['modified']) ){
|
||
|
$file_stats['modified'] = $fileModTime;
|
||
|
}
|
||
|
if( !isset($file_stats['gpversion']) ){
|
||
|
$file_stats['gpversion'] = $fileVersion;
|
||
|
}
|
||
|
|
||
|
// File stats
|
||
|
self::$last_modified = $fileModTime;
|
||
|
self::$last_version = $fileVersion;
|
||
|
self::$last_stats = $file_stats;
|
||
|
if( isset($meta_data) ){
|
||
|
self::$last_meta = $meta_data;
|
||
|
}
|
||
|
|
||
|
return ${$var_name};
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Experimental
|
||
|
*
|
||
|
*/
|
||
|
private static function Get_Json($file,$var_name){
|
||
|
|
||
|
if( !file_exists($file) ){
|
||
|
return array();
|
||
|
}
|
||
|
|
||
|
$contents = file_get_contents($file);
|
||
|
$data = json_decode($contents,true);
|
||
|
|
||
|
if( !isset($data[$var_name]) || !is_array($data[$var_name]) ){
|
||
|
return array();
|
||
|
}
|
||
|
|
||
|
// File stats
|
||
|
self::$last_modified = $data['file_stats']['modified'];
|
||
|
self::$last_version = $data['file_stats']['gpversion'];
|
||
|
self::$last_stats = $data['file_stats'];
|
||
|
self::$last_meta = $data['meta_data'];
|
||
|
|
||
|
return $data[$var_name];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get the raw contents of a data file
|
||
|
*
|
||
|
*/
|
||
|
public static function GetRaw($file){
|
||
|
|
||
|
$file = self::FilePath($file);
|
||
|
|
||
|
return file_get_contents($file);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return true if the data file exists
|
||
|
*
|
||
|
*/
|
||
|
public static function Exists($file){
|
||
|
|
||
|
$file = self::FilePath($file);
|
||
|
|
||
|
return file_exists($file);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Read directory and return an array with files corresponding to $filetype
|
||
|
*
|
||
|
* @param string $dir The path of the directory to be read
|
||
|
* @param mixed $filetype If false, all files in $dir will be included. false=all,1=directories,'php'='.php' files
|
||
|
* @return array() List of files in $dir
|
||
|
*/
|
||
|
public static function ReadDir($dir,$filetype='php'){
|
||
|
$files = array();
|
||
|
if( !file_exists($dir) ){
|
||
|
return $files;
|
||
|
}
|
||
|
$dh = @opendir($dir);
|
||
|
if( !$dh ){
|
||
|
return $files;
|
||
|
}
|
||
|
|
||
|
while( ($file = readdir($dh)) !== false){
|
||
|
if( $file == '.' || $file == '..' ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//get all
|
||
|
if( $filetype === false ){
|
||
|
$files[$file] = $file;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//get directories
|
||
|
if( $filetype === 1 ){
|
||
|
$fullpath = $dir.'/'.$file;
|
||
|
if( is_dir($fullpath) ){
|
||
|
$files[$file] = $file;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$dot = strrpos($file, '.');
|
||
|
if( $dot === false ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$type = substr($file, $dot + 1);
|
||
|
|
||
|
//if $filetype is an array
|
||
|
if( is_array($filetype) ){
|
||
|
if( in_array($type, $filetype) ){
|
||
|
$files[$file] = $file;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//if $filetype is a string
|
||
|
if( $type == $filetype ){
|
||
|
$file = substr($file, 0, $dot);
|
||
|
$files[$file] = $file;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
closedir($dh);
|
||
|
|
||
|
return $files;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Read all of the folders and files within $dir and return them in an organized array
|
||
|
*
|
||
|
* @param string $dir The directory to be read
|
||
|
* @return array() The folders and files within $dir
|
||
|
*
|
||
|
*/
|
||
|
public static function ReadFolderAndFiles($dir){
|
||
|
$dh = @opendir($dir);
|
||
|
if( !$dh ){
|
||
|
return array();
|
||
|
}
|
||
|
|
||
|
$folders = array();
|
||
|
$files = array();
|
||
|
while( ($file = readdir($dh)) !== false){
|
||
|
if( strpos($file, '.') === 0){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$fullPath = $dir. '/'. $file;
|
||
|
if( is_dir($fullPath) ){
|
||
|
$folders[] = $file;
|
||
|
}else{
|
||
|
$files[] = $file;
|
||
|
}
|
||
|
}
|
||
|
natcasesort($folders);
|
||
|
natcasesort($files);
|
||
|
return array($folders, $files);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get the Section Clipboard
|
||
|
* @since 5.1-b1
|
||
|
*
|
||
|
*/
|
||
|
public static function GetSectionClipboard(){
|
||
|
global $dataDir;
|
||
|
|
||
|
$clipboard_dir = $dataDir . '/data/_clipboard';
|
||
|
self::CheckDir($clipboard_dir);
|
||
|
$clipboard_data = self::Get($clipboard_dir . '/clipboard_data.php', 'clipboard_data');
|
||
|
|
||
|
return $clipboard_data;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Save the Section Clipboard
|
||
|
* @since 5.1-b1
|
||
|
*
|
||
|
*/
|
||
|
public static function SaveSectionClipboard($clipboard_data=array()){
|
||
|
global $dataDir;
|
||
|
|
||
|
$clipboard_dir = $dataDir . '/data/_clipboard';
|
||
|
self::CheckDir($clipboard_dir);
|
||
|
|
||
|
return self::SaveData($clipboard_dir . '/clipboard_data.php', 'clipboard_data', $clipboard_data);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Clean a string for use as a page label (displayed title)
|
||
|
* Similar to CleanTitle() but less restrictive
|
||
|
*
|
||
|
* @param string $title The title to be cleansed
|
||
|
* @return string The cleansed title
|
||
|
*/
|
||
|
public static function CleanLabel($title=''){
|
||
|
|
||
|
$title = str_replace(array('"'), array(''), $title);
|
||
|
$title = str_replace(array('<', '>'), array('_'), $title);
|
||
|
$title = trim($title);
|
||
|
|
||
|
// Remove control characters
|
||
|
return preg_replace('#[[:cntrl:]]#u', '', $title); // [\x00-\x1F\x7F]
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Clean a string of html that may be used as file content
|
||
|
*
|
||
|
* @param string $text The string to be cleansed. Passed by reference
|
||
|
*/
|
||
|
public static function CleanText(&$text){
|
||
|
\gp\tool\Editing::tidyFix($text);
|
||
|
self::rmPHP($text);
|
||
|
self::FixTags($text);
|
||
|
$text = \gp\tool\Plugins::Filter('CleanText',array($text));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Use html parser to check the validity of $text
|
||
|
*
|
||
|
* @param string $text The html content to be checked. Passed by reference
|
||
|
*/
|
||
|
public static function FixTags(&$text){
|
||
|
$gp_html_output = new \gp\tool\Editing\HTML($text);
|
||
|
$text = $gp_html_output->result;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Remove php tags from $text
|
||
|
*
|
||
|
* @param string $text The html content to be checked. Passed by reference
|
||
|
*/
|
||
|
public static function rmPHP(&$text){
|
||
|
$search = array('<?', '<?php', '?>');
|
||
|
$replace = array('<?', '<?php', '?>');
|
||
|
$text = str_replace($search, $replace, $text);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Removes any NULL characters in $string.
|
||
|
* @since 3.0.2
|
||
|
* @param string $string
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function NoNull($string){
|
||
|
$string = preg_replace('/\0+/', '', $string);
|
||
|
return preg_replace('/(\\\\0)+/', '', $string);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Save the content for a new page in /data/_pages/<title>
|
||
|
* @since 1.8a1
|
||
|
*
|
||
|
*/
|
||
|
public static function NewTitle($title, $section_content=false, $type='text'){
|
||
|
// get the file for the title
|
||
|
if( empty($title) ){
|
||
|
return false;
|
||
|
}
|
||
|
$file = self::PageFile($title);
|
||
|
if( !$file ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// organize section data
|
||
|
$file_sections = array();
|
||
|
if( is_array($section_content) && isset($section_content['type']) ){
|
||
|
$file_sections[0] = $section_content;
|
||
|
}elseif( is_array($section_content) ){
|
||
|
$file_sections = $section_content;
|
||
|
}else{
|
||
|
$file_sections[0] = array(
|
||
|
'type' => $type,
|
||
|
'content' => $section_content,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// add meta data
|
||
|
$meta_data = array(
|
||
|
'file_number' => self::NewFileNumber(),
|
||
|
'file_type' => $type,
|
||
|
);
|
||
|
|
||
|
return self::SaveData($file,'file_sections',$file_sections,$meta_data);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return the data file location for a title
|
||
|
* Since v4.6, page files are within a subfolder
|
||
|
* As of v2.3.4, it defaults to an index based file name but falls back on title based file name for backwards compatibility
|
||
|
*
|
||
|
*
|
||
|
* @param string $title
|
||
|
* @return string The path of the data file
|
||
|
*/
|
||
|
public static function PageFile($title){
|
||
|
global $dataDir, $config, $gp_index;
|
||
|
|
||
|
$index_path = false;
|
||
|
|
||
|
// filename based on title index
|
||
|
if( gp_index_filenames && isset($gp_index[$title]) && isset($config['gpuniq']) ){
|
||
|
$index_path = $dataDir . '/data/_pages/' . substr($config['gpuniq'], 0, 7) . '_' . $gp_index[$title] . '/page.php';
|
||
|
}
|
||
|
|
||
|
// using file name instead of index
|
||
|
$normal_path = $dataDir . '/data/_pages/' . str_replace('/', '_', $title) . '/page.php';
|
||
|
if( !$index_path || self::Exists($normal_path) ){
|
||
|
return $normal_path;
|
||
|
}
|
||
|
|
||
|
return $index_path;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
public static function NewFileNumber(){
|
||
|
global $config;
|
||
|
|
||
|
if( !isset($config['file_count']) ){
|
||
|
$config['file_count'] = 0;
|
||
|
}
|
||
|
$config['file_count']++;
|
||
|
|
||
|
\gp\admin\Tools::SaveConfig();
|
||
|
|
||
|
return $config['file_count'];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get the meta data for the specified file
|
||
|
*
|
||
|
* @param string $file
|
||
|
* @return array
|
||
|
*/
|
||
|
public static function GetTitleMeta($file){
|
||
|
self::Get($file,'meta_data');
|
||
|
return self::$last_meta;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return an array of info about the data file
|
||
|
*
|
||
|
*/
|
||
|
public static function GetFileStats($file){
|
||
|
|
||
|
$file_stats = self::Get($file, 'file_stats');
|
||
|
if( $file_stats ){
|
||
|
return $file_stats;
|
||
|
}
|
||
|
|
||
|
return array('created'=> time());
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Save a file with content and data to the server
|
||
|
* This function will be deprecated in future releases. Using it is not recommended
|
||
|
*
|
||
|
* @param string $file The path of the file to be saved
|
||
|
* @param string $contents The contents of the file to be saved
|
||
|
* @param string $code The data to be saved
|
||
|
* @param string $time The unix timestamp to be used for the $fileVersion
|
||
|
* @return bool True on success
|
||
|
*/
|
||
|
public static function SaveFile($file, $contents, $code=false, $time=false){
|
||
|
|
||
|
$result = self::FileStart($file, $time);
|
||
|
if( $result !== false ){
|
||
|
$result .= "\n" . $code;
|
||
|
}
|
||
|
$result .= "\n\n?" . ">\n";
|
||
|
$result .= $contents;
|
||
|
|
||
|
return self::Save($file, $result);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Save raw content to a file to the server
|
||
|
*
|
||
|
* @param string $file The path of the file to be saved
|
||
|
* @param string $contents The contents of the file to be saved
|
||
|
* @return bool True on success
|
||
|
*/
|
||
|
public static function Save($file,$contents){
|
||
|
global $gp_not_writable;
|
||
|
|
||
|
$exists = self::Exists($file);
|
||
|
|
||
|
//make sure directory exists
|
||
|
if( !$exists ){
|
||
|
$dir = \gp\tool::DirName($file);
|
||
|
if( !file_exists($dir) ){
|
||
|
self::CheckDir($dir);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$fp = @fopen($file, 'wb');
|
||
|
if( $fp === false ){
|
||
|
$gp_not_writable[] = $file;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( !flock($fp, LOCK_EX) ){
|
||
|
trigger_error('flock could not be obtained.');
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( !$exists ){
|
||
|
@chmod($file, gp_chmod_file);
|
||
|
}elseif( function_exists('opcache_invalidate') && substr($file, -4) === '.php' ){
|
||
|
opcache_invalidate($file);
|
||
|
}
|
||
|
|
||
|
$return = fwrite($fp, $contents);
|
||
|
|
||
|
flock($fp, LOCK_UN);
|
||
|
fclose($fp);
|
||
|
|
||
|
return ($return !== false);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Rename a file
|
||
|
* @since 4.6
|
||
|
*/
|
||
|
public static function Rename($from, $to){
|
||
|
global $gp_not_writable;
|
||
|
|
||
|
if( !self::WriteLock() ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//make sure directory exists
|
||
|
$dir = \gp\tool::DirName($to);
|
||
|
if( !file_exists($dir) && !self::CheckDir($dir) ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return rename($from, $to);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Replace $to with $from
|
||
|
*
|
||
|
*/
|
||
|
public static function Replace($from, $to){
|
||
|
|
||
|
$temp_dir = '';
|
||
|
|
||
|
// move the $to out of the way if it exists
|
||
|
if( file_exists($to) ){
|
||
|
$temp_dir = $to . '_' . time();
|
||
|
if( !self::rename($to, $temp_dir) ){
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// rename $from -> $to
|
||
|
if( !self::rename($from, $to) ){
|
||
|
if( $temp_dir ){
|
||
|
self::rename($temp_dir, $to);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( !empty($temp_dir) ){
|
||
|
self::RmAll($temp_dir);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get a write lock to prevent simultaneous writing
|
||
|
* @since 3.5.3
|
||
|
*/
|
||
|
public static function WriteLock(){
|
||
|
|
||
|
if( defined('gp_has_lock') ){
|
||
|
return gp_has_lock;
|
||
|
}
|
||
|
|
||
|
$expires = gp_write_lock_time;
|
||
|
if( self::Lock('write', gp_random, $expires) ){
|
||
|
define('gp_has_lock', true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
trigger_error('CMS write lock could not be obtained.');
|
||
|
define('gp_has_lock', false);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get a lock
|
||
|
* Loop and delay to wait for the removal of existing locks (maximum of about .2 of a second)
|
||
|
*
|
||
|
*/
|
||
|
public static function Lock($file, $value, &$expires){
|
||
|
global $dataDir;
|
||
|
|
||
|
$tries = 0;
|
||
|
$lock_file = $dataDir . '/data/_lock_' . sha1($file);
|
||
|
$file_time = 0;
|
||
|
$elapsed = 0;
|
||
|
|
||
|
while( $tries < 1000 ){
|
||
|
|
||
|
if( !file_exists($lock_file) ){
|
||
|
file_put_contents($lock_file, $value);
|
||
|
usleep(100);
|
||
|
}elseif( !$file_time ){
|
||
|
$file_time = filemtime($lock_file);
|
||
|
}
|
||
|
|
||
|
$contents = @file_get_contents($lock_file);
|
||
|
if( $value === $contents ){
|
||
|
@touch($lock_file);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if( $file_time ){
|
||
|
$elapsed = time() - $file_time;
|
||
|
if( $elapsed > $expires ){
|
||
|
@unlink($lock_file);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
clearstatcache();
|
||
|
usleep(100);
|
||
|
$tries++;
|
||
|
}
|
||
|
|
||
|
if( $file_time ){
|
||
|
$expires -= $elapsed;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Remove a lock file if the value matches
|
||
|
*
|
||
|
*/
|
||
|
public static function Unlock($file, $value){
|
||
|
global $dataDir;
|
||
|
|
||
|
$lock_file = $dataDir . '/data/_lock_' . sha1($file);
|
||
|
if( !file_exists($lock_file) ){
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
$contents = @file_get_contents($lock_file);
|
||
|
if( $contents === false ){
|
||
|
return true;
|
||
|
}
|
||
|
if( $value === $contents ){
|
||
|
unlink($lock_file);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Save array(s) to a $file location
|
||
|
* Takes 2n+3 arguments
|
||
|
*
|
||
|
* @param string $file The location of the file to be saved
|
||
|
* @param string $varname The name of the variable being saved
|
||
|
* @param array $array The value of $varname to be saved
|
||
|
*
|
||
|
* @deprecated 4.3.5
|
||
|
*/
|
||
|
public static function SaveArray(){
|
||
|
|
||
|
if( gp_data_type === '.json' ){
|
||
|
throw new Exception('SaveArray() cannot be used for json data. Use SaveData() instead');
|
||
|
}
|
||
|
|
||
|
$args = func_get_args();
|
||
|
$count = count($args);
|
||
|
if( ($count %2 !== 1) || ($count < 3) ){
|
||
|
trigger_error('Wrong argument count ' . $count . ' for \gp\tool\Files::SaveArray() ');
|
||
|
return false;
|
||
|
}
|
||
|
$file = array_shift($args);
|
||
|
|
||
|
$file_stats = array();
|
||
|
$data = '';
|
||
|
while( count($args) ){
|
||
|
$varname = array_shift($args);
|
||
|
$array = array_shift($args);
|
||
|
if( $varname == 'file_stats' ){
|
||
|
$file_stats = $array;
|
||
|
}else{
|
||
|
$data .= self::ArrayToPHP($varname, $array);
|
||
|
$data .= "\n\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$data = self::FileStart($file, time(), $file_stats) . $data;
|
||
|
|
||
|
return self::Save($file, $data);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Save array to a $file location
|
||
|
*
|
||
|
* @param string $file The location of the file to be saved
|
||
|
* @param string $varname The name of the variable being saved
|
||
|
* @param array $array The value of $varname to be saved
|
||
|
* @param array $meta meta data to be saved along with $array
|
||
|
*
|
||
|
*/
|
||
|
public static function SaveData($file, $varname, $array, $meta=array()){
|
||
|
|
||
|
$file = self::FilePath($file);
|
||
|
|
||
|
if( gp_data_type === '.json' ){
|
||
|
$json = self::FileStart_Json($file);
|
||
|
$json[$varname] = $array;
|
||
|
$json['meta_data'] = $meta;
|
||
|
$content = json_encode($json);
|
||
|
}else{
|
||
|
$content = self::FileStart($file);
|
||
|
$content .= self::ArrayToPHP($varname, $array);
|
||
|
$content .= "\n\n";
|
||
|
$content .= self::ArrayToPHP('meta_data', $meta);
|
||
|
}
|
||
|
|
||
|
return self::Save($file, $content);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Experimental
|
||
|
*
|
||
|
*/
|
||
|
private static function FileStart_Json($file, $time=null ){
|
||
|
global $gpAdmin;
|
||
|
|
||
|
if( is_null($time) ){
|
||
|
$time = time();
|
||
|
}
|
||
|
|
||
|
//file stats
|
||
|
$file_stats = self::GetFileStats($file);
|
||
|
$file_stats['gpversion'] = gpversion;
|
||
|
$file_stats['modified'] = $time;
|
||
|
$file_stats['username'] = false;
|
||
|
|
||
|
if( \gp\tool::loggedIn() ){
|
||
|
$file_stats['username'] = $gpAdmin['username'];
|
||
|
}
|
||
|
|
||
|
$json = array();
|
||
|
$json['file_stats'] = $file_stats;
|
||
|
|
||
|
return $json;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return the beginning content of a data file
|
||
|
*
|
||
|
*/
|
||
|
public static function FileStart($file, $time=null, $file_stats=array()){
|
||
|
global $gpAdmin;
|
||
|
|
||
|
if( is_null($time) ){
|
||
|
$time = time();
|
||
|
}
|
||
|
|
||
|
//file stats
|
||
|
$file_stats = (array)$file_stats + self::GetFileStats($file);
|
||
|
$file_stats['gpversion'] = gpversion;
|
||
|
$file_stats['modified'] = $time;
|
||
|
|
||
|
if( \gp\tool::loggedIn() ){
|
||
|
$file_stats['username'] = $gpAdmin['username'];
|
||
|
}else{
|
||
|
$file_stats['username'] = false;
|
||
|
}
|
||
|
|
||
|
return '<' . '?' . 'php'
|
||
|
. "\ndefined('is_running') or die('Not an entry point...');"
|
||
|
. "\n" . '$fileVersion = \'' . gpversion . '\';' // @deprecated 3.0
|
||
|
. "\n" . '$fileModTime = \'' . $time . '\';' // @deprecated 3.0
|
||
|
. "\n" . self::ArrayToPHP('file_stats', $file_stats)
|
||
|
. "\n\n";
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
public static function ArrayToPHP($varname, &$array){
|
||
|
return '$' . $varname . ' = ' . var_export($array, true) . ';';
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Insert a key-value pair into an associative array
|
||
|
*
|
||
|
* @param mixed $search_key Value to search for in existing array to insert before
|
||
|
* @param mixed $new_key Key portion of key-value pair to insert
|
||
|
* @param mixed $new_value Value portion of key-value pair to insert
|
||
|
* @param array $array Array key-value pair will be added to
|
||
|
* @param int $offset Offset distance from where $search_key was found. A value of 1 would insert after $search_key, a value of 0 would insert before $search_key
|
||
|
* @param int $length If length is omitted, nothing is removed from $array. If positive, then that many elements will be removed starting with $search_key + $offset
|
||
|
* @return bool True on success
|
||
|
*/
|
||
|
public static function ArrayInsert($search_key, $new_key, $new_value, &$array, $offset=0, $length=0){
|
||
|
|
||
|
$array_keys = array_keys($array);
|
||
|
$array_values = array_values($array);
|
||
|
|
||
|
$insert_key = array_search($search_key,$array_keys);
|
||
|
if( ($insert_key === null) || ($insert_key === false) ){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
array_splice($array_keys, $insert_key + $offset, $length, $new_key);
|
||
|
array_splice($array_values, $insert_key + $offset, $length, 'fill'); //use fill in case $new_value is an array
|
||
|
$array = array_combine($array_keys, $array_values);
|
||
|
$array[$new_key] = $new_value;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Replace a key-value pair in an associative array
|
||
|
* ArrayReplace() is a shortcut for using \gp\tool\Files::ArrayInsert() with $offset = 0 and $length = 1
|
||
|
*/
|
||
|
public static function ArrayReplace($search_key, $new_key, $new_value, &$array){
|
||
|
return self::ArrayInsert($search_key, $new_key, $new_value, $array, 0, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Check recursively to see if a directory exists, if it doesn't attempt to create it
|
||
|
*
|
||
|
* @param string $dir The directory path
|
||
|
* @param bool $index Whether or not to add an index.hmtl file in the directory
|
||
|
* @return bool True on success
|
||
|
*/
|
||
|
public static function CheckDir($dir, $index=true){
|
||
|
global $config;
|
||
|
|
||
|
if( !file_exists($dir) ){
|
||
|
$parent = \gp\tool::DirName($dir);
|
||
|
self::CheckDir($parent, $index);
|
||
|
|
||
|
|
||
|
//ftp mkdir
|
||
|
if( !@mkdir($dir,gp_chmod_dir) ){
|
||
|
return false;
|
||
|
}
|
||
|
@chmod($dir, gp_chmod_dir); //some systems need more than just the 0755 in the mkdir() function
|
||
|
|
||
|
|
||
|
// make sure there's an index.html file
|
||
|
// only check if we just created the directory, we don't want to keep
|
||
|
// creating an index.html file if a user deletes it
|
||
|
if( $index && gp_dir_index ){
|
||
|
$indexFile = $dir . '/index.html';
|
||
|
if( !file_exists($indexFile) ){
|
||
|
//not using \gp\tool\Files::Save() so we can avoid infinite looping
|
||
|
// (it's safe since we already know the directory exists and we're not concerned about the content)
|
||
|
file_put_contents($indexFile, '<html></html>');
|
||
|
@chmod($indexFile, gp_chmod_file);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Remove a directory
|
||
|
* Will only work if directory is empty
|
||
|
*
|
||
|
*/
|
||
|
public static function RmDir($dir){
|
||
|
return @rmdir($dir);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Remove a file or directory and it's contents
|
||
|
*
|
||
|
*/
|
||
|
public static function RmAll($path){
|
||
|
|
||
|
if( empty($path) ){
|
||
|
return false;
|
||
|
}
|
||
|
if( is_link($path) ){
|
||
|
return @unlink($path);
|
||
|
}
|
||
|
if( !is_dir($path) ){
|
||
|
return @unlink($path);
|
||
|
}
|
||
|
|
||
|
$success = true;
|
||
|
$subDirs = array();
|
||
|
//$files = scandir($path);
|
||
|
$files = self::ReadDir($path, false);
|
||
|
|
||
|
foreach($files as $file){
|
||
|
$full_path = $path . '/' . $file;
|
||
|
|
||
|
if( !is_link($full_path) && is_dir($full_path) ){
|
||
|
$subDirs[] = $full_path;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( !@unlink($full_path) ){
|
||
|
$success = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach($subDirs as $subDir){
|
||
|
if( !self::RmAll($subDir) ){
|
||
|
$success = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( $success ){
|
||
|
return self::RmDir($path);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get the correct path for the data file
|
||
|
* Two valid methods to get a data file path:
|
||
|
* Full path: /var/www/html/site/data/_site/config.php
|
||
|
* Relative: _site/config
|
||
|
*
|
||
|
*/
|
||
|
public static function FilePath($path){
|
||
|
global $dataDir;
|
||
|
|
||
|
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
||
|
|
||
|
if( $ext === 'gpjson' ){
|
||
|
$path = substr($path,0,-7);
|
||
|
|
||
|
}elseif( $ext === 'php' ){
|
||
|
$path = substr($path,0,-4);
|
||
|
|
||
|
}else{
|
||
|
$path = $dataDir . '/data/' . ltrim($path, '/');
|
||
|
}
|
||
|
|
||
|
if( gp_data_type === '.json' ){
|
||
|
return $path . '.gpjson';
|
||
|
}
|
||
|
|
||
|
return $path . '.php';
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @deprecated 3.0
|
||
|
* Use \gp\tool\Editing::CleanTitle() instead
|
||
|
* Used by Simple_Blog1
|
||
|
*/
|
||
|
public static function CleanTitle($title, $spaces='_'){
|
||
|
trigger_error('Deprecated Function');
|
||
|
return \gp\tool\Editing::CleanTitle($title, $spaces);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
namespace{
|
||
|
class gpFiles extends gp\tool\Files{}
|
||
|
}
|