lots of docs

This commit is contained in:
Shish 2009-07-19 08:38:13 +01:00
parent 24b715424b
commit 627ecdbf4c
12 changed files with 648 additions and 139 deletions

43
core/README Normal file
View file

@ -0,0 +1,43 @@
The Highest Level
~~~~~~~~~~~~~~~~~
index.php takes care of loading the globals:
$config -- some variety of Config class
$database -- a class used to get raw SQL access
$page -- a GenericPage object, a data structure which holds all the page parts
$user -- the currently logged in User
then it sends an InitExtEvent and PageRequestEvent, these can each trigger
more events of their own.
Once the chain of events comes to an end, the $page object is passed
to the theme's layout.class.php to be turned into HTML
Events and Extensions
~~~~~~~~~~~~~~~~~~~~~
An event is a little blob of data saying "something happened", possibly
"something happened, here's the specific data". Events are sent with the
send_event() function.
An extension is something which is capable of reacting to events. They
register themselves using the add_event_listener() command. (Although for
subclasses of SimpleExtension, registration is handled automatically).
Themes
~~~~~~
Each extension has a theme with a specific name -- the extension Cake which
is stored in ext/cake/main.php will have a theme called CakeTheme stored in
ext/cake/theme.php. If you want to customise it, create a class in the file
themes/mytheme/cake.theme.php called CustomCakeTheme which extends CakeTheme
and overrides some of its methods.
Generally an extension should only deal with processing data; whenever it
wants to display something, it should pass the $page data structure along
with the data to be displayed to the theme object, and the theme will add
the data into the page.

View file

