Location: PHPKode > projects > kure > functions.php
<?php

/*LICENSE INFORMATION*
 * Kure is distributed under the terms of the GNU General Public License
 * (http://www.gnu.org/licenses/gpl.html).
 * Kure Copyright 2007-2008 Ben Carlsson
 * 
 *-->
 * This file is part of Kure.
 * 
 * Kure is free software: you can redistribute it and/or modify it under the terms of the 
 * GNU General Public License as published by the Free Software Foundation, either version
 * 3 of the License, or (at your option) any later version.
 * 
 * Kure is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with Kure.  If
 * not, see <http://www.gnu.org/licenses/>.
 *-->
 *
 * Please see index.php for notes.
 */


/***** FILE HANDLING ********************************************************************/

function sort_by_mtime($file1,$file2) {
  $time1 = filemtime($file1);
  $time2 = filemtime($file2);
  if ($time1 == $time2) {
    return 0;
  }
  return ($time1 < $time2) ? 1 : -1;
}

if(!function_exists("file_put_contents")) {
  define('FILE_APPEND', 1);
  function file_put_contents($n, $d, $flag = false) {
    $mode = ($flag == FILE_APPEND || strtoupper($flag) == 'FILE_APPEND') ? 'a' : 'w';
    $f = @fopen($n, $mode);
    if ($f === false) {
      return 0;
    } else {
      if (is_array($d)) {
        $d = implode($d);
      }
      $bytes_written = fwrite($f, $d);
      fclose($f);
      return $bytes_written;
    }
  }
}

if(!function_exists("file_get_contents")) {
  function file_get_contents($filename) {
    return implode("\n", file($filename));
  }
}

function write_config($newcfg) {
global $config, $root;
// writes all values in array $newcfg to config.php with keys as variable names, overwriting current values
// ($newcfg does not need all config options in it; this function will preserve those that are not changed)
// note that if passed string "true" or "false" it will convert to a boolean value, otherwise datatype will be preserved
// returns true on success; false otherwise
  $write = "<?php\n\n// autogenerated by Kure\n\n";
  foreach($config as $option => $value) {
    if(isset($newcfg[$option])) // overwrite current values with passed values, if they were passed
      $newvalue = $newcfg[$option];
    else // otherwise, use the current values
      $newvalue = $value;
    
    $newvalue = config_value($newvalue);
    
    $write .= "\$config['" . config_key($option) . "'] = $newvalue;\n";
  }
  $write .= "\n?>";
  return (bool)(file_put_contents($root . "config.php", $write)); // true on success; false otherwise
}

function config_key($var) {
// returns a format of $var friendly to writing into a config file (as a variable name or key)
  $disallowed = array(
    "`", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "=", "+", "\t", "[",
    "{", "]", "}", "\\", "|", ";", ":", "'", "\"", "\n", ",", "<", ".", ">", "/", "?"
  );
  $var = str_replace($disallowed, "", $var);
  return $var;
}

function config_value($var) {
// returns a format of $var friendly to writing into a config file (as a variable value), e.g.
// if $var is a boolean false, "false" (a string) will be returned;
// if $var is a string "banana", "\"banana\"" will be returned;
// if $var is an int 71, 71 will be returned (no change), etc.
// note that passing this function "false" (string) is the same as passing it false (boolean),
// likewise passing it "14" (string) is the same as passing it 14 (int)
  if(is_bool($var) || $var === "true" || $var === "false") {
  // if it's a boolean, make it a string so it will write as a boolean
    if($var === "true" || $var === "false") return $var;
    else return ($var ? "true" : "false");
  }
  if(ctype_digit($var))
  // if it only contains numeric digits, return its int value
    return (int)$var;
  if(is_numeric($var))
  // if it's a number but contains more than just numeric digits, return its double value
    return (double)$var;
  if(is_string($var))
  // if it's a string, surround it with quotes
    return "\"$var\"";
  exit("<span class=\"error\">Invalid datatype: <tt>write_value($var)</tt></span>");
}

function create_entry($title, $content, $type) {
global $root;
// creates entry with title $title, content $content and of type $type
// returns true on success. exit()s otherwise.
  $title = parse_title($title);
  $content = parse($content);
  if(substr($type, -1) != "s") $type .= "s"; // change "doc" -> "docs" and "post" -> "posts"
  
  if(file_exists($root . $type . "/" . $title . ".txt"))
    error("<span class=\"error\">A post with that name already exists.</span>");
  elseif(!file_put_contents($root . $type . "/" . $title . ".txt", $content))
    error("Could not create file <tt>" . $type . "/" . $title . ".txt</tt>. Check permissions and try again.\n<br /><br />It is also possible that you used an invalid character in your title (titles are used as filenames).</span>");
  return true;
}

