Source for file mvblog_common.php
Documentation is available at
mvblog_common.php
<?php
/**
* MvBlog -- An open source no-nosense blogtool
*
* Copyright (C) 2005-2007, Michiel van Baak
* Michiel van Baak <mvanbaak@users.sourceforge.net>
*
* See http://dev.mvblog.org for more information on MvBlog.
* That page also provides Bugtrackers, Filereleases etc.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*
*
@package
MvBlog
*
@author
Michiel van Baak
*
@version
%%VERSION%%
*
@copyright
2005-2007 Michiel van Baak
*/
/**
* Class that holds methods that can be used by every part of mvblog
*
@package
MvBlog
*/
Class
MvBlog_common
{
/* constants */
/* variables */
/* {{{ */
/**
*
@var
object
$db
The PEAR::DB connected database
*/
public
$db
;
/**
*
@var
string
$version
The current program version
*/
public
$version
=
"%%VERSION%%"
;
/**
*
@var
array
$plugins
Array with registered plugins.
* The array looks like this:
* <pre>
* array (
* [$type] => "name",
* [$type] => "name"
* )
* </pre>
* Where type can be:
* - text_output
*/
public
$plugins
=
array
(
)
;
/**
*
@var
array
$authors
Array with all active authors.
* The array looks like this:
* <pre>
* array (
* [id] => "fullname",
* [id] => "fullname"
* )
* </pre>
*/
public
$authors
=
array
(
)
;
/**
*
@var
array
$categories
Array with all active categories.
* The array looks like this:
* <pre>
* array (
* [id] => array(
* "id" => id,
* "login" => loginname,
* "password" => password,
* "email" => email address,
* "fullname" => userfriendly name,
* "active" => 1 if active, 0 or null otherwise,
* "website" => full url to authors website
* ),
* [id] => ....
* )
* </pre>
*/
public
$categories
=
array
(
)
;
/**
*
@var
array
$dossiers
Array with all the dossiers.
* The array looks like this:
* <pre>
* array (
* [id] => array(
* "id" => id,
* "name" => name
* ),
* [id] => ...
* )
* </pre>
*/
public
$dossiers
=
array
(
)
;
/**
*
@var
array
$settings
Array with all active settings.
* The array looks like this:
* <pre>
* array (
* [settingname] => "settingvalue",
* [settingname] => "settingvalue"
* )
* </pre>
* Current settingnames:
* - blogtitle
* - blogdescription
* - blogkeywords
* - postsperpage
* - allowanoncomments
* - cleanurl
*/
public
$settings
=
array
(
)
;
/**
*
@var
array
$menuitems
The user configured menuitems
*/
public
$menuitems
=
array
(
)
;
/**
*
@var
string
$webroot
The webroot for current blog
*/
public
$webroot
=
""
;
public
$plugman
;
public
$active_plugins
=
array
(
)
;
/* }}} */
/* methods */
/* __construct {{{ */
/**
* Setup stuff and handle settings etc and populate the data containers.
*
* If one of the default values for the function parameters is changed,
* please also change the call in mvblog_upgrade constructor.
*
*
@param
string
$plugindir
Directory where the plugins are.
*
@param
int
$adminmode
Must be 1 if in the admin interface.
*
@param
int
$upgrade
If set to 1 the data containers will not be populated to allow upgrades to them.
*/
public
function
__construct
(
$plugindir
=
"plugins/"
,
$adminmode
=
0
,
$upgrade
=
0
)
{
/* start session and output buffering */
session_start
(
)
;
ob_start
(
)
;
/* handle php bugs with globals overwrite */
$this
->
_handle_php_bugs
(
)
;
/* handle magic quotes */
$this
->
_handle_magic_quotes
(
)
;
/* get settings from ini file */
if
(
array_key_exists
(
"config"
,
$GLOBALS
))
$inisettings
=
$GLOBALS
[
"config"
]
->
getSettings
(
)
;
else
$inisettings
=
array
(
)
;
if
(
!
array_key_exists
(
"database"
,
$inisettings
))
$inisettings
[
"database"
]
=
""
;
/* init database connection */
$this
->
_init_db
(
$inisettings
[
"database"
]
)
;
/* populate the settings array */
$this
->
_get_settings
(
)
;
/* set the language etc */
putenv
(
"LANG="
.
$this
->
lang
)
;
setlocale
(
LC_ALL
,
$this
->
lang
)
;
$domain
=
'messages'
;
if
(
$adminmode
)
bindtextdomain
(
$domain
,
"../locale"
)
;
else
bindtextdomain
(
$domain
,
"locale"
)
;
textdomain
(
$domain
)
;
/* set the timezone (needed for php5.1 and newer) */
if
(
function_exists
(
"date_default_timezone_get"
)
&&
function_exists
(
"date_default_timezone_set"
))
{
$tz
=
@
date_default_timezone_get
(
)
;
date_default_timezone_set
(
$tz
)
;
}
/* get base href */
$this
->
_get_webroot
(
)
;
/* populate the active plugins array */
$this
->
_get_active_plugins
(
)
;
if
(
!
$upgrade
)
{
/* populate the authors array */
$this
->
_get_authors
(
)
;
/* populate the categories array */
$this
->
_get_categories
(
)
;
/* populate the dossiers array */
$this
->
_get_dossiers
(
)
;
/* populate the menuitems array */
$this
->
_get_menuitems
(
)
;
}
/* plugin handling */
require_once
(
"plugins.php"
)
;
$plugman
=
new
MvBlog_pluginmgr
(
$plugindir
,
$this
)
;
$plugman
->
set_active_plugins
(
$this
->
active_plugins
)
;
$this
->
plugman
=
$plugman
;
}
/* }}} */
/* data manipulation methods */
/* _handle_php_bugs {{{ */
/**
* Handle some php bugs.
*
* There's some weird bugs when register_globals is on.
* You can clear them with stuff like this: ?GLOBALS&GLOBALS[bla]=test
* So what we do is detect this and bail out.
* We also make sure that if register_globals is on the gpc stuff will be removed from the globals stuff
*/
protected
function
_handle_php_bugs
(
)
{
/**
* catch "PHP5 Globals Vulnerability".
* code taken from Advisory ttp://www.ush.it/2006/01/25/php5-globals-vulnerability/
*/
if
(
isset
(
$HTTP_POST_VARS
[
'GLOBALS'
]
)
|| isset
(
$_POST
[
'GLOBALS'
]
)
|| isset
(
$HTTP_POST_FILES
[
'GLOBALS'
]
)
|| isset
(
$_FILES
[
'GLOBALS'
]
)
||
isset
(
$HTTP_GET_VARS
[
'GLOBALS'
]
)
|| isset
(
$_GET
[
'GLOBALS'
]
)
|| isset
(
$HTTP_COOKIE_VARS
[
'GLOBALS'
]
)
|| isset
(
$_COOKIE
[
'GLOBALS'
]
))
die
(
"GLOBAL GPC hacking attemt!"
)
;
/**
* if register_globals is on, you cannot turn it off with ini_set.
* The vars will be registered before the ini_set is executed.
* We can fake register_globals is off by removing the GPCFR keys from
* the global var space :) I got the idea from Alan Hogan with his comment on php.net ini_set function docs.
* I rewrote it to match mvblog codestyle
*/
if
(
ini_get
(
"register_globals"
))
{
foreach
(
$_GET
as
$key
=>
$value
)
if
(
preg_match
(
"/^([a-z]|_){1}([a-z0-9]|_)*$/si"
,
$key
))
unset
(
$GLOBALS
[
$key
]
)
;
foreach
(
$_POST
as
$key
=>
$value
)
if
(
preg_match
(
'/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'
,
$key
))
unset
(
$GLOBALS
[
$key
]
)
;
foreach
(
$_COOKIE
as
$key
=>
$value
)
if
(
preg_match
(
'/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'
,
$key
))
unset
(
$GLOBALS
[
$key
]
)
;
foreach
(
$_FILES
as
$key
=>
$value
)
if
(
preg_match
(
'/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'
,
$key
))
unset
(
$GLOBALS
[
$key
]
)
;
foreach
(
$_REQUEST
as
$key
=>
$value
)
if
(
preg_match
(
'/^([a-zA-Z]|_){1}([a-zA-Z0-9]|_)*$/'
,
$key
))
unset
(
$GLOBALS
[
$key
]
)
;
}
}
/* }}} */
/* _handle_magic_quotes {{{ */
/**
* Detect wether magic_quotes_gpc is on.
* If so, it will disable it and get rid of all the automagically added slashes etc
*/
protected
function
_handle_magic_quotes
(
)
{
/* check for magic_quotes_gpc. If on, remove the escape slashes */
set_magic_quotes_runtime
(
0
)
;
if
(
get_magic_quotes_gpc
(
)
||
ini_get
(
"magic_quotes_sybase"
))
{
$_GET
=
$this
->
_magic_quotes_strip
(
$_GET
)
;
$_POST
=
$this
->
_magic_quotes_strip
(
$_POST
)
;
$_COOKIE
=
$this
->
_magic_quotes_strip
(
$_COOKIE
)
;
$_REQUEST
=
array_merge
(
$_GET
,
$_POST
,
$_COOKIE
)
;
$_FILES
=
$this
->
_magic_quotes_strip
(
$_FILES
)
;
$_ENV
=
$this
->
_magic_quotes_strip
(
$_ENV
)
;
$_SERVER
=
$this
->
_magic_quotes_strip
(
$_SERVER
)
;
}
}
/* }}} */
/* _magic_quotes_strip() {{{ */
/**
* strip escape \ signs when magic_quotes_gpc is on in php.ini
*
*
@param
mixed
$mixed
the input string or array
*
@return
mixed
the string/array with the magic_quotes_gpc added slashes removed
*/
protected
function
_magic_quotes_strip
(
$mixed
)
{
if
(
is_array
(
$mixed
))
return
array_map
(
array
(
$this
,
"_magic_quotes_strip"
)
,
$mixed
)
;
return
stripslashes
(
$mixed
)
;
}
/* }}} */
/* _init_db {{{ */
/**
* Create database connection using the PEAR::MDB2 framework and puts this object in class variable db
*/
protected
function
_init_db
(
$settings
=
""
)
{
require_once
(
"MDB2.php"
)
;
//sqlite has a different scheme, because it's filebased
if
(
$settings
[
"type"
]
==
"sqlite"
)
{
if
(
is_dir
(
"db"
))
$dsn
=
sprintf
(
"%s:///db/%s.db?mode=0666"
,
$settings
[
"type"
]
,
$settings
[
"database"
]
)
;
elseif
(
is_dir
(
"../db"
))
$dsn
=
sprintf
(
"%s:///../db/%s.db?mode=0666"
,
$settings
[
"type"
]
,
$settings
[
"database"
]
)
;
}
else
{
$dsn
=
$settings
[
"type"
]
.
"://"
.
$settings
[
"username"
]
.
":"
.
$settings
[
"password"
]
.
"@tcp("
.
$settings
[
"hostname"
]
.
")/"
.
$settings
[
"database"
]
;
$dsn
=
sprintf
(
"%s://%s:%s@tcp(%s)/%s"
,
$settings
[
"type"
]
,
$settings
[
"username"
]
,
$settings
[
"password"
]
,
$settings
[
"hostname"
]
,
$settings
[
"database"
]
)
;
}
$options
=
array
(
"debug"
=>
2
,
"portability"
=>
MDB2_PORTABILITY_ALL
,
)
;
$db
=
&
MDB2
::
connect
(
$dsn
,
$options
)
;
if
(
PEAR
::
isError
(
$db
))
{
die
(
$db
->
getMessage
(
))
;
}
$this
->
db
=
$db
;
}
/* }}} */
/* _sanitize {{{ */
/**
* Sanitize given data.
*
* This function will return an array if array was given, otherwise it will return the input.
* The array contents or the given string will be sanitized based on the optional options array.
* Key's with names that are outside a-zA-Z0-9_- will be removed.
*
* The optional options parameter is an array. The following keys will be handled:
* - bbcode: if true, besides the a-zA-Z0-9_- also @[]=/:+.? will be allowed
* - space: if true, also allow a whitespace character
* - url: if true, also allow :/+.?
* - email: if true, also allow @.
* if no options array is given, only a-zA-Z0-9_- will be allowed (that is without whitespace chars)
*
*
@param
mixed
$data
The data to sanitize
*
@param
array
$options
Options, see description for possible items
*
@return
mixed
See description of the function for array structure
*/
public
function
_sanitize
(
$data
,
$options
=
array
(
))
{
$allowed
=
"a-zA-Z0-9_\-"
;
$allowed
.=
preg_quote
(
"(){}"
)
;
/* create preg_replace string of characters we allow */
if
(
array_key_exists
(
"bbcode"
,
$options
))
{
$allowed
.=
preg_quote
(
"![]&@=+:/.?;,'\\\""
,
"/"
)
;
}
if
(
array_key_exists
(
"space"
,
$options
))
{
$allowed
.=
"\s"
;
}
if
(
array_key_exists
(
"url"
,
$options
))
{
$allowed
.=
preg_quote
(
"+:/.?"
,
"/"
)
;
}
if
(
array_key_exists
(
"email"
,
$options
))
{
$allowed
.=
preg_quote
(
"@."
)
;
}
$allowed
=
"
/[^
$allowed
]/s
"
;
if
(
is_array
(
$data
))
{
/* lets handle the array */
foreach
(
$data
as
$k
=>
$v
)
{
/* if the data is an array too, recurse */
if
(
is_array
(
$v
))
$v
=
$this
->
_sanitize
(
$v
,
$options
)
;
if
(
!
preg_match
(
"/[^a-zA-Z0-9_-]/s"
,
$k
))
{
/* do the actual sanitizing */
$_data
[
$k
]
=
preg_replace
(
$allowed
,
""
,
$v
)
;
}
}
}
else
{
/* it's a string, lets process it */
$_data
=
preg_replace
(
$allowed
,
""
,
$data
)
;
}
return
$_data
;
}
/* }}} */
/* db_quote {{{ */
/**
* Quote a fieldname with the database specific quote style
*
*
@param
string
fieldname to quote
*
@return
string
the quoted version
*/
public
function
db_quote
(
$field
)
{
/* get the db type */
$dbtype
=
$this
->
db
->
dbsyntax
;
switch
(
$dbtype
)
{
case
"mysql"
:
$return
=
"`"
.
$field
.
"`"
;
break
;
case
"pgsql"
:
$return
=
"\""
.
$field
.
"\""
;
break
;
default
:
$return
=
$field
;
break
;
}
return
$return
;
}
/* }}} */
/* data getters */
/* _get_settings {{{ */
/**
* Get all the settings into an array
*/
protected
function
_get_settings
(
)
{
$res
=
&
$this
->
db
->
query
(
"SELECT settingname, settingvalue FROM settings"
)
;
if
(
PEAR
::
isError
(
$res
))
{
die
(
$res
->
getMessage
(
))
;
}
// Add default settings as a fallback for when nothing's been set yet.
$settings
=
array
(
)
;
$settings
[
"blogtitle"
]
=
""
;
$settings
[
"blogdescription"
]
=
""
;
$settings
[
"blogkeywords"
]
=
""
;
$settings
[
"postsperpage"
]
=
20
;
$settings
[
"cleanurl"
]
=
""
;
$settings
[
"allowanoncomments"
]
=
0
;
$settings
[
"dbversion"
]
=
0
;
$settings
[
"show_cat_icons"
]
=
0
;
while
(
$row
=
$res
->
fetchRow
(
MDB2_FETCHMODE_ASSOC
))
{
$settings
[
$row
[
"settingname"
]]
=
$row
[
"settingvalue"
]
;
}
if
(
array_key_exists
(
"language"
,
$settings
))
$this
->
lang
=
$settings
[
"language"
]
;
$this
->
settings
=
$settings
;
}
/* }}} */
/* _get_webroot {{{ */
/**
* Get the webroot for the mvblog install
* Sets the value in class var webroot.
* This value will always end with a /
*/
protected
function
_get_webroot
(
)
{
if
(
array_key_exists
(
"bloglocation"
,
$this
->
settings
)
&&
!
empty
(
$this
->
settings
[
"bloglocation"
]
))
{
$webroot
=
$this
->
settings
[
"bloglocation"
]
;
}
else
{
if
(
array_key_exists
(
"HTTPS"
,
$_SERVER
)
&&
strtolower
(
$_SERVER
[
"HTTPS"
]
)
==
"on"
)
{
$webroot
=
"https://"
.
strtolower
(
$_SERVER
[
"SERVER_NAME"
]
)
;
$httpsmode
=
1
;
}
else
{
$webroot
=
"http://"
.
strtolower
(
$_SERVER
[
"SERVER_NAME"
]
)
;
$httpsmode
=
0
;
}
$webroot
.=
substr
(
$_SERVER
[
"SCRIPT_NAME"
]
,
0
,
strpos
(
$_SERVER
[
"SCRIPT_NAME"
]
,
"index.php"
))
;
}
/* if webroot does not end with a / append it */
if
(
substr
(
$webroot
,
-
1
,
1
)
!=
"/"
)
$webroot
.=
"/"
;
$this
->
webroot
=
$webroot
;
}
/* }}} */
/* _get_authors() {{{ */
/**
* Get all the authors into an array.
*/
public
function
_get_authors
(
)
{
/* author with id 0 is for a new author. */
$authors
=
array
(
0
=>
array
(
"login"
=>
"login"
,
"password"
=>
""
,
"email"
=>
""
,
"fullname"
=>
""
,
"active"
=>
1
,
"website"
=>
""
)
)
;
$res
=
&
$this
->
db
->
query
(
"SELECT id,login,password,email,fullname,active,website FROM authors"
)
;
if
(
PEAR
::
isError
(
$res
))
{
die
(
$res
->
getMessage
(
))
;
}
while
(
$row
=
$res
->
fetchRow
(
MDB2_FETCHMODE_ASSOC
))
{
$authors
[
$row
[
"id"
]]
=
array
(
"login"
=>
$row
[
"login"
]
,
"password"
=>
$row
[
"password"
]
,
"email"
=>
$row
[
"email"
]
,
"fullname"
=>
$row
[
"fullname"
]
,
"active"
=>
$row
[
"active"
]
,
"website"
=>
$row
[
"website"
]
)
;
}
$this
->
authors
=
$authors
;
}
/* }}} */
/* _get_active_plugins {{{ */
/**
* Read active plugins from settings and unserialize it so plugmrg can handle it
*/
protected
function
_get_active_plugins
(
)
{
if
(
array_key_exists
(
"active_plugins"
,
$this
->
settings
))
{
$this
->
active_plugins
=
unserialize
(
stripslashes
(
$this
->
settings
[
"active_plugins"
]
))
;
}
else
{
$this
->
active_plugins
=
array
(
)
;
}
}
/* }}} */
/* _get_categories {{{ */
/**
* Get all the categories into an array
*/
protected
function
_get_categories
(
)
{
/* empty one for create new */
$categories
=
array
(
0
=>
array
(
"name"
=>
"Category Name"
,
"desc"
=>
"Category Description"
,
"public"
=>
1
,
"active"
=>
1
,
"icon"
=>
0
)
)
;
$res
=
&
$this
->
db
->
query
(
"SELECT * FROM categories"
)
;
if
(
PEAR
::
isError
(
$res
))
{
die
(
$res
->
getMessage
(
))
;
}
while
(
$row
=
$res
->
fetchRow
(
MDB2_FETCHMODE_ASSOC
))
{
$categories
[
$row
[
"id"