Source for file mvblog_common.php

Documentation is available at mvblog_common.php

  1. <?php
  2. /**
  3.  * MvBlog -- An open source no-nosense blogtool
  4.  *
  5.  * Copyright (C) 2005-2007, Michiel van Baak
  6.  * Michiel van Baak <mvanbaak@users.sourceforge.net>
  7.  *
  8.  * See http://dev.mvblog.org for more information on MvBlog.
  9.  * That page also provides Bugtrackers, Filereleases etc.
  10.  *
  11.  * This program is free software, distributed under the terms of
  12.  * the GNU General Public License Version 2. See the LICENSE file
  13.  * at the top of the source tree.
  14.  *
  15.  * @package MvBlog
  16.  * @author Michiel van Baak
  17.  * @version %%VERSION%%
  18.  * @copyright 2005-2007 Michiel van Baak
  19.  */
  20.  
  21. /**
  22.  * Class that holds methods that can be used by every part of mvblog
  23.  * @package MvBlog
  24.  */
  25. Class MvBlog_common {
  26.     /* constants */
  27.  
  28.     /* variables */
  29.     /* {{{ */
  30.     /**
  31.      * @var object $db The PEAR::DB connected database
  32.      */
  33.     public $db;
  34.     /**
  35.      * @var string $version The current program version
  36.      */
  37.     public $version    = "%%VERSION%%";
  38.     /**
  39.      * @var array $plugins Array with registered plugins.
  40.      *  The array looks like this:
  41.      *  <pre>
  42.      *  array (
  43.      *    [$type] => "name",
  44.      *    [$type] => "name"
  45.      *  )
  46.      *  </pre>
  47.      *  Where type can be:
  48.      *  - text_output
  49.      */
  50.     public $plugins    = array();
  51.     /**
  52.      * @var array $authors Array with all active authors.
  53.      *  The array looks like this:
  54.      *  <pre>
  55.      *  array (
  56.      *    [id] => "fullname",
  57.      *    [id] => "fullname"
  58.      *  )
  59.      *  </pre>
  60.      */
  61.     public $authors    = array();
  62.     /**
  63.      * @var array $categories Array with all active categories.
  64.      *  The array looks like this:
  65.      *  <pre>
  66.      *  array (
  67.      *    [id] => array(
  68.      *      "id" => id,
  69.      *      "login" => loginname,
  70.      *      "password" => password,
  71.      *      "email" => email address,
  72.      *      "fullname" => userfriendly name,
  73.      *      "active" => 1 if active, 0 or null otherwise,
  74.      *      "website" => full url to authors website
  75.      *    ),
  76.      *    [id] => ....
  77.      *  )
  78.      *  </pre>
  79.      */
  80.     public $categories = array();
  81.     /**
  82.      * @var array $dossiers Array with all the dossiers.
  83.      *  The array looks like this:
  84.      *  <pre>
  85.      *  array (
  86.      *    [id] => array(
  87.      *       "id" => id,
  88.      *       "name" => name
  89.      *    ),
  90.      *    [id] => ...
  91.      *  )
  92.      *  </pre>
  93.      */
  94.     public $dossiers = array();
  95.     /**
  96.      * @var array $settings Array with all active settings.
  97.      *  The array looks like this:
  98.      *  <pre>
  99.      *  array (
  100.      *    [settingname] => "settingvalue",
  101.      *    [settingname] => "settingvalue"
  102.      *  )
  103.      *  </pre>
  104.      *  Current settingnames:
  105.      *  - blogtitle
  106.      *  - blogdescription
  107.      *  - blogkeywords
  108.      *  - postsperpage
  109.      *  - allowanoncomments
  110.      *  - cleanurl
  111.      */
  112.     public $settings   = array();
  113.     /**
  114.      * @var array $menuitems The user configured menuitems
  115.      */
  116.     public $menuitems  = array();
  117.     /**
  118.      * @var string $webroot The webroot for current blog
  119.      */
  120.     public $webroot    = "";
  121.     public $plugman;
  122.     public $active_plugins = array();
  123.  
  124.     /* }}} */
  125.     /* methods */
  126.     /* __construct {{{ */
  127.     /**
  128.      * Setup stuff and handle settings etc and populate the data containers.
  129.      *
  130.      * If one of the default values for the function parameters is changed,
  131.      * please also change the call in mvblog_upgrade constructor.
  132.      *
  133.      * @param string $plugindir Directory where the plugins are.
  134.      * @param int $adminmode Must be 1 if in the admin interface.
  135.      * @param int $upgrade If set to 1 the data containers will not be populated to allow upgrades to them.
  136.      */
  137.     public function __construct($plugindir="plugins/"$adminmode=0$upgrade=0{
  138.         /* start session and output buffering */
  139.         session_start();
  140.         ob_start();
  141.  
  142.         /* handle php bugs with globals overwrite */
  143.         $this->_handle_php_bugs();
  144.  
  145.         /* handle magic quotes */
  146.         $this->_handle_magic_quotes();
  147.  
  148.         /* get settings from ini file */
  149.         if (array_key_exists("config"$GLOBALS))
  150.             $inisettings $GLOBALS["config"]->getSettings();
  151.         else
  152.             $inisettings array();
  153.  
  154.         if (!array_key_exists("database"$inisettings))
  155.             $inisettings["database""";
  156.  
  157.         /* init database connection */
  158.         $this->_init_db($inisettings["database"]);
  159.  
  160.         /* populate the settings array */
  161.         $this->_get_settings();
  162.  
  163.         /* set the language etc */
  164.         putenv("LANG=".$this->lang);
  165.         setlocale(LC_ALL$this->lang);
  166.         $domain 'messages';
  167.         if ($adminmode)
  168.             bindtextdomain($domain"../locale");
  169.         else
  170.             bindtextdomain($domain"locale");
  171.         textdomain($domain);
  172.  
  173.         /* set the timezone (needed for php5.1 and newer) */
  174.         if (function_exists("date_default_timezone_get"&& function_exists("date_default_timezone_set")) {
  175.             $tz @date_default_timezone_get();
  176.             date_default_timezone_set($tz);
  177.         }
  178.  
  179.         /* get base href */
  180.         $this->_get_webroot();
  181.  
  182.         /* populate the active plugins array */
  183.         $this->_get_active_plugins();
  184.  
  185.         if (!$upgrade{
  186.             /* populate the authors array */
  187.             $this->_get_authors();
  188.  
  189.             /* populate the categories array */
  190.             $this->_get_categories();
  191.  
  192.             /* populate the dossiers array */
  193.             $this->_get_dossiers();
  194.  
  195.             /* populate the menuitems array */
  196.             $this->_get_menuitems();
  197.         }
  198.  
  199.         /* plugin handling */
  200.         require_once("plugins.php");
  201.         $plugman new MvBlog_pluginmgr($plugindir$this);
  202.         $plugman->set_active_plugins($this->active_plugins);
  203.         $this->plugman = $plugman;
  204.     }
  205.     /* }}} */
  206.     /* data manipulation methods */
  207.     /* _handle_php_bugs {{{ */
  208.     /**
  209.      * Handle some php bugs.
  210.      *
  211.      * There's some weird bugs when register_globals is on.
  212.      * You can clear them with stuff like this: ?GLOBALS&GLOBALS[bla]=test
  213.      * So what we do is detect this and bail out.
  214.      * We also make sure that if register_globals is on the gpc stuff will be removed from the globals stuff
  215.      */
  216.     protected function _handle_php_bugs({
  217.         /**
  218.          * catch "PHP5 Globals Vulnerability".
  219.          * code taken from Advisory ttp://www.ush.it/2006/01/25/php5-globals-vulnerability/
  220.          */
  221.         if (isset($HTTP_POST_VARS['GLOBALS']|| isset($_POST['GLOBALS']|| isset($HTTP_POST_FILES['GLOBALS']|| isset($_FILES['GLOBALS']||
  222.             isset($HTTP_GET_VARS['GLOBALS']|| isset($_GET['GLOBALS']|| isset($HTTP_COOKIE_VARS['GLOBALS']|| isset($_COOKIE['GLOBALS']))
  223.             die("GLOBAL GPC hacking attemt!");
  224.         /**
  225.          *    if register_globals is on, you cannot turn it off with ini_set.
  226.          *    The vars will be registered before the ini_set is executed.
  227.          *    We can fake register_globals is off by removing the GPCFR keys from
  228.          *    the global var space :) I got the idea from Alan Hogan with his comment on php.net ini_set function docs.
  229.          *    I rewrote it to match mvblog codestyle
  230.          */
  231.         if (ini_get("register_globals")) {
  232.             foreach ($_GET as $key => $value)
  233.                 if (preg_match("/^([a-z]|_){1}([a-z0-9]|_)*$/si"$key))
  234.                     unset($GLOBALS[$key]);
  235.  
  236.             foreach ($_POST as $key => $value)
  237.                 if (preg_match('/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'$key))
  238.                     unset($GLOBALS[$key]);
  239.  
  240.             foreach ($_COOKIE as $key => $value)
  241.                 if (preg_match('/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'$key))
  242.                     unset($GLOBALS[$key]);
  243.  
  244.             foreach ($_FILES as $key => $value)
  245.                 if (preg_match('/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'$key))
  246.                     unset($GLOBALS[$key]);
  247.  
  248.             foreach ($_REQUEST as $key => $value)
  249.                 if (preg_match('/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'$key))
  250.                     unset($GLOBALS[$key]);
  251.         }
  252.     }
  253.     /* }}} */
  254.     /* _handle_magic_quotes {{{ */
  255.     /**
  256.      * Detect wether magic_quotes_gpc is on.
  257.      * If so, it will disable it and get rid of all the automagically added slashes etc
  258.      */
  259.     protected function _handle_magic_quotes({
  260.         /* check for magic_quotes_gpc. If on, remove the escape slashes */
  261.         set_magic_quotes_runtime(0);
  262.         if(get_magic_quotes_gpc(|| ini_get("magic_quotes_sybase")) {
  263.             $_GET     $this->_magic_quotes_strip($_GET);
  264.             $_POST    $this->_magic_quotes_strip($_POST);
  265.             $_COOKIE  $this->_magic_quotes_strip($_COOKIE);
  266.             $_REQUEST array_merge($_GET$_POST$_COOKIE);
  267.             $_FILES   $this->_magic_quotes_strip($_FILES);
  268.             $_ENV     $this->_magic_quotes_strip($_ENV);
  269.             $_SERVER  $this->_magic_quotes_strip($_SERVER);
  270.         }
  271.     }
  272.     /* }}} */
  273.     /* _magic_quotes_strip() {{{ */
  274.     /**
  275.      * strip escape \ signs when magic_quotes_gpc is on in php.ini
  276.      *
  277.      * @param mixed $mixed the input string or array
  278.      * @return mixed the string/array with the magic_quotes_gpc added slashes removed
  279.      */
  280.     protected function _magic_quotes_strip($mixed{
  281.         if(is_array($mixed))
  282.             return array_map(array($this"_magic_quotes_strip")$mixed);
  283.         return stripslashes($mixed);
  284.     }
  285.     /* }}} */
  286.     /* _init_db {{{ */
  287.     /**
  288.      * Create database connection using the PEAR::MDB2 framework and puts this object in class variable db
  289.      */
  290.     protected function _init_db($settings ""{
  291.         require_once("MDB2.php");
  292.         //sqlite has a different scheme, because it's filebased
  293.         if ($settings["type"== "sqlite"{
  294.             if (is_dir("db"))
  295.                 $dsn sprintf("%s:///db/%s.db?mode=0666"$settings["type"]$settings["database"]);
  296.             elseif (is_dir("../db"))
  297.                 $dsn sprintf("%s:///../db/%s.db?mode=0666"$settings["type"]$settings["database"]);
  298.         else {
  299.             $dsn $settings["type"]."://".$settings["username"].":".$settings["password"]."@tcp(".$settings["hostname"].")/".$settings["database"];
  300.             $dsn sprintf("%s://%s:%s@tcp(%s)/%s",
  301.                 $settings["type"]$settings["username"]$settings["password"],
  302.                 $settings["hostname"]$settings["database"]);
  303.         }
  304.  
  305.         $options array(
  306.             "debug"       => 2,
  307.             "portability" => MDB2_PORTABILITY_ALL,
  308.         );
  309.  
  310.         $db =MDB2::connect($dsn$options);
  311.         if (PEAR::isError($db)) {
  312.             die($db->getMessage());
  313.         }
  314.         $this->db = $db;
  315.     }
  316.     /* }}} */
  317.     /* _sanitize {{{ */
  318.     /**
  319.      * Sanitize given data.
  320.      *
  321.      * This function will return an array if array was given, otherwise it will return the input.
  322.      * The array contents or the given string will be sanitized based on the optional options array.
  323.      * Key's with names that are outside a-zA-Z0-9_- will be removed.
  324.      *
  325.      * The optional options parameter is an array. The following keys will be handled:
  326.      * - bbcode: if true, besides the a-zA-Z0-9_- also @[]=/:+.? will be allowed
  327.      * - space: if true, also allow a whitespace character
  328.      * - url: if true, also allow :/+.?
  329.      * - email: if true, also allow @.
  330.      * if no options array is given, only a-zA-Z0-9_- will be allowed (that is without whitespace chars)
  331.      *
  332.      * @param mixed $data The data to sanitize
  333.      * @param array $options Options, see description for possible items
  334.      * @return mixed See description of the function for array structure
  335.      */
  336.     public function _sanitize($data$options=array()) {
  337.         $allowed  "a-zA-Z0-9_\-";
  338.         $allowed .= preg_quote("(){}");
  339.         /* create preg_replace string of characters we allow */
  340.         if (array_key_exists("bbcode"$options )) $allowed .= preg_quote("![]&@=+:/.?;,'\\\"""/")}
  341.         if (array_key_exists("space"$options  )) $allowed .= "\s"}
  342.         if (array_key_exists("url"$options    )) $allowed .= preg_quote("+:/.?""/")}
  343.         if (array_key_exists("email"$options  )) $allowed .= preg_quote("@.")}
  344.  
  345.         $allowed "/[^$allowed]/s";
  346.         if (is_array($data)) {
  347.             /* lets handle the array */
  348.             foreach ($data as $k=>$v{
  349.                 /* if the data is an array too, recurse */
  350.                 if (is_array($v))
  351.                     $v $this->_sanitize($v$options);
  352.  
  353.                 if (!preg_match("/[^a-zA-Z0-9_-]/s"$k)) {
  354.                     /* do the actual sanitizing */
  355.                     $_data[$kpreg_replace($allowed""$v);
  356.                 }
  357.             }
  358.         else {
  359.             /* it's a string, lets process it */
  360.             $_data preg_replace($allowed""$data);
  361.         }
  362.         return $_data;
  363.     }
  364.     /* }}} */
  365.     /* db_quote {{{ */
  366.     /**
  367.      * Quote a fieldname with the database specific quote style
  368.      *
  369.      * @param string fieldname to quote
  370.      * @return string the quoted version
  371.      */
  372.     public function db_quote($field{
  373.         /* get the db type */
  374.         $dbtype $this->db->dbsyntax;
  375.         switch ($dbtype{
  376.             case "mysql" :
  377.                 $return "`".$field."`";
  378.                 break;
  379.             case "pgsql" :
  380.                 $return "\"".$field."\"";
  381.                 break;
  382.             default :
  383.                 $return $field;
  384.                 break;
  385.         }
  386.         return $return;
  387.     }
  388.     /* }}} */
  389.     /* data getters */
  390.     /* _get_settings {{{ */
  391.     /**
  392.      * Get all the settings into an array
  393.      */
  394.     protected function _get_settings({
  395.         $res =$this->db->query("SELECT settingname, settingvalue FROM settings");
  396.         if (PEAR::isError($res)) {
  397.             die($res->getMessage());
  398.         }
  399.  
  400.         // Add default settings as a fallback for when nothing's been set yet.
  401.         $settings array();
  402.         $settings["blogtitle"]         "";
  403.         $settings["blogdescription"]   "";
  404.         $settings["blogkeywords"]      "";
  405.         $settings["postsperpage"]      20;
  406.         $settings["cleanurl"]          "";
  407.         $settings["allowanoncomments"0;
  408.         $settings["dbversion"]         0;
  409.         $settings["show_cat_icons"]    0;
  410.  
  411.         while ($row $res->fetchRow(MDB2_FETCHMODE_ASSOC)) {
  412.             $settings[$row["settingname"]] $row["settingvalue"];
  413.         }
  414.         if (array_key_exists("language"$settings))
  415.             $this->lang     $settings["language"];
  416.         $this->settings = $settings;
  417.     }
  418.     /* }}} */
  419.     /* _get_webroot {{{ */
  420.     /**
  421.      * Get the webroot for the mvblog install
  422.      * Sets the value in class var webroot.
  423.      * This value will always end with a /
  424.      */
  425.     protected function _get_webroot({
  426.         if (array_key_exists("bloglocation"$this->settings&& !empty($this->settings["bloglocation"])) {
  427.             $webroot $this->settings["bloglocation"];
  428.         else {
  429.             if (array_key_exists("HTTPS"$_SERVER&& strtolower($_SERVER["HTTPS"]== "on"{
  430.                 $webroot "https://".strtolower($_SERVER["SERVER_NAME"]);
  431.                 $httpsmode 1;
  432.             else {
  433.                 $webroot "http://".strtolower($_SERVER["SERVER_NAME"]);
  434.                 $httpsmode 0;
  435.             }
  436.             $webroot .= substr($_SERVER["SCRIPT_NAME"]0strpos($_SERVER["SCRIPT_NAME"]"index.php"));
  437.         }
  438.         /* if webroot does not end with a / append it */
  439.         if (substr($webroot-11!= "/")
  440.             $webroot .= "/";
  441.         $this->webroot = $webroot;
  442.     }
  443.     /* }}} */
  444.     /* _get_authors() {{{ */
  445.     /**
  446.      * Get all the authors into an array.
  447.      */
  448.     public function _get_authors({
  449.         /* author with id 0 is for a new author. */
  450.         $authors array(
  451.             => array(
  452.                 "login"    => "login",
  453.                 "password" => "",
  454.                 "email"    => "",
  455.                 "fullname" => "",
  456.                 "active"   => 1,
  457.                 "website"  => ""
  458.             )
  459.         );
  460.  
  461.         $res =$this->db->query("SELECT id,login,password,email,fullname,active,website FROM authors");
  462.         if (PEAR::isError($res)) {
  463.             die($res->getMessage());
  464.         }
  465.         while ($row $res->fetchRow(MDB2_FETCHMODE_ASSOC)) {
  466.             $authors[$row["id"]] array(
  467.                 "login"    => $row["login"],
  468.                 "password" => $row["password"],
  469.                 "email"    => $row["email"],
  470.                 "fullname" => $row["fullname"],
  471.                 "active"   => $row["active"],
  472.                 "website"  => $row["website"]
  473.             );
  474.         }
  475.         $this->authors = $authors;
  476.     }
  477.     /* }}} */
  478.     /* _get_active_plugins {{{ */
  479.     /**
  480.      * Read active plugins from settings and unserialize it so plugmrg can handle it
  481.      */
  482.     protected function _get_active_plugins({
  483.         if (array_key_exists("active_plugins"$this->settings)) {
  484.             $this->active_plugins = unserialize(stripslashes($this->settings["active_plugins"]));
  485.         else {
  486.             $this->active_plugins = array();
  487.         }
  488.     }
  489.     /* }}} */
  490.     /* _get_categories {{{ */
  491.     /**
  492.      * Get all the categories into an array
  493.      */
  494.     protected function _get_categories({
  495.         /* empty one for create new */
  496.         $categories array(
  497.             => array(
  498.                 "name"   => "Category Name",
  499.                 "desc"   => "Category Description",
  500.                 "public" => 1,
  501.                 "active" => 1,
  502.                 "icon"   => 0
  503.             )
  504.         );
  505.         $res =$this->db->query("SELECT * FROM categories");
  506.         if (PEAR::isError($res)) {
  507.             die($res->getMessage());
  508.         }
  509.         while ($row $res->fetchRow(MDB2_FETCHMODE_ASSOC)) {
  510.             $categories[$row["id"