function delete_entry($title, $type) {
global $root;
// attempts to delete entry $title of type $type ($type can be "post", "posts", "doc" or "docs")
// returns true on success; false otherwise
  $title = str_replace("../", "", $title);
  $title = str_replace("/", "", $title);
  $title = str_replace("\\", "", $title);
  $title = str_replace(" ", "_", $title);
  
  if(substr($type, -1) != "s") $type .= "s"; // change "doc" -> "docs" and "post" -> "posts"
  return unlink($root . $type . "/" . $title . ".txt");
}

/***** TEMPLATING ***********************************************************************/

function runtemplate($page, $vars = null) {
global $config, $root;
// outputs code from $page in the current template using the variables contained in array $vars

  $code = file_get_contents($root . "templates/" . $config['template'] . "/" . $page . ".html");

  $vars['TITLE'] = $config['blog_name'];
  $vars['SUBTITLE'] = $config['blog_sub'];
  $vars['VERSION'] = $config['kure_ver'];
  
  foreach($vars as $var => $val)
    $code = str_replace("{" . $var . "}", $val, $code);

  // conditionals: show if the config value is true, hide if it is not
  $vars_find = array(
    '/{IF:DOCDATES}(.*?){\/IF:DOCDATES}/is',
    '/{IF:DOCSPAGEDATES}(.*?){\/IF:DOCSPAGEDATES}/is',
    '/{IF:ADMINLINK}(.*?){\/IF:ADMINLINK}/is',
    '/{IF:POST}(.*?){\/IF:POST}/is', 
    '/{IF:DOC}(.*?)\{\/IF:DOC}/is',
  );
  
  if($config['docdates']) $vars_replace[] = '$1';
  else $vars_replace[] = '';
  
  if($config['docspagedates']) $vars_replace[] = '$1';
  else $vars_replace[] = '';
  
  if($config['showadmin']) $vars_replace[] = '$1';
  else $vars_replace[] = '';
  
  if($vars['ENTRYTYPE'] == "post") $vars_replace[] = '$1'; 
  else $vars_replace[] = '';
  
  if($vars['ENTRYTYPE'] == "doc") $vars_replace[] = '$1';
  else $vars_replace[] = '';
  
  $code = preg_replace($vars_find, $vars_replace, $code);
  // end conditionals
  
  // start hook processing
  
  // todo: convert this into a preg_replace so that hooks don't need to be "defined" somewhere
  $hook_pages = array(
    "kure" => array("head", "top", "title_before", "title_after", "navtitle_before", "navtitle_after", "navposts_after", "navdocs_after", "navadmin_after", "page_top", "page_bottom", "bottom"),
    "posts" => array("top", "bottom", "post_top", "post-title_after", "post-date_after", "post-body_after"),
    "post" => array("top", "title_after", "date_after", "body_after"),
    "docs" => array("top", "bottom", "doc-title_after", "doc-body_after"), 
    "doc" => array("top", "title_after", "date_after", "body_after"),
    "adm" => array("head", "top"),
    "admcreate" => array("top", "title_after", "content_after", "type_after", "button_after"),
    "admmodify" => array("top", "title_after", "content_after", "type_after", "button_after"),
    "admplugins" => array("listing", "page")
  );
  
  foreach($hook_pages as $page => $locs)
    foreach($locs as $loc) {
      if(isset($vars['id']))
        $plug = plug($page, $loc, $vars['id']); // if it's a dynamic hook, pass plug() the id for it
      else
        $plug = plug($page, $loc); // if not, then don't
      $code = str_ireplace("{HOOK:" . $page . "-" . $loc . "}", $plug, $code);
    }

  // end hook processing
  
  print($code);
}

/***** PLUGINS **************************************************************************/

/***** FIND PLUGINS *****/
$plugging = false;
$rac[] = true; // mockup array so all our foreach()s don't fail if we don't find plugins
if(file_exists($root . "plugins/")) { // plugins dir is optional
  $findmods = glob($root . "plugins/*.php");
  if(count($findmods) != 0) {
    // intialize our arrays so array_merge_recursive won't fail if they are not arrays by that time
    $rac = array();
    $rack = array();
    foreach($findmods as $weight => $pluginfile) {
      include($pluginfile); // read the plugin ($rack will get set by the plugin during this time)
      $rack = add_dimension($rack, $pluginfile); // turns $rack['posts']['post-body_after'] into $rack['posts']['post-body_after']['pluginfilename.php']
      $rac = array_merge_recursive($rac, $rack); // merge with all other plugins
      unset($rack); // remove all entries from $rack so that they don't overflow into the next plugin's array
    }
  }
}