@ -1,18 +1,38 @@
<?php
/*
* A basic chunk of page
* $header -- the block's title
* $body -- the content
* $section -- where the block should be placed. The default theme supports
* "main" and "left", other themes can add their own areas
* $position -- how far down the section the block should appear, higher
* numbers appear lower. The scale is 0-100 by convention,
* though any number or string will work.
/**
* @package SCore
*/
/**
* A basic chunk of a page
*/
class Block {
/**
* The block's title
*
* @var string
*/
var $header;
/**
* The content
*
* @var string
*/
var $body;
/**
* Where the block should be placed. The default theme supports
* "main" and "left", other themes can add their own areas
*
* @var string
*/
var $section;
/**
* How far down the section the block should appear, higher
* numbers appear lower. The scale is 0-100 by convention,
* though any number or string will work.
*
* @var int
*/
var $position;
public function __construct($header, $body, $section="main", $position=50) {
@ -24,9 +44,10 @@ class Block {
}
/*
* A generic navigation block with a link to the main page. Used
* because "new NavBlock()" is easier than "new Block('Navigation', ..."
/**
* A generic navigation block with a link to the main page.
*
* Used because "new NavBlock()" is easier than "new Block('Navigation', ..."
*/
class NavBlock extends Block {
public function __construct() {

View file

@ -1,13 +1,19 @@
<?php
/*
/**
* Functions which are only in some versions of PHP,
* or only implemented on some platforms
*
* @ignore
* @package SCore
*/
# (PHP 5 >= 5.2.1)
# Based on http://www.phpit.net/
# article/creating-zip-tar-archives-dynamically-php/2/
if(!function_exists('sys_get_temp_dir')) {
/**
* @ignore
*/
function sys_get_temp_dir() {
// Try to get from environment variable
if(!empty($_ENV['TMP'])) {
@ -40,6 +46,9 @@ function sys_get_temp_dir() {
# (PHP >= 5.1)
# from http://www.php.net/inet_pton
if(!function_exists('inet_pton')) {
/**
* @ignore
*/
function inet_pton($ip) {
# ipv4
if(strpos($ip, '.') !== FALSE) {
@ -61,6 +70,9 @@ function inet_pton($ip) {
# (PHP >= 5.1)
# from http://www.php.net/inet_ntop
if(!function_exists('inet_ntop')) {
/**
* @ignore
*/
function inet_ntop($ip) {
if (strlen($ip)==4) {
// ipv4

View file

@ -1,5 +1,9 @@
<?php
/*
/**
* @package SCore
*/
/**
* an abstract interface for altering a name:value pair list
*/
interface Config {
@ -22,9 +26,11 @@ interface Config {
}
/*
/**
* Common methods for manipulating the list, loading and saving is
* left to the concrete implementation
*
* @ignore
*/
abstract class BaseConfig implements Config {
var $values = array();
@ -93,13 +99,15 @@ abstract class BaseConfig implements Config {
}
/*
/**
* Loads the config list from a PHP file; the file should be in the format:
*
* <?php
* $config['foo'] = "bar";
* $config['baz'] = "qux";
* ?>
*
* @ignore
*/
class StaticConfig extends BaseConfig {
public function __construct($filename) {
@ -123,7 +131,7 @@ class StaticConfig extends BaseConfig {
}
/*
/**
* Loads the config list from a table in a given database, the table should
* be called config and have the schema:
*
@ -131,6 +139,8 @@ class StaticConfig extends BaseConfig {
* name VARCHAR(255) NOT NULL,
* value TEXT
* );
*
* @ignore
*/
class DatabaseConfig extends BaseConfig {
var $database = null;

View file

@ -1,12 +1,17 @@
<?php
/**
* @package SCore
*/
require_once "compat.inc.php";
$ADODB_CACHE_DIR=sys_get_temp_dir();
require_once "lib/adodb/adodb.inc.php";
require_once "lib/adodb/adodb-exceptions.inc.php";
/* Querylet {{{
* A fragment of a query, used to build large search queries
/**#@+
* @ignore
*/
// Querylet {{{
class Querylet {
var $sql;
var $variables;
@ -197,17 +202,28 @@ class MemCache implements CacheEngine {
public function get_misses() {return $this->misses;}
}
// }}}
/**#@-*/
/*
/**
* A class for controlled database access
*/
class Database {
/**
* The ADODB database connection object, for anyone who wants direct access
*/
var $db;
var $extensions;
/**
* Meta info about the database engine
*/
var $engine = null;
/**
* The currently active cache engine
*/
var $cache = null;
/*
/**
* Create a new database object using connection info
* stored in config.php in the root shimmie folder
*/
@ -263,6 +279,9 @@ class Database {
}
}
/**
* Execute an SQL query and return an ADODB resultset
*/
public function execute($query, $args=array()) {
$result = $this->db->Execute($query, $args);
if($result === False) {
@ -274,6 +293,9 @@ class Database {
return $result;
}
/**
* Execute an SQL query and return a 2D array
*/
public function get_all($query, $args=array()) {
$result = $this->db->GetAll($query, $args);
if($result === False) {
@ -285,6 +307,9 @@ class Database {
return $result;
}
/**
* Execute an SQL query and return a single row
*/
public function get_row($query, $args=array()) {
$result = $this->db->GetRow($query, $args);
if($result === False) {
@ -301,6 +326,9 @@ class Database {
}
}
/**
* Create a table from pseudo-SQL
*/
public function create_table($name, $data) {
$this->execute($this->engine->create_table_sql($name, $data));
}

View file

@ -1,22 +1,27 @@
<?php
/*
* Event:
* generic parent class
/**
* @package SCore
*/
/**
* Generic parent class for all events.
*
* An event is anything that can be passed around via send_event($blah)
*/
abstract class Event {
public function __construct() {}
}
/*
* InitExtEvent:
/**
* A wake-up call for extensions
*/
class InitExtEvent extends Event {}
/*
* PageRequestEvent:
/**
* A signal that a page has been requested.
*
* User requests /view/42 -> an event is generated with $args = array("view",
* "42"); when an event handler asks $event->page_matches("view"), it returns
* true and ignores the matched part, such that $event->count_args() = 1 and
@ -25,7 +30,6 @@ class InitExtEvent extends Event {}
class PageRequestEvent extends Event {
var $args;
var $arg_count;
var $part_count;
public function __construct($args) {
@ -33,6 +37,11 @@ class PageRequestEvent extends Event {
$this->arg_count = count($args);
}
/**
* Test if the requested path matches a given pattern.
*
* If it matches, store the remaining path elements in $args
*/
public function page_matches($name) {
$parts = explode("/", $name);
$this->part_count = count($parts);
@ -66,18 +75,27 @@ class PageRequestEvent extends Event {
}
/*
* TextFormattingEvent:
* $original - for reference
* $formatted - with formatting applied
* $stripped - with formatting removed
/**
* A signal that some text needs formatting, the event carries
* both the text and the result
*/
class TextFormattingEvent extends Event {
/**
* For reference
*/
var $original;
/**
* with formatting applied
*/
var $formatted;
/**
* with formatting removed
*/
var $stripped;
public function TextFormattingEvent($text) {
public function __construct($text) {
$h_text = html_escape(trim($text));
$this->original = $h_text;
$this->formatted = $h_text;
@ -86,16 +104,36 @@ class TextFormattingEvent extends Event {
}
/*
* LogEvent
* $section = a category, normally the extension name
* $priority = see python
* $message = free text
/**
* A signal that something needs logging
*/
class LogEvent extends Event {
/**
* a category, normally the extension name
*
* @var string
*/
var $section;
/**
* See python...
*
* @var int
*/
var $priority = 0;
/**
* Free text to be logged
*
* @var text
*/
var $message;
/**
* The time that the event was created
*
* @var int
*/
var $time;
public function __construct($section, $priority, $message) {

View file

@ -1,6 +1,15 @@
<?php
/**
* @package SCore
*/
/**
* A base exception to be caught by the upper levels
*/
class SCoreException extends Exception {}
/**
* A fairly common, generic exception
*/
class PermissionDeniedException extends SCoreException {}
?>

View file

@ -1,12 +1,16 @@
<?php
/*
/**
* @package SCore
*/
/**
* A generic extension class, for subclassing
*/
interface Extension {
public function receive_event(Event $event);
}
/*
/**
* send_event(BlahEvent()) -> onBlah($event)
*
* Also loads the theme object into $this->theme if available
@ -40,7 +44,7 @@ abstract class SimpleExtension implements Extension {
}
}
/*
/**
* Several extensions have this in common, make a common API
*/
abstract class FormatterExtension implements Extension {
@ -55,7 +59,7 @@ abstract class FormatterExtension implements Extension {
abstract public function strip($text);
}
/*
/**
* This too is a common class of extension with many methods in common,
* so we have a base class to extend from
*/

View file

@ -1,15 +1,16 @@
<?php
/*
/**
* All the imageboard-specific bits of code should be in this file, everything
* else in /core should be standard SCore bits.
*
* @package SCore
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Classes *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
/**
* An object representing an entry in the images table. As of 2.2, this no
* longer necessarily represents an image per se, but could be a video,
* sound file, or any other supported upload type.
@ -23,8 +24,9 @@ class Image {
var $posted;
var $source;
/*
* Constructors and other instance creators
/**
* One will very rarely construct an image directly, more common
* would be to use Image::by_id, Image::by_hash, etc
*/
public function Image($row=null) {
if(!is_null($row)) {
@ -37,6 +39,11 @@ class Image {
}
}
/**
* Find an image by ID
*
* @var Image
*/
public static function by_id($id) {
assert(is_numeric($id));
global $database;
@ -45,6 +52,11 @@ class Image {
return ($row ? new Image($row) : null);
}
/**
* Find an image by hash
*
* @var Image
*/
public static function by_hash($hash) {
assert(is_string($hash));
global $database;
@ -53,6 +65,11 @@ class Image {
return ($row ? new Image($row) : null);
}
/**
* Pick a random image out of a set
*
* @var Image
*/
public static function by_random($tags=array()) {
assert(is_array($tags));
$max = Image::count_images($tags);
@ -62,6 +79,9 @@ class Image {
else return null;
}
/**
* Search for an array of images
*/
public static function find_images($start, $limit, $tags=array()) {
assert(is_numeric($start));
assert(is_numeric($limit));
@ -87,6 +107,10 @@ class Image {
/*
* Image-related utility functions
*/
/**
* Count the number of image results for a given search
*/
public static function count_images($tags=array()) {
assert(is_array($tags));
global $database;
@ -100,6 +124,9 @@ class Image {
}
}
/**
* Count the number of pages for a given search
*/
public static function count_pages($tags=array()) {
assert(is_array($tags));
global $config, $database;
@ -111,6 +138,15 @@ class Image {
/*
* Accessors & mutators
*/
/**
* Find the next image in the sequence.
*
* Rather than simply $this_id + 1, one must take into account
* deleted images and search queries
*
* @var Image
*/
public function get_next($tags=array(), $next=true) {
assert(is_array($tags));
assert(is_bool($next));
@ -138,14 +174,27 @@ class Image {
return ($row ? new Image($row) : null);
}
/**
* The reverse of get_next
*
* @var Image
*/
public function get_prev($tags=array()) {
return $this->get_next($tags, false);
}
/**
* Find the User who owns this Image
*
* @var User
*/
public function get_owner() {
return User::by_id($this->owner_id);
}
/**
* Get this image's tags as an array
*/
public function get_tag_array() {
global $database;
$cached = $database->cache->get("image-{$this->id}-tags");
@ -164,10 +213,18 @@ class Image {
return $this->tag_array;
}
/**
* Get this image's tags as a string
*/
public function get_tag_list() {
return implode(' ', $this->get_tag_array());
}
/**
* Get the URL for the full size image
*
* @var string
*/
public function get_image_link() {
global $config;
if(strlen($config->get_string('image_ilink')) > 0) {
@ -181,11 +238,22 @@ class Image {
}
}
/**
* Get a short link to the full size image
*
* @deprecated
* @var string
*/
public function get_short_link() {
global $config;
return $this->parse_link_template($config->get_string('image_slink'));
}
/**
* Get the URL for the thumbnail
*
* @var string
*/
public function get_thumb_link() {
global $config;
if(strlen($config->get_string('image_tlink')) > 0) {
@ -199,11 +267,22 @@ class Image {
}
}
/**
* Get the tooltip for this image, formatted according to the
* configured template
*
* @var string
*/
public function get_tooltip() {
global $config;
return $this->parse_link_template($config->get_string('image_tip'), "html_escape");
}
/**
* Figure out where the full size image is on disk
*
* @var string
*/
public function get_image_filename() {
$hash = $this->hash;
$ab = substr($hash, 0, 2);
@ -211,34 +290,69 @@ class Image {
return "images/$ab/$hash";
}
/**
* Figure out where the thumbnail is on disk
*
* @var string
*/
public function get_thumb_filename() {
$hash = $this->hash;
$ab = substr($hash, 0, 2);
return "thumbs/$ab/$hash";
}
/**
* Get the original filename
*
* @var string
*/
public function get_filename() {
return $this->filename;
}
/**
* Get the image's mime type
*
* FIXME: now we handle more than just images
*
* @var string
*/
public function get_mime_type() {
return "image/".($this->ext);
}
/**
* Get the image's filename extension
*
* @var string
*/
public function get_ext() {
return $this->ext;
}
/**
* Get the image's source URL
*
* @var string
*/
public function get_source() {
return $this->source;
}
/**
* Set the image's source URL
*/
public function set_source($source) {
global $database;
if(empty($source)) $source = null;
$database->execute("UPDATE images SET source=? WHERE id=?", array($source, $this->id));
}
/**
* Delete all tags from this image.
*
* Normally in preparation to set them to a new set.
*/
public function delete_tags_from_image() {
global $database;
$database->execute(
@ -247,6 +361,9 @@ class Image {
$database->execute("DELETE FROM image_tags WHERE image_id=?", array($this->id));
}
/**
* Set the tags for this image
*/
public function set_tags($tags) {
global $database;
$tags = Tag::resolve_list($tags);
@ -287,9 +404,8 @@ class Image {
$database->cache->delete("image-{$this->id}-tags");
}
/*
* Other actions
/**
* Delete this image from the database and disk
*/
public function delete() {
global $database;
@ -301,6 +417,11 @@ class Image {
unlink($this->get_thumb_filename());
}
/**
* ...?
*
* @var string
*/
public function parse_link_template($tmpl, $_escape="url_escape") {
global $config;
@ -649,7 +770,15 @@ class Image {
}
}
/**
* A class for organising the tag related functions.
*
* All the methods are static, one should never actually use a tag object.
*/
class Tag {
/**
* Remove any excess fluff from a user-input tag
*/
public static function sanitise($tag) {
assert(is_string($tag));
$tag = preg_replace("/[\s?*]/", "", $tag);
@ -658,16 +787,18 @@ class Tag {
return $tag;
}
/**
* Turn any string or array into a valid tag array
*/
public static function explode($tags) {
assert(is_string($tags) || is_array($tags));
if(is_string($tags)) {
$tags = explode(' ', $tags);
}
else if(is_array($tags)) {
// do nothing
}
else {
die("Tag::explode() only takes strings or arrays");
}
$tags = array_map("trim", $tags);
@ -729,83 +860,14 @@ class Tag {
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Debugging functions *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function get_debug_info() {
global $config, $_event_count;
if(function_exists('memory_get_usage')) {
$i_mem = sprintf("%5.2f", ((memory_get_usage()+512)/1024)/1024);
}
else {
$i_mem = "???";
}
if(function_exists('getrusage')) {
$ru = getrusage();
$i_utime = sprintf("%5.2f", ($ru["ru_utime.tv_sec"]*1e6+$ru["ru_utime.tv_usec"])/1000000);
$i_stime = sprintf("%5.2f", ($ru["ru_stime.tv_sec"]*1e6+$ru["ru_stime.tv_usec"])/1000000);
}
else {
$i_utime = "???";
$i_stime = "???";
}
$i_files = count(get_included_files());
global $_execs;
global $database;
$hits = $database->cache->get_hits();
$miss = $database->cache->get_misses();
$debug = "<br>Took $i_utime + $i_stime seconds and {$i_mem}MB of RAM";
$debug .= "; Used $i_files files and $_execs queries";
$debug .= "; Sent $_event_count events";
$debug .= "; $hits cache hits and $miss misses";
return $debug;
}
// print_obj ($object, $title, $return)
function print_obj($object,$title="Object Information", $return=false) {
global $user;
if(DEBUG && isset($_GET['debug']) && $user->is_admin()) {
$pr = print_r($object,true);
$count = substr_count($pr,"\n")<=25?substr_count($pr,"\n"):25;
$pr = "<textarea rows='".$count."' cols='80'>$pr</textarea>";
if($return) {
return $pr;
} else {
global $page;
$page->add_block(new Block($title,$pr,"main",1000));
return true;
}
}
}
// preset tests.
// Prints the contents of $event->args, even though they are clearly visible in
// the URL bar.
function print_url_args() {
global $event;
print_obj($event->args,"URL Arguments");
}
// Prints all the POST data.
function print_POST() {
print_obj($_POST,"\$_POST");
}
// Prints GET, though this is also visible in the url ( url?var&var&var)
function print_GET() {
print_obj($_GET,"\$_GET");
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Misc functions *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Move a file from PHP's temporary area into shimmie's image storage
* heirachy, or throw an exception trying
*/
function move_upload_to_archive($event) {
$hash = $event->hash;
$ha = substr($hash, 0, 2);
@ -816,6 +878,10 @@ function move_upload_to_archive($event) {
return true;
}
/**
* Given a full size pair of dimentions, return a pair scaled down to fit
* into the configured thumbnail square, with ratio intact
*/
function get_thumbnail_size($orig_width, $orig_height) {
global $config;

View file

@ -1,12 +1,28 @@
<?php
/**
* @package SCore
*/
/**
* A data structure for holding all the bits of data that make up a page.
*
* The various extensions all add whatever they want to this structure,
* then layout.class.php turns it into HTML
*/
class GenericPage {
var $mode = "page";
var $type = "text/html";
/**
* Set what this page should do; page, data, or redirect.
*/
public function set_mode($mode) {
$this->mode = $mode;
}
/**
* Set the page's MIME type
*/
public function set_type($type) {
$this->type = $type;
}
@ -18,10 +34,16 @@ class GenericPage {
var $data = "";
var $filename = null;
/**
* If the page is in "data" mode, this will set the data to be sent
*/
public function set_data($data) {
$this->data = $data;
}
/**
* If the page is in "data" mode, this will set the recommended download filename
*/
public function set_filename($filename) {
$this->filename = $filename;
}
@ -32,6 +54,9 @@ class GenericPage {
// redirect
var $redirect = "";
/**
* If the page is in "redirect" mode, this will set where to redirect to
*/
public function set_redirect($redirect) {
$this->redirect = $redirect;
}
@ -47,29 +72,47 @@ class GenericPage {
var $headers = array();
var $blocks = array();
/**
* If the page is in "page" mode, set the window title
*/
public function set_title($title) {
$this->title = $title;
}
/**
* If the page is in "page" mode, set the main heading
*/
public function set_heading($heading) {
$this->heading = $heading;
}
/**
* If the page is in "page" mode, set the sub heading
*/
public function set_subheading($subheading) {
$this->subheading = $subheading;
}
/**
* If the page is in "page" mode, add a line to the HTML head section
*/
public function add_header($line, $position=50) {
while(isset($this->headers[$position])) $position++;
$this->headers[$position] = $line;
}
/**
* If the page is in "page" mode, add a block of data
*/
public function add_block($block) {
$this->blocks[] = $block;
}
// ==============================================
/**
* display the page according to the mode and data given
*/
public function display() {
global $page;

View file

@ -1,10 +1,19 @@
<?php
/**
* @package SCore
*/
/**
* @ignore
*/
function _new_user($row) {
return new User($row);
}
/*
/**
* An object representing a row in the "users" table.
*
* The currently logged in user will always be accessable via the global variable $user
*/
class User {
var $config;
@ -25,6 +34,10 @@ class User {
* $user = User::by_name("bob"); *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* One will very rarely construct a user directly, more common
* would be to use User::by_id, User::by_session, etc
*/
public function User($row) {
$this->id = int_escape($row['id']);
$this->name = $row['name'];
@ -78,12 +91,21 @@ class User {
* useful user object functions start here
*/
/**
* Test if this user is anonymous (not logged in)
*
* @var bool
*/
public function is_anonymous() {
global $config;
return ($this->id == $config->get_int('anon_id'));
}
/**
* Test if this user is an administrator
*
* @var bool
*/
public function is_admin() {
return $this->admin;
}

View file

@ -1,17 +1,36 @@
<?php
/**
* @package SCore
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Input / Output Sanitising *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Make some data safe for printing into HTML
*
* @var string
*/
function html_escape($input) {
return htmlentities($input, ENT_QUOTES, "UTF-8");
}
/**
* Make sure some data is safe to be used in integer context
*
* @var int
*/
function int_escape($input) {
return (int)$input;
}
/**
* Make sure some data is safe to be used in URL context
*
* @var string
*/
function url_escape($input) {
$input = str_replace('^', '^^', $input);
$input = str_replace('/', '^s', $input);
@ -19,11 +38,21 @@ function url_escape($input) {
return $input;
}
/**
* Make sure some data is safe to be used in SQL context
*
* @var string
*/
function sql_escape($input) {
global $database;
return $database->db->Quote($input);
}
/**
* Turn a human readable filesize into an integer, eg 1KB -> 1024
*
* @var int
*/
function parse_shorthand_int($limit) {
if(is_numeric($limit)) {
return (int)$limit;
@ -45,6 +74,11 @@ function parse_shorthand_int($limit) {
}
}
/**
* Turn an integer into a human readable filesize, eg 1024 -> 1KB
*
* @var string
*/
function to_shorthand_int($int) {
if($int >= pow(1024, 3)) {
return sprintf("%.1fGB", $int / pow(1024, 3));
@ -65,6 +99,12 @@ function to_shorthand_int($int) {
* HTML Generation *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Figure out the correct way to link to a page, taking into account
* things like the nice URLs setting
*
* @var string
*/
function make_link($page=null, $query=null) {
global $config;
@ -103,6 +143,9 @@ function theme_file($filepath) {
* Misc *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ignore
*/
function version_check() {
if(version_compare(PHP_VERSION, "5.0.0") == -1) {
print <<<EOD
@ -114,6 +157,9 @@ EOD;
}
}
/**
* @ignore
*/
function check_cli() {
if(isset($_SERVER['REMOTE_ADDR'])) {
print "This script is to be run from the command line only.";
@ -122,7 +168,11 @@ function check_cli() {
$_SERVER['REMOTE_ADDR'] = "127.0.0.1";
}
# $db is the connection object
/**
* $db is the connection object
*
* @ignore
*/
function _count_execs($db, $sql, $inputarray) {
global $_execs;
if(DEBUG) {
@ -143,6 +193,9 @@ function _count_execs($db, $sql, $inputarray) {
$null = null; return $null;
}
/**
* Find the theme object for a given extension
*/
function get_theme_object(Extension $class, $fatal=true) {
$base = get_class($class);
if(class_exists("Custom{$base}Theme")) {
@ -157,6 +210,11 @@ function get_theme_object(Extension $class, $fatal=true) {
}
}
/**
* Compare two Block objects, used to sort them before being displayed
*
* @var int
*/
function blockcmp($a, $b) {
if($a->position == $b->position) {
return 0;
@ -166,6 +224,11 @@ function blockcmp($a, $b) {
}
}
/**
* Figure out PHP's internal memory limit
*
* @var int
*/
function get_memory_limit() {
global $config;
@ -190,6 +253,12 @@ function get_memory_limit() {
return $memory;
}
/**
* Get the currently active IP, masked to make it not change when the last
* octet or two change, for use in session cookies and such
*
* @var string
*/
function get_session_ip($config) {
$mask = $config->get_string("session_hash_mask", "255.255.0.0");
$addr = $_SERVER['REMOTE_ADDR'];
@ -197,8 +266,12 @@ function get_session_ip($config) {
return $addr;
}
/*
/**
* Figure out the path to the shimmie install root.
*
* PHP really, really sucks.
*
* @var string
*/
function get_base_href() {
$possible_vars = array('SCRIPT_NAME', 'PHP_SELF', 'PATH_INFO', 'ORIG_PATH_INFO');
@ -215,6 +288,12 @@ function get_base_href() {
return $dir;
}
/**
* A shorthand way to send a TextFormattingEvent and get the
* results
*
* @var string
*/
function format_text($string) {
$tfe = new TextFormattingEvent($string);
send_event($tfe);
@ -246,6 +325,11 @@ function log_info($section, $message) {
* Things which should be in the core API *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Remove an item from an array
*
* @var array
*/
function array_remove($array, $to_remove) {
$array = array_unique($array);
$a2 = array();
@ -257,13 +341,22 @@ function array_remove($array, $to_remove) {
return $a2;
}
/**
* Add an item to an array
*
* @var array
*/
function array_add($array, $element) {
$array[] = $element;
$array = array_unique($array);
return $array;
}
// case insensetive uniqueness
/**
* Return the unique elements of an array, case insensitively
*
* @var array
*/
function array_iunique($array) {
$ok = array();
foreach($array as $element) {
@ -280,7 +373,13 @@ function array_iunique($array) {
return $ok;
}
// from http://uk.php.net/network
/**
* Figure out if an IP is in a specified range
*
* from http://uk.php.net/network
*
* @var bool
*/
function ip_in_range($IP, $CIDR) {
list ($net, $mask) = split ("/", $CIDR);
@ -294,8 +393,12 @@ function ip_in_range($IP, $CIDR) {
return ($ip_ip_net == $ip_net);
}
// from a patch by Christian Walde; only intended for use in the
// "extension manager" extension, but it seems to fit better here
/**
* Delete an entire file heirachy
*
* from a patch by Christian Walde; only intended for use in the
* "extension manager" extension, but it seems to fit better here
*/
function deltree($f) {
if (is_link($f)) {
unlink($f);
@ -312,7 +415,11 @@ function deltree($f) {
}
}
// from a comment on http://uk.php.net/copy
/**
* Copy an entire file heirachy
*
* from a comment on http://uk.php.net/copy
*/
function full_copy($source, $target) {
if(is_dir($source)) {
@mkdir($target);
@ -338,10 +445,16 @@ function full_copy($source, $target) {
}
}
/**
* @ignore
*/
function stripslashes_r($arr) {
return is_array($arr) ? array_map('stripslashes_r', $arr) : stripslashes($arr);
}
/**
* @ignore
*/
function sanitise_environment() {
if(DEBUG) {
error_reporting(E_ALL);
@ -358,6 +471,9 @@ function sanitise_environment() {
}
}
/**
* @ignore
*/
function weighted_random($weights) {
$total = 0;
foreach($weights as $k => $w) {
@ -377,8 +493,14 @@ function weighted_random($weights) {
* Event API *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ignore
*/
$_event_listeners = array();
/**
* Register an Extension
*/
function add_event_listener(Extension $extension, $pos=50) {
global $_event_listeners;
while(isset($_event_listeners[$pos])) {
@ -387,7 +509,14 @@ function add_event_listener(Extension $extension, $pos=50) {
$_event_listeners[$pos] = $extension;
}
/**
* @ignore
*/
$_event_count = 0;
/**
* Send an event to all registered Extensions
*/
function send_event(Event $event) {
global $_event_listeners, $_event_count;
$my_event_listeners = $_event_listeners; // http://bugs.php.net/bug.php?id=35106
@ -399,15 +528,90 @@ function send_event(Event $event) {
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Debugging functions *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function get_debug_info() {
global $config, $_event_count;
if(function_exists('memory_get_usage')) {
$i_mem = sprintf("%5.2f", ((memory_get_usage()+512)/1024)/1024);
}
else {
$i_mem = "???";
}
if(function_exists('getrusage')) {
$ru = getrusage();
$i_utime = sprintf("%5.2f", ($ru["ru_utime.tv_sec"]*1e6+$ru["ru_utime.tv_usec"])/1000000);
$i_stime = sprintf("%5.2f", ($ru["ru_stime.tv_sec"]*1e6+$ru["ru_stime.tv_usec"])/1000000);
}
else {
$i_utime = "???";
$i_stime = "???";
}
$i_files = count(get_included_files());
global $_execs;
global $database;
$hits = $database->cache->get_hits();
$miss = $database->cache->get_misses();
$debug = "<br>Took $i_utime + $i_stime seconds and {$i_mem}MB of RAM";
$debug .= "; Used $i_files files and $_execs queries";
$debug .= "; Sent $_event_count events";
$debug .= "; $hits cache hits and $miss misses";
return $debug;
}
// print_obj ($object, $title, $return)
function print_obj($object,$title="Object Information", $return=false) {
global $user;
if(DEBUG && isset($_GET['debug']) && $user->is_admin()) {
$pr = print_r($object,true);
$count = substr_count($pr,"\n")<=25?substr_count($pr,"\n"):25;
$pr = "<textarea rows='".$count."' cols='80'>$pr</textarea>";
if($return) {
return $pr;
} else {
global $page;
$page->add_block(new Block($title,$pr,"main",1000));
return true;
}
}
}
// preset tests.
// Prints the contents of $event->args, even though they are clearly visible in
// the URL bar.
function print_url_args() {
global $event;
print_obj($event->args,"URL Arguments");
}
// Prints all the POST data.
function print_POST() {
print_obj($_POST,"\$_POST");
}
// Prints GET, though this is also visible in the url ( url?var&var&var)
function print_GET() {
print_obj($_GET,"\$_GET");
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Request initialisation stuff *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
/**
* Turn ^^ into ^ and ^s into /
*
* Necessary because various servers and various clients
* think that / is special...
*
* @ignore
*/
function _decaret($str) {
$out = "";
@ -424,6 +628,9 @@ function _decaret($str) {
return $out;
}
/**
* @ignore
*/
function _get_query_parts() {
if(isset($_GET["q"])) {
$path = $_GET["q"];
@ -453,6 +660,9 @@ function _get_query_parts() {
}
}
/**
* @ignore
*/
function _get_page_request() {
global $config;
$args = _get_query_parts();
@ -464,6 +674,9 @@ function _get_page_request() {
return new PageRequestEvent($args);
}
/**
* @ignore
*/
function _get_user() {
global $config, $database;
$user = null;