function plug($page, $hook, $id = false) {
global $plugging, $rac;
// processes and prints plugins in page $page at position $hook
  $plugging = true;
  if(!$id) $output = "";
  if(is_array($rac[$page][$hook])) {
    foreach($rac[$page][$hook] as $file => $html) {
      include($file);
      $output .= ($rack[$page][$hook]); // print refreshed html
    }
  }
  if($id) $output .= plug($page, $hook . "#" . $id); // dynamic plug
  $plugging = false;
  return $output;
}

function add_dimension($array, $dimension) {
// adds dimension $dimension to each element in array $array, e.g. $x['a']['b'] = y; becomes $x['a']['b']['c'] = y;
  if(!is_array($array)) return array($dimension => $array); // base case
  foreach($array as $key => $val)
    $array[$key] = add_dimension($val, $dimension);
  return $array;
}

function set_config($plugin, $config) {
global $root;
// writes all values in array $config to /plugins/config/$plugin.php with keys as variable names
// this function will OVERWRITE the whole file and start clean each time it is called,
// writing only the variables that it is given. this means it must be passed ALL variables every time.
// note that if passed string "true" or "false" it will convert to a boolean value, otherwise datatype will be preserved
// returns true on success; false otherwise
  $plugin = config_key($plugin);
  if(!file_exists($root . "plugins/config")) mkdir($root . "plugins/config");
  $write = "<?php\n\n// plugin config file for $plugin\n// autogenerated by Kure\n\n";
  foreach($config as $option => $value)
    $write .= "\$" . $plugin . "['" . $option . "'] = " . config_value($value) . ";\n";
  $write .= "\n?>";
  
  if(!file_put_contents($root . "plugins/config/$plugin.php", $write))
    return false;
  return true;
}

function get_config($plugin) {
// returns an array containing all config variables for plugin $plugin,
// with variable names as the key and variable values as the value
  $plugin = config_key($plugin);
  include($root . "plugins/config/" . $plugin . ".php");
  return $$plugin; // variable variables: http://php.net/manual/en/language.variables.variable.php
}

/***** PARSING **************************************************************************/

function parse($string) {
// returns a parsed version of $string for use in entry content; removes any php code and applies bbcode
  $string = str_replace("<?", "&lt;?", $string);
  $string = str_replace("?>", "?&gt;", $string);
  $string = str_replace("\\", "", $string);
  
  // start bbcode
  // see http://www.think-ink.net/html/bold.htm
  // for why we use <strong> and <em> instead of <b> and <i>
  $bb_find = array(
    '/\[b\](.*?)\[\/b\]/is',
    '/\[i\](.*?)\[\/i\]/is',
    '/\[u\](.*?)\[\/u\]/is',
    '/\[url\=(.*?)\](.*?)\[\/url\]/is',
    '/\[url\](.*?)\[\/url\]/is',
    '/\[img\](.*?)\[\/img\]/is',
  );
  
  $bb_replace = array(
    '<strong>$1</strong>',
    '<em>$1</em>',
    '<u>$1</u>',
    '<tt><a href="$1" class="content">$2</a></tt>',
    '<tt><a href="$1" class="content">$1</a></tt>',
    '<img src="$1" />',
  );
  
  $string = preg_replace($bb_find, $bb_replace, $string);
  // end bbcode
  
  return $string;
}

function parse_title($string) {
// returns a parsed version of $string for use as an entry filename
  $string = parse($string);
  if(strpos($string, "_") ||
    strpos($string, "/") ||
    strpos($string, "\\")||
    strpos($string, "|") ||
    strpos($string, ":") ||
    strpos($string, "*") ||
    strpos($string, "?") ||
    strpos($string, "\"")||
    strpos($string, "<") ||
    strpos($string, ">") ||
    strpos($string, "../")
  ) exit("Invalid characters in title.");
  $string = str_replace(" ", "_", $string);
  $string = str_replace("../", "", $string);
  return $string;
}

function deparse_title($string) {
// inverse function of parse_title()
  return str_replace("_", " ", $string);
}

function sanitize($string) {
// cleans $string of any attempts to access things it shouldn't
  $string = str_replace("../", "", $string);
  $string = htmlspecialchars($string);
  return $string;
}

function error($string, $exit = true) {
// outputs $string in error format and stops page execution if $exit is true
  print("<span class=\"error\">ERROR: " . $string . "</span><br />");
  if($exit) {
    runtemplate("footer", array()); // print footer
    exit();
  }
}

?>
Return current item: kure