Initial commit

This commit is contained in:
Nathan Adams
2013-07-20 17:41:56 -05:00
commit 3b1e713fc4
606 changed files with 136001 additions and 0 deletions

1
pluf/src/Pluf/.htaccess Normal file
View File

@@ -0,0 +1 @@
Deny from all

556
pluf/src/Pluf/AB.php Normal file
View File

@@ -0,0 +1,556 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Core A/B testing component.
*
* The two importants methods are `test` and `convert`.
*
* For performance reasons, the A/B testing component requires you to
* setup a cache (APC or Memcached) and use the MongoDB database. The
* amount of data in the MongoDB should not be that big for most of
* the websites and as such it is fine if you are using the 32bit
* version of MongoDB.
*
* For the moment the storage is not abstracted to use another database.
*
* All the configuration variables for the component start with
* `pluf_ab_`. You need to add 'Pluf_AB' to your list of middleware.
*
*/
class Pluf_AB
{
/**
* MongoDB database handler.
*/
public static $db = null;
/**
* Returns an alternative for a given test.
*
* The middleware is already storing the uid of the user and makes
* it available as $request->pabuid.
*
* @param $test string Unique name of the test
* @param $request Pluf_HTTP_Request
* @param $alts array Alternatives to pick from (array(true,false))
* @param $weights array Weights for the alternatives (null)
* @param $desc string Optional description of the test ('')
* @return mixed One value from $alts
*/
public static function test($test, &$request, $alts=array(true,false),
$weights=null, $desc='')
{
if (Pluf::f('pluf_ab_allow_force', false) and
isset($request->GET[$test])) {
return $alts[$request->GET[$test]];
}
$db = self::getDb();
// Get or set test
$dtest = $db->tests->findOne(array('_id' => $test),
array('_id', 'active', 'winner'));
if ($dtest == null) {
$dtest = array('_id' => $test,
'creation_dtime' => gmdate('Y-m-d H:i:s',
$request->time),
'desc' => $desc,
'alts' => $alts,
'exp' => 0,
'conv' => 0,
'active' => true);
for ($i=0;$i<count($alts);$i++) {
$dtest['expalt_'.$i] = 0;
$dtest['convalt_'.$i] = 0;
}
$db->tests->update(array('_id'=>$test), $dtest,
array('upsert' => true));
} elseif (!$dtest['active']) {
// If test closed with given alternative, returns alternative
return (isset($dtest['winner'])) ? $alts[$dtest['winner']] : $alts[0];
}
if (!isset($request->pabuid)) {
$request->pabuid = self::getUid($request);
}
if ($request->pabuid == 'bot') {
return $alts[0];
}
// If $request->pabuid in test, returns corresponding alternative
$intest = $db->intest->findOne(array('_id' => $test.'##'.$request->pabuid),
array('_id', 'alt'));
if ($intest) {
return $alts[$intest['alt']];
}
// Else find alternative, store and return it
if ($weights == null) {
$weights = array_fill(0, count($alts), 1.0/count($alts));
}
$alt = self::weightedRand($weights);
$intest = array('_id' => $test.'##'.$request->pabuid,
'test' => $test,
'pabuid' => $request->pabuid,
'first_dtime' => gmdate('Y-m-d H:i:s',
$request->time),
'alt' => $alt);
$db->intest->update(array('_id' => $test.'##'.$request->pabuid),
$intest, array('upsert' => true));
// Update the counts of the test
$db->tests->update(array('_id' => $test),
array('$inc' => array('exp' => 1,
'expalt_'.$alt => 1)));
return $alts[$alt];
}
/**
* Mark a test as converted.
*
* A user which was not exposed to the test or a bot is not marked
* as converted as it is not significant.
*
* @param $test string Test
* @param $request Pluf_HTTP_Request
*/
public static function convert($test, $request)
{
if (!isset($request->pabuid) or $request->pabuid == 'bot') {
return;
}
$db = self::getDb();
$id = $test.'##'.$request->pabuid;
$intest = $db->intest->findOne(array('_id' => $id),
array('_id', 'alt'));
if (!$intest) {
// Not tested
return;
}
$conv = $db->convert->findOne(array('_id' => $id));
if ($conv) {
// Already converted
return;
}
$dtest = $db->tests->findOne(array('_id' => $test));
if (!$dtest or !$dtest['active']) {
return;
}
$conv = array(
'_id' => $id,
'test' => $test,
);
$db->convert->update(array('_id' => $id), $conv,
array('upsert' => true));
// increment the test counters
$db->tests->update(array('_id' => $test),
array('$inc' => array('conv' => 1,
'convalt_'.$intest['alt'] => 1)));
}
/**
* Register a property set for the user.
*
* This allows you to segment your users with these properties.
*
* @param $request Pluf_HTTP_Request
* @param $props array Properties
*/
public static function register(&$request, $props)
{
$pabuid = (isset($request->pabuid)) ?
$request->pabuid :
self::getUid($request);
if ($pabuid == 'bot') {
return;
}
$request->pabuid = $pabuid;
$request->pabprops = array_merge($request->pabprops, $props);
}
/**
* Track a funnel.
*
* The array of properties can be used to track different A/B
* testing cases.
*
* The list of properties must be the same at all the steps of the
* funnel, you cannot pass array('gender' => 'M') at step 1 and
* array('age' => 32) at step 2. You need to pass both of them at
* all steps.
*
* @param $funnel string Name of the funnel
* @param $step int Step in the funnel, from 1 to n
* @param $stepname string Readable name for the step
* @param $request Pluf_HTTP_Request Request object
* @param $props array Array of properties associated with the funnel (array())
*/
public static function trackFunnel($funnel, $step, $stepname, $request, $props=array())
{
$pabuid = (isset($request->pabuid)) ?
$request->pabuid :
self::getUid($request);
if ($pabuid == 'bot') {
return;
}
$request->pabuid = $pabuid;
$cache = Pluf_Cache::factory();
$key = 'pluf_ab_funnel_'.crc32($funnel.'#'.$step.'#'.$pabuid);
if ($cache->get($key, false)) {
return; // The key is valid 60s not to track 2 steps within 60s
}
$cache->set($key, '1', 60);
$what = array(
'f' => $funnel,
's' => $step,
'sn' => $stepname,
't' => (int) gmdate('Ymd', $request->time),
'u' => $pabuid,
'p' => array_merge($request->pabprops, $props),
);
$db = self::getDb();
$db->funnellogs->insert($what);
}
/**
* Process the response of a view.
*
* If the request has no cookie and the request has a pabuid, set
* the cookie in the response.
*
* @param Pluf_HTTP_Request The request
* @param Pluf_HTTP_Response The response
* @return Pluf_HTTP_Response The response
*/
function process_response($request, $response)
{
if (!isset($request->COOKIE['pabuid']) and isset($request->pabuid)
and $request->pabuid != 'bot') {
$response->cookies['pabuid'] = $request->pabuid;
}
if (isset($request->pabprops) and count($request->pabprops)
and $request->pabuid != 'bot') {
$response->cookies['pabprops'] = Pluf_Sign::dumps($request->pabprops, null, true);
}
return $response;
}
/**
* Process the request.
*
* If the request has the A/B test cookie, set $request->pabuid.
*
* @param Pluf_HTTP_Request The request
* @return bool False
*/
function process_request($request)
{
if (isset($request->COOKIE['pabuid']) and
self::check_uid($request->COOKIE['pabuid'])) {
$request->pabuid = $request->COOKIE['pabuid'];
}
$request->pabprops = array();
if (isset($request->COOKIE['pabprops'])) {
try {
$request->pabprops = Pluf_Sign::loads($request->COOKIE['pabprops']);
} catch (Exception $e) {
}
}
return false;
}
/**
* Get a MongoDB database handle.
*
* It opens only one connection per request and tries to keep a
* persistent connection between the requests.
*
* The configuration keys used are:
*
* `pluf_ab_mongo_server`: 'mongodb://localhost:27017'
* `pluf_ab_mongo_options`: array('connect' => true,
* 'persist' => 'pluf_ab_mongo')
* `pluf_ab_mongo_db`: 'pluf_ab'
*
* If you have a default installation of MongoDB, it should work
* out of the box.
*
*/
public static function getDb()
{
if (self::$db !== null) {
return self::$db;
}
$server = Pluf::f('pluf_ab_mongo_server', 'mongodb://localhost:27017');
$options = Pluf::f('pluf_ab_mongo_options',
array('connect' => true, 'persist' => 'pluf_ab_mongo'));
$conn = new Mongo($server, $options);
self::$db = $conn->selectDB(Pluf::f('pluf_ab_mongo_db', 'pluf_ab'));
return self::$db;
}
/**
* Get the uid of a given request.
*
* @param $request Pluf_HTTP_Request
*/
public static function getUid($request)
{
if (isset($request->COOKIE['pabuid']) and
self::check_uid($request->COOKIE['pabuid'])) {
return $request->COOKIE['pabuid'];
}
if (!isset($request->SERVER['HTTP_USER_AGENT']) or
self::isBot($request->SERVER['HTTP_USER_AGENT'])) {
return 'bot';
}
// Here we need to make an uid, first check if a user with
// same ip/agent exists and was last seen within the last 1h.
// We get that from MemcacheDB
$cache = Pluf_Cache::factory();
$key = 'pluf_ab_'.crc32($request->remote_addr.'#'.$request->SERVER['HTTP_USER_AGENT']);
if ($uid=$cache->get($key, null)) {
$cache->set($key, $uid, 3600);
return $uid;
}
$uid = self::make_uid($request);
$cache->set($key, $uid, 3600);
return $uid;
}
/**
* Check if a given user agent is a bot.
*
* @param $user_agent string User agent string
* @return bool True if the user agent is a bot
*/
public static function isBot($user_agent)
{
static $bots = array('robot', 'checker', 'crawl', 'discovery',
'hunter', 'scanner', 'spider', 'sucker', 'larbin',
'slurp', 'libwww', 'lwp', 'yandex', 'netcraft',
'wget', 'twiceler');
static $pbots = array('/bot[\s_+:,\.\;\/\\\-]/i',
'/[\s_+:,\.\;\/\\\-]bot/i');
foreach ($bots as $r) {
if (false !== stristr($user_agent, $r)) {
return true;
}
}
foreach ($pbots as $p) {
if (preg_match($p, $user_agent)) {
return true;
}
}
if (false === strpos($user_agent, '(')) {
return true;
}
return false;
}
/**
* Returns a random weighted alternative.
*
* Given a series of weighted alternative in the format:
*
* <pre>
* array('alt1' => 0.2,
* 'alt2' => 0.3,
* 'alt3' => 0.5);
* </pre>
*
* Returns the key of the selected alternative. In the following
* example, the alternative 3 (alt3) has a 50% chance to be
* selected, if the selected the results would be 'alt3'.
* @link: http://20bits.com/downloads/w_rand.phps
*
* @param $weights array Weighted alternatives
* @return mixed Key of the selected $weights array
*/
public static function weightedRand($weights)
{
$r = mt_rand(1,10000);
$offset = 0;
foreach ($weights as $k => $w) {
$offset += $w*10000;
if ($r <= $offset) {
return $k;
}
}
}
/**
* Given a request, make a corresponding A/B test UID.
*
* The UID is based on the time, the remote address, a random
* component and is hashed to ensure the integrity and avoid the
* need of a database hit when controlled.
*
* @param $request Pluf_HTTP_Request
* @return string UID
*/
public static function make_uid($request)
{
$base = sprintf('%08X%08X%08X', $request->time,
sprintf('%u', crc32($request->remote_addr)),
rand());
return sprintf('%s%08X', $base, sprintf('%u', crc32($base.md5(Pluf::f('secret_key')))));
}
/**
* Validate the uid in the cookie.
*
* @see self::make_uid
*
* @param $uid string The UID
* @return bool True if the UID is valid
*/
public static function check_uid($uid)
{
if (strlen($uid) != 32) {
return false;
}
$check = sprintf('%08X', sprintf('%u', crc32(substr($uid, 0, 24).md5(Pluf::f('secret_key')))));
return ($check == substr($uid, -8));
}
/* ------------------------------------------------------------
*
* Statistics Functions
*
* Note: I am not a statistician, use at your own risk!
*
* ------------------------------------------------------------ */
/**
* Given a conversion rate calculate the recommended sample sizes.
*
* The sample sizes is calculated to be significant at 95% in the
* case of a variation of conversion with respect to the other
* alternative of 25%, 15% and 5%.
*
* @param $conv Conversion rate ]0.0;1.0]
* @return array The 3 sample sizes for 25%, 15% and 5%
*/
public static function ssize($conv)
{
$a = 3.84145882689; // $a = pow(inverse_ncdf(1-(1-0.95)/2),2)
$res = array();
$bs = array(0.0625, 0.0225, 0.0025);
foreach ($bs as $b) {
$res[] = (int) ((1-$conv)*$a/($b*$conv));
}
return $res;
}
/**
* Given a test, returns the corresponding stats.
*
* @param $test array Test definition and results
* @return array Statistics for the test
*/
public static function getTestStats($test)
{
$stats = array(); // Will store the stats
$n = count($test['alts']);
$aconvr = array(); // All the conversion rates to sort the alternatives
for ($i=0;$i<$n;$i++) {
$conv = (isset($test['convalt_'.$i])) ? $test['convalt_'.$i] : 0;
$exp = (isset($test['expalt_'.$i])) ? $test['expalt_'.$i] : 0;
$convr = self::cr(array($exp, $conv));
$nconvr = ($convr !== null) ?
sprintf('%01.2f%%', $convr*100.0) : 'N/A';
$ssize = ($convr !== null and $convr > 0) ?
self::ssize($convr) : array();
$stats[] = array('alt' => $i,
'convr' => $convr,
'conv' => $conv,
'exp' => $exp,
'nconvr' => $nconvr,
'ssize' => $ssize);
$aconvr[] = ($convr === null) ? 0 : $convr;
}
array_multisort($aconvr, SORT_DESC, $stats);
// We want the best to be significantly better than the second best.
for ($i=0;$i<$n;$i++) {
$convr = $stats[$i]['convr'];
$exp = $stats[$i]['exp'];
$conv = $stats[$i]['conv'];
$comp = false;
$zscore = false;
$conf = false;
$better = false;
if ($i != 1 and $stats[1]['convr'] > 0) {
// Compare with base case and get confidence/Z-score
$comp = 100.0 * (float) ($convr - $stats[1]['convr'])/ (float) ($stats[1]['convr']);
if ($comp > 0) $better = true;
$comp = sprintf('%01.2f%%', $comp);
$zscore = self::zscore(array($stats[1]['exp'], $stats[1]['conv']),
array($exp, $conv));
$conf = sprintf('%01.2f%%', self::cumnormdist($zscore)*100.0);
$zscore = sprintf('%01.2f', $zscore);
}
$stats[$i]['comp'] = $comp;
$stats[$i]['zscore'] = $zscore;
$stats[$i]['conf'] = $conf;
$stats[$i]['better'] = $better;
}
return $stats;
}
public static function cr($t)
{
if ($t[1] < 0) return null;
if ($t[0] <= 0) return null;
return $t[1]/$t[0];
}
public static function zscore($c, $t)
{
$z = self::cr($t)-self::cr($c);
$s = (self::cr($t)*(1-self::cr($t)))/$t[0]
+ (self::cr($c)*(1-self::cr($c)))/$c[0];
return $z/sqrt($s);
}
/**
* Approximation of the cumulative normal distribution.
*/
public static function cumnormdist($x)
{
$b1 = 0.319381530;
$b2 = -0.356563782;
$b3 = 1.781477937;
$b4 = -1.821255978;
$b5 = 1.330274429;
$p = 0.2316419;
$c = 0.39894228;
if($x >= 0.0) {
$t = 1.0 / ( 1.0 + $p * $x );
return (1.0 - $c * exp( -$x * $x / 2.0 ) * $t *
( $t *( $t * ( $t * ( $t * $b5 + $b4 ) + $b3 ) + $b2 ) + $b1 ));
} else {
$t = 1.0 / ( 1.0 - $p * $x );
return ( $c * exp( -$x * $x / 2.0 ) * $t *
( $t *( $t * ( $t * ( $t * $b5 + $b4 ) + $b3 ) + $b2 ) + $b1 ));
}
}
}

View File

@@ -0,0 +1,86 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Mark the winner of a test.
*
* This form is not used to display the form, only to validate and
* process it.
*
*/
class Pluf_AB_Form_MarkWinner extends Pluf_Form
{
protected $test = null; /**< Store the test retrieved during validation. */
public function initFields($extra=array())
{
$this->fields['test'] = new Pluf_Form_Field_Varchar(
array('required' => true)
);
$this->fields['alt'] = new Pluf_Form_Field_Integer(
array('required' => true,
'min' => 0,
));
}
/**
* Validate that the test exists, is active and the corresponding
* alternative exists too.
*
* The validation is at the global level to prevent the need of a
* form per test and simplify the dashboard design.
*/
public function clean()
{
$db = Pluf_AB::getDb();
$test = $db->tests->findOne(array('_id' => $this->cleaned_data['test']));
if ($test == null) {
throw new Pluf_Form_Invalid(__('The test has not been found.'));
}
if (!$test['active']) {
throw new Pluf_Form_Invalid(__('The test is already inactive.'));
}
if (!isset($test['alts'][$this->cleaned_data['alt']])) {
throw new Pluf_Form_Invalid(__('This alternative is not available.'));
}
// Good we have the test and the right alternative
$this->test = $test;
return $this->cleaned_data;
}
/**
* Save the test.
*
* @return array Test.
*/
function save($commit=true)
{
$this->test['winner'] = $this->cleaned_data['alt'];
$this->test['active'] = false;
$this->test['stop_dtime'] = gmdate('Y-m-d H:i:s');
$db = Pluf_AB::getDb();
$db->tests->update(array('_id'=> $this->cleaned_data['test']),
$this->test);
return $this->test;
}
}

219
pluf/src/Pluf/AB/Funnel.php Normal file
View File

@@ -0,0 +1,219 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Funnel statistics.
*
* Funnels are easy to track but not that easy to generate statistics
* out of them.
*
* Stats are compiled "by GMT day", so you can track your funnel per
* day, week or more. Stats are put in cache in the "funnels" collection.
*
*/
class Pluf_AB_Funnel
{
/**
* Returns the list of funnels.
*
* @return array Funnels
*/
public static function getFunnels()
{
$db = Pluf_AB::getDb();
foreach (array('f', 't') as $k) {
// Once created, it will return immediately in the future
// calls so the overhead is negligeable.
$db->funnellogs->ensureIndex(array($k => 1),
array('background' => true));
}
$nf = $db->command(array('distinct' => 'funnellogs', 'key' => 'f'));
if ((int) $nf['ok'] == 1) {
sort($nf['values']);
return $nf['values'];
}
return array();
}
/**
* Get all the properties for a given period.
*/
public static function getFunnelProps($funnel, $period='today')
{
$db = Pluf_AB::getDb();
switch ($period) {
case 'yesterday':
$q = array('t' => (int) gmdate('Ymd', time()-86400));
break;
case 'today':
$q = array('t' => (int) gmdate('Ymd'));
break;
case '7days':
$q = array('t' => array('$gte' => (int) gmdate('Ymd', time()-604800)));
break;
case 'all':
default:
$q = array();
break;
}
$q['f'] = $funnel;
$props = array();
foreach ($db->funnellogs->find($q) as $log) {
foreach ($log['p'] as $prop => $v) {
if (isset($props[$prop]) and !in_array($v, $props[$prop])) {
$props[$prop][] = $v;
} else {
$props[$prop] = array($v);
}
}
}
return $props;
}
/**
* Get stats for a given funnel.
*
* @param $funnel string Funnel
* @param $period string Time period 'yesterday', ('today'), '7days', 'all'
* @param $prop string Property to filter (null)
*/
public static function getStats($funnel, $period='today', $prop=null)
{
$db = Pluf_AB::getDb();
$steps = array();
for ($i=1;$i<=20;$i++) {
$steps[$i] = array();
}
switch ($period) {
case 'yesterday':
$q = array('t' => (int) gmdate('Ymd', time()-86400));
break;
case 'today':
$q = array('t' => (int) gmdate('Ymd'));
break;
case '7days':
$q = array('t' => array('$gte' => (int) gmdate('Ymd', time()-604800)));
break;
case 'all':
default:
$q = array();
break;
}
$q['f'] = $funnel;
if ($prop) {
$q['p.'.$prop] = array('$exists' => true);
}
$uids = array();
// With very big logs, we will need to find by schunks, this
// will be very easy to adapt.
foreach ($db->funnellogs->find($q) as $log) {
if (!isset($uids[$log['u'].'##'.$log['s']])) {
if ($prop and !isset($log['p'][$prop])) {
continue;
}
$uids[$log['u'].'##'.$log['s']] = true;
$step = $log['s'];
$steps[$step]['name'] = $log['sn'];
$steps[$step]['id'] = $log['s'];
if ($prop and !isset($steps[$step]['props'])) {
$steps[$step]['props'] = array();
}
$steps[$step]['total'] = (isset($steps[$step]['total'])) ?
$steps[$step]['total'] + 1 : 1;
if ($prop) {
$steps[$step]['props'][$log['p'][$prop]] = (isset($steps[$step]['props'][$log['p'][$prop]])) ?
$steps[$step]['props'][$log['p'][$prop]] + 1 : 1;
}
}
}
// Now, compile the stats for steps 2 to n
// First, we find the "max" for the reference number of
// visitors along this funnel. This is $t1 and $tprops[prop]
$t1 = 0;
foreach ($steps as $step) {
if (isset($step['total']) and $step['total'] > $t1) {
$t1 = $step['total'];
}
if ($prop and isset($step['props'])) {
foreach ($step['props'] as $v => $t) {
if (!isset($tprops[$v])) {
$tprops[$v] = $t;
continue;
}
if ($tprops[$v] < $t) {
$tprops[$v] = $t;
}
}
}
}
if ($t1 == 0) {
return array();
}
$prev_step = null;
for ($i=1;$i<=20;$i++) {
if ($prev_step == null) {
}
if ($steps[$i]) {
$tp = $prev_step['total'];
$tn = $steps[$i]['total'];
if ($tp) {
$steps[$i]['conv'] = sprintf('%01.2f%%', 100.0 - (float)($tp-$tn)/$tp*100.0);
} else {
$steps[$i]['conv'] = 'N/A';
}
if ($t1) {
$steps[$i]['conv1'] = sprintf('%01.2f%%', 100.0 - (float)($t1-$tn)/$t1*100.0);
} else {
$steps[$i]['conv1'] = 'N/A';
}
if ($prop) {
$steps[$i]['sprops'] = array();
$steps[$i]['sprops1'] = array();
foreach ($steps[$i]['props'] as $v => $t) {
if (!isset($tprops[$v])) {
$tprops[$v] = $t;
}
$pv = isset($prev_step['props'][$v]) ? $prev_step['props'][$v] : 0;
$steps[$i]['sprops'][$v] = array($t, $pv);
$steps[$i]['sprops1'][$v] = array($t, $tprops[$v]);
if ($pv) {
$steps[$i]['sprops'][$v][] = round(100*(float)$t/(float)$pv,2).'%';
} else {
$steps[$i]['sprops'][$v][] = 0;
}
$steps[$i]['sprops1'][$v][] = round(100*(float)$t/(float)$tprops[$v],2).'%';
}
}
$steps[$i]['bigtotal'] = $t1;
$prev_step = $steps[$i];
}
}
for ($i=20;$i>=1;$i--) {
if (!$steps[$i]) {
unset($steps[$i]); // We remove the inexisting steps
}
}
return $steps;
}
}

176
pluf/src/Pluf/AB/Views.php Normal file
View File

@@ -0,0 +1,176 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
Pluf::loadFunction('Pluf_Shortcuts_RenderToResponse');
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
/**
* Manage and visualize the tests.
*
* It is possible to mark a test as inactive by picking a
* winner.
*
* Check the urls.php file for the URL definition to integrate the
* dashboard in your application/project.
*
* The permission used are:
*
* Pluf_AB.view-dashboard: The user can view the dasboard.
* Pluf_AB.edit-test: The user can edit a test.
*
*/
class Pluf_AB_Views
{
/**
* Display the currently running tests.
*
* The name of the view in the urls must be 'pluf_ab_dashboard'.
*/
public $dasboard_precond = array(array('Pluf_Precondition::hasPerm',
'Pluf_AB.view-dashboard'));
public function dashboard($request, $match)
{
$url = Pluf_HTTP_URL_urlForView('pluf_ab_dashboard');
$can_edit = $request->user->hasPerm('Pluf_AB.edit-test');
if ($can_edit && $request->method == 'POST') {
// We mark the winner.
$form = new Pluf_AB_Form_MarkWinner($request->POST);
if ($form->isValid()) {
$form->save();
$request->user->setMessage(__('The test has been updated.'));
return new Pluf_HTTP_Response_Redirect($url);
}
} else {
// To have it available for the control of the errors in
// the template.
$form = new Pluf_AB_Form_MarkWinner();
}
// Get the list of tests
$db = Pluf_AB::getDb();
$active = array();
$stopped = array();
foreach ($db->tests->find() as $test) {
$test['stats'] = Pluf_AB::getTestStats($test);
if ($test['active']) {
$active[] = $test;
} else {
$stopped[] = $test;
}
}
return Pluf_Shortcuts_RenderToResponse('pluf/ab/dashboard.html',
array('active' => $active,
'stopped' => $stopped,
'form' => $form,
'can_edit' => $can_edit,
),
$request);
}
/**
* Display the list of funnels.
*
*/
public $funnels_precond = array(array('Pluf_Precondition::hasPerm',
'Pluf_AB.view-funnels'));
public function funnels($request, $match)
{
$url = Pluf_HTTP_URL_urlForView('pluf_ab_funnels');
$funnels = Pluf_AB_Funnel::getFunnels();
return Pluf_Shortcuts_RenderToResponse('pluf/ab/funnels.html',
array('funnels' => $funnels,
),
$request);
}
/**
* Display a given funnel stats.
*
*/
public $funnel_precond = array(array('Pluf_Precondition::hasPerm',
'Pluf_AB.view-funnels'));
public function funnel($request, $match)
{
$periods = array('yesterday' => __('Yesterday'),
'today' => __('Today'),
'7days' => __('Last 7 days'),
'all' => __('All time'));
$period = 'today';
$nperiod = $periods[$period];
if (isset($request->REQUEST['p'])
and isset($periods[$request->REQUEST['p']])) {
$period = $request->REQUEST['p'];
$nperiod = $periods[$request->REQUEST['p']];
}
$props = Pluf_AB_Funnel::getFunnelProps($match[1], $period);
$prop = null;
if (isset($request->REQUEST['prop']) and
in_array($request->REQUEST['prop'], array_keys($props))) {
$prop = $request->REQUEST['prop'];
}
$stats = Pluf_AB_Funnel::getStats($match[1], $period, $prop);
return Pluf_Shortcuts_RenderToResponse('pluf/ab/funnel.html',
array('stats' => $stats,
'funnel' => $match[1],
'nperiod' => $nperiod,
'period' => $period,
'props' => $props,
'prop' => $prop,
),
$request);
}
/**
* A simple view to redirect a user and convert it.
*
* To convert the user for the test 'my_test' and redirect it to
* the URL 'http://www.example.com' add the following view in your
* urls.php:
*
* <pre>
* array('regex' => '#^/goto/example/$#',
* 'base' => $base,
* 'model' => 'Pluf_AB_Views',
* 'method' => 'convRedirect',
* 'name' => 'go_to_example',
* 'params' => array('url' => 'http://www.example.com',
* 'test' => 'my_test')
* );
* </pre>
*
* Try to put a url which reflects the final url after redirection
* to minimize the confusion for the user. In this example, in
* your code or template you use the named url 'go_to_example'.
*
*/
public function convRedirect($request, $match, $p)
{
Pluf_AB::convert($p['test'], $request);
return new Pluf_HTTP_Response_Redirect($p['url']);
}
}

View File

@@ -0,0 +1,139 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Backend to authenticate against a LDAP server.
*
* Configuration is done with the 'auth_ldap_*' keys.
*/
class Pluf_Auth_LdapBackend
{
/**
* Given a user id, retrieve it.
*
* Here we get the against the model database.
*/
public static function getUser($user_id)
{
$user_model = Pluf::f('pluf_custom_user','Pluf_User');
$sql = new Pluf_SQL('login=%s', array($user_id));
return Pluf::factory($user_model)->getOne($sql->gen());
}
/**
* Given an array with the authentication data, auth the user and return it.
*/
public static function authenticate($auth_data)
{
$password = $auth_data['password'];
$login = $auth_data['login'];
// Small security check against the login
if (preg_match('/[^A-Za-z0-9\-\_]/', $login)) {
return false;
}
// We check the user against the LDAP server, if it works we
// are happy, if not return false.
$ldap_dn = Pluf::f('auth_ldap_dn', 'ou=users,dc=example,dc=com');
$ldap_user = Pluf::f('auth_ldap_user', null);
$ldap_password = Pluf::f('auth_ldap_password', null);
$ldap_version = Pluf::f('auth_ldap_version', 3);
$ldap_user_key = Pluf::f('auth_ldap_user_key', 'uid');
// If auth_ldap_password_key, it will use crypt hash control
// to test the login password, else it will bind.
$ldap_password_key = Pluf::f('auth_ldap_password_key', null);
$ldap_surname_key = Pluf::f('auth_ldap_surname_key', 'sn');
$ldap_givenname_key = Pluf::f('auth_ldap_givenname_key', 'cn');
$ldap_email_key = Pluf::f('auth_ldap_email_key', 'mail');
$ldap = ldap_connect(Pluf::f('auth_ldap_host', 'localhost'));
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION,
Pluf::f('auth_ldap_version', 3));
if (!ldap_bind($ldap, $ldap_user, $ldap_password)) {
Pluf_Log::warn(sprintf('Cannot bind to the ldap server, user:%s, password:***', $ldap_user));
ldap_close($ldap);
return false;
}
// Go for a search
$search = ldap_search($ldap, $ldap_dn,
'('.$ldap_user_key.'='.$login.')',
array($ldap_user_key, $ldap_surname_key,
$ldap_givenname_key, $ldap_email_key));
$n = ldap_get_entries($ldap, $search);
if ($n['count'] != 1) {
ldap_close($ldap);
return false;
}
$entry = ldap_first_entry($ldap, $search);
// We get all the data first, the bind or hash control is done
// later. If we control with bind now, we need to search again
// to have an $entry resource to get the values.
list($family_name,) = @ldap_get_values($ldap, $entry, $ldap_surname_key);
list($first_name,) = @ldap_get_values($ldap, $entry, $ldap_givenname_key);
list($email,) = @ldap_get_values($ldap, $entry, $ldap_email_key);
$user_dn = ldap_get_dn($ldap, $entry);
if ($ldap_password_key) {
// Password authentication.
list($ldap_hash,) = ldap_get_values($ldap, $entry, $ldap_password_key);
$ldap_hash = substr($ldap_hash, 7);
$salt = substr($ldap_hash, 0, 12);
$hash = crypt($password, $salt);
if ($ldap_hash != $hash) {
ldap_close($ldap);
return false;
}
} else {
// Bind authentication
if (!@ldap_bind($ldap, $user_dn, $password)) {
ldap_close($ldap);
return false;
}
}
// We get the user values as the
// Now we get the user and we create it if not available
$user = self::getUser($login);
if ($user) {
ldap_close($ldap);
return $user;
}
// Need to create it
ldap_close($ldap);
$user_model = Pluf::f('pluf_custom_user','Pluf_User');
$user = new $user_model();
$user->active = true;
$user->login = $login;
$user->password = $password;
$user->last_name = $family_name;
$user->first_name = $first_name;
$user->email = $email;
$user->create();
return $user;
}
}

View File

@@ -0,0 +1,58 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Backend to authenticate against the Pluf_User model.
*/
class Pluf_Auth_ModelBackend
{
/**
* Given a user id, retrieve it.
*
* In the case of the Pluf_User backend, the $user_id is the login.
*/
public static function getUser($user_id)
{
$user_model = Pluf::f('pluf_custom_user','Pluf_User');
$sql = new Pluf_SQL('login=%s', array($user_id));
return Pluf::factory($user_model)->getOne($sql->gen());
}
/**
* Given an array with the authentication data, auth the user and return it.
*/
public static function authenticate($auth_data)
{
$password = $auth_data['password'];
$login = $auth_data['login'];
$user = self::getUser($login);
if (!$user) {
return false;
}
if (!$user->active) {
return false;
}
return ($user->checkPassword($password)) ? $user : false;
}
}

90
pluf/src/Pluf/Cache.php Normal file
View File

@@ -0,0 +1,90 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Cache class.
*
* You should not use this class directly, but one of the subclasses
* implementing a given engine. This is done automatically when using
* the factory. It will use the engine defined by the 'cache_engine'
* configuration variable.
*
* Default timeout in seconds is defined by the 'cache_timeout'
* configuration variable.
*
* <pre>
* $cache = new Pluf_Cache::factory();
* if (null === ($foo=$cache->get('my-key'))) {
* $foo = run_complex_operation();
* $cache->set('my-key', $foo);
* }
* return $foo;
* </pre>
*
* The value to be stored in the cache must be serializable.
*
* @see http://www.php.net/serialize
*/
class Pluf_Cache
{
/**
* Factory.
*
* @return Pluf_Cache_* Cache object
*/
public static function factory()
{
if (false === ($engine=Pluf::f('cache_engine', false))) {
throw new Pluf_Exception_SettingError('"cache_engine" setting not defined.');
}
if (!isset($GLOBALS['_PX_Pluf_Cache-'.$engine])) {
$GLOBALS['_PX_Pluf_Cache-'.$engine] = new $engine();
}
return $GLOBALS['_PX_Pluf_Cache-'.$engine];
}
/**
* Set a value in the cache.
*
* @param string Key to store the information
* @param mixed Value to store
* @param int Timeout in seconds (null)
* @return bool Success
*/
public function set($key, $value, $timeout=null)
{
throw new Pluf_Exception_NotImplemented();
}
/**
* Get value from the cache.
*
* @param string Key to get the information
* @param mixed Default value to return if cache miss (null)
* @param mixed Stored value or default
*/
public function get($key, $default=null)
{
throw new Pluf_Exception_NotImplemented();
}
}

102
pluf/src/Pluf/Cache/Apc.php Normal file
View File

@@ -0,0 +1,102 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* APC based cache.
*
* You need APC installed on your server for this cache system to
* work. You can install APC with <code>$ sudo pecl install apc</code>
* on most systems.
*
* A special 'cache_apc_keyprefix' can be set to use APC for different
* applications and avoid conflict. Compression is performed at the
* PHP level using the gz(in|de)flate functions.
*
* Example of configuration:
*
* <pre>
* $cfg['cache_engine'] = 'Pluf_Cache_Apc';
* $cfg['cache_timeout'] = 300;
* $cfg['cache_apc_keyprefix'] = 'uniqueforapp';
* $cfg['cache_apc_compress'] = true;
* </pre>
*
* @see Pluf_Cache
* @see http://www.php.net/gzdeflate
* @see http://www.php.net/gzinflate
*/
class Pluf_Cache_Apc extends Pluf_Cache
{
/**
* Prefix added to all the keys.
*/
private $keyprefix = '';
/**
* Auto compress the data to save memory against a small
* performance loss.
*/
private $compress = false;
/**
* Create the cache object and initialize it from the
* configuration.
*/
public function __construct()
{
$this->keyprefix = Pluf::f('cache_apc_keyprefix', '');
$this->compress = Pluf::f('cache_apc_compress', false);
}
/**
* Set a value in the cache.
*
* @param string Key to store the information
* @param mixed Value to store
* @param int Timeout in seconds (null)
* @return bool Success
*/
public function set($key, $value, $timeout=null)
{
if ($timeout == null) $timeout = Pluf::f('cache_timeout', 300);
$value = serialize($value);
if ($this->compress) $value = gzdeflate($value, 9);
return apc_store($this->keyprefix.$key, $value, $timeout);
}
/**
* Get value from the cache.
*
* @param string Key to get the information
* @param mixed Default value to return if cache miss (null)
* @return mixed Stored value or default
*/
public function get($key, $default=null)
{
$success = false;
$value = apc_fetch($this->keyprefix.$key, &$success);
if (!$success) return $default;
if ($this->compress) $value = gzinflate($value);
return unserialize($value);
}
}

View File

@@ -0,0 +1,132 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* File based cache.
*
* Info are stored in the 'cache_file_folder' folder. In the folder, 2
* subdirectories are created based on the md5 of the key.
*/
class Pluf_Cache_File extends Pluf_Cache
{
/**
* Is debug mode?
*
* @var boolean
*/
private $_debug;
/**
* Mapping key => md5.
*
* @var array
*/
private $_keymap = array();
public function __construct()
{
if (!Pluf::f('cache_file_folder', false)) {
throw new Pluf_Exception_SettingError('"cache_file_folder" setting not defined.');
}
$this->_debug = Pluf::f('debug', false);
}
/**
* Set a value in the cache.
*
* @param string Key to store the information
* @param mixed Value to store
* @param int Timeout in seconds (null)
* @return bool Success
*/
public function set($key, $value, $timeout=null)
{
$fname = $this->_keyToFile($key);
$dir = dirname($fname);
if (null === $timeout) {
$timeout = Pluf::f('cache_timeout', 300);
}
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
$expire = $_SERVER['REQUEST_TIME'] + $timeout;
$success = file_put_contents($fname, $expire."\n".serialize($value), LOCK_EX);
chmod($fname, 0777);
return (false === $success) ? false : true;
}
/**
* Get value from the cache.
*
* @param string Key to get the information
* @param mixed Default value to return if cache miss (null)
* @param mixed Stored value or default
*/
public function get($key, $default=null)
{
$fname = $this->_keyToFile($key);
if (!file_exists($fname)) {
return $default;
}
if ($this->_debug) {
ob_start();
include $fname;
$data = ob_get_contents();
ob_end_clean();
} else {
$data = file_get_contents($fname);
}
list($timeout, $content) = explode("\n", $data, 2);
if ($timeout < $_SERVER['REQUEST_TIME']) {
@unlink($fname);
return $default;
}
return unserialize($content);
}
/**
* Convert a key into a path to a file.
*
* @param string Key
* @return string Path to file
*/
public function _keyToFile($key)
{
if (isset($this->_keymap[$key])) {
$md5 = $this->_keymap[$key];
} else {
$md5 = md5($key);
$this->_keymap[$key] = $md5;
}
return Pluf::f('cache_file_folder') . '/' .
substr($md5, 0, 2) . '/' .
substr($md5, 2, 2) . '/' .
substr($md5, 4);
}
}

View File

@@ -0,0 +1,94 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Memcached based cache.
*
* A special 'cache_memcached_keyprefix' can be set to use one
* memcached for different applications and avoid conflict.
*
* Example of configuration:
*
* <pre>
* $cfg['cache_engine'] = 'Pluf_Cache_Memcached';
* $cfg['cache_timeout'] = 300;
* $cfg['cache_memcached_keyprefix'] = 'uniqueforapp';
* $cfg['cache_memcached_server'] = 'localhost';
* $cfg['cache_memcached_port'] = 11211;
* $cfg['cache_memcached_compress'] = 0; (or MEMCACHE_COMPRESSED)
* </pre>
*/
class Pluf_Cache_Memcached extends Pluf_Cache
{
private $memcache = null;
private $keyprefix = '';
public function __construct()
{
$this->memcache = memcache_connect(Pluf::f('cache_memcached_server', 'localhost'),
Pluf::f('cache_memcached_port', 11211));
if (false === $this->memcache) {
$this->memcache = null;
}
$this->keyprefix = Pluf::f('cache_memcached_keyprefix', '');
}
/**
* Set a value in the cache.
*
* @param string Key to store the information
* @param mixed Value to store
* @param int Timeout in seconds (null)
* @return bool Success
*/
public function set($key, $value, $timeout=null)
{
if ($this->memcache) {
if ($timeout == null) $timeout = Pluf::f('cache_timeout', 300);
$this->memcache->set($this->keyprefix.$key, serialize($value),
Pluf::f('cache_memcached_compress', 0),
$timeout);
}
}
/**
* Get value from the cache.
*
* @param string Key to get the information
* @param mixed Default value to return if cache miss (null)
* @param mixed Stored value or default
*/
public function get($key, $default=null)
{
if ($this->memcache) {
$val = $this->memcache->get($this->keyprefix.$key);
if (false === $val) {
return $default;
} else {
return unserialize($val);
}
} else {
return $default;
}
}
}

485
pluf/src/Pluf/Calendar.php Normal file
View File

@@ -0,0 +1,485 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Calendar to display a list of events in a calendar table.
*
* The calendar is independent of other elements of Pluf, you can use
* it standalone if you want.
*
* The principle is that you set options and feed the calendar with a
* list of events. Based on the options, the render() method will
* produce different views of the calendar.
*/
class Pluf_Calendar
{
/**
* The list of events to display.
*/
var $events = array();
var $summary = '';
/**
* The display options of the calendar.
*/
var $opts = array();
// When updating an interval, if a col span more rows and columns,
// store the info for the next rows to compensate as needed.
var $bspans = array();
/**
* List of events without the events not between the start/end
* days.
*/
var $_events = array();
/**
* List of time intervals in the $_events list.
*/
var $_time_intervals = array();
/**
* Simultaneous events at a given time slot, for a given group.
*
* array('2007-03-25' =>
* array(array('time' => '10:15',
* 'start' => 4 ,
* 'continued' => 5),
* array('time' => '11:30',
* 'start' => 3 ,
* 'continued' => 0),
* )
* '2007-03-24' =>
* array(array('time' => '11:30',
* 'start' => 2 ,
* 'continued' => 3),
* )
* )
*
*/
var $_simultaneous = array();
var $_max_simultaneous = array();
var $_groups = array();
/**
* Render the calendar based on the options.
*/
public function render()
{
if (count($this->events) == 0) {
return '';
}
$this->cleanEventList();
$this->getTimeIntervals();
$this->getSimultaneous();
$this->getMaxSimultaneous();
$s = '';
if ($this->summary) {
$s = 'summary="'.htmlspecialchars($this->summary).'" ';
}
$out = '<table '.$s.'cellspacing="0" class="px-calendar">'."\n";
$out .= $this->getHead();
$out .= $this->getBody();
$out .= '</table>'."\n";
return Pluf_Template_SafeString::markSafe($out);
}
/**
* Event are grouped by day per default, you can group as you
* want, just subclass this method. Groups are used to make
* columns in the table with the headings.
*/
function getEventGroup($event)
{
return substr($event['start'], 0, 10);
}
/**
* Get all the available groups.
*/
function getGroups()
{
if (count($this->_groups)) {
return $this->_groups;
}
foreach ($this->_events as $event) {
$group = $this->getEventGroup($event);
if (!in_array($group, $this->_groups)) {
$this->_groups[] = $group;
}
}
return $this->_groups;
}
/**
* Get the name of a group to print in the headers.
*/
function getGroupName($group)
{
$dw = $this->daysOfWeek();
$days = date('w', strtotime($group));
return htmlspecialchars($dw[$days%7]);
}
/**
* Generate the body of the calendar.
*/
function getBody()
{
$out = '<tbody>'."\n";
$inters = $this->getTimeIntervals();
$groups = $this->getGroups();
for ($i=0;$i<(count($inters)-1);$i++) {
$out .= '<tr>'."\n";
$out .= ' <th scope="row">'.$inters[$i].' - '.$inters[$i+1].'</th>'."\n";
foreach ($groups as $group) {
$out .= $this->getEventCell($group, $inters[$i]);
}
$out .= '</tr>'."\n";
}
$out .= '</tbody>'."\n";
return $out;
}
/**
* Get the value to print for the given cell
*
* @param string Current group
* @param string Current interval
* @return string Table cells
*/
function getEventCell($group, $inter)
{
$out = '';
$max = $this->getMaxSimultaneous();
$fullspanevent = false;
foreach ($this->_events as $event) {
// Get the start time of the event
$e_start = substr($event['start'], 11, 5);
if ($e_start != $inter) {
// If the event does not start at the current time,
// skip it
continue;
}
if ($group != $this->getEventGroup($event)) {
// Check if full span even at this time interval
if (!empty($event['fullspan'])) {
$fullspanevent = true;
}
continue;
}
// Find how many rows the event will span
$extra = '';
$content = '';
if (!isset($event['content'])) $event['content'] = '';
$row_span = $this->getEventRowSpanning($event, $this->_time_intervals);
if ($row_span > 1) {
$extra .= ' rowspan="'.$row_span.'"';
}
if (!empty($event['fullspan'])) {
$colspan = 0;
foreach ($max as $_s) {
$colspan += $_s;
}
$extra .= ' colspan="'.$colspan.'"';
$fullspanevent = true;
}
if (strlen($event['color']) > 0) {
$extra .= ' style="background-color: '.$event['color'].';"';
}
if (strlen($event['content']) > 0) {
$content .= $event['content'];
}
if (strlen($event['url']) > 0) {
$content .= '<a href="'.$event['url'].'">'.htmlspecialchars($event['title']).'</a>';
}
if (strlen($event['content']) == 0 and strlen($event['url']) == 0) {
$content .= htmlspecialchars($event['title']);
}
$out .= ' <td'.$extra.'>'.$content.'</td>'."\n";
}
if (!$fullspanevent) {
$sim = null;
foreach ($this->_simultaneous[$group] as $_sim) {
if ($_sim['time'] == $inter) {
$sim = $_sim;
break;
}
}
$diff = $max[$group] - ($sim['start'] + $sim['continued']);
for ($k=0; $k<$diff; $k++) {
$out .= ' <td class="empty">&nbsp;</td>'."\n";
}
}
return $out;
}
/**
* Get event spanning over the rows.
*
* @param array Event
* @param array Intervals
* @return int Spanning
*/
function getEventRowSpanning($event, $inters)
{
$start = substr($event['start'], 11, 5);
$end = substr($event['end'], 11, 5);
$span = 1;
foreach ($inters as $inter) {
if ($inter < $end and $inter > $start) {
$span++;
}
}
return $span;
}
/**
* Generate the head of the calendar.
*/
function getHead()
{
$out = '<thead>'."\n".'<tr>'."\n".' <th>&nbsp;</th>'."\n";
// Print the groups.
$groups = $this->getGroups();
$max = $this->getMaxSimultaneous();
foreach ($groups as $group) {
if ($max[$group] > 1) {
$span = ' colspan="'.$max[$group].'"';
} else {
$span = '';
}
$out .= ' <th scope="col"'.$span.'>'.$this->getGroupName($group).'</th>'."\n";
}
$out .= '</tr>'."\n".'</thead>'."\n";
return $out;
}
/**
* Get the rowspan for each day.
*/
function getDaySpanning()
{
list($start, $end) = $this->getStartEndDays();
$inters = $this->getTimeIntervals($start, $end);
$n = $this->getDayNumber($start, $end);
$inter_n = array_fill(0, count($inters), 0);
$day_span = array_fill(0, $n+1, $inter_n);
foreach ($this->events as $event) {
// The event must be between $start and $end
$e_dstart = substr($event['start'], 0, 10);
$e_dend = substr($event['end'], 0, 10);
if ($e_dend < $start or $e_dstart > $end) {
continue;
}
$day = $this->getDayNumber($start, substr($event['end'], 0, 10));
$e_start = substr($event['start'], 11, 5);
$e_end = substr($event['end'], 11, 5);
$i = 0;
foreach ($inters as $inter) {
if ($inter < $e_end and $inter >= $e_start) {
$day_span[$day][$i]++;
}
$i++;
}
}
return $day_span;
}
/**
* Get an array with the days of the week.
*/
function daysOfWeek()
{
return array(
__('Sunday'),
__('Monday'),
__('Tuesday'),
__('Wednesday'),
__('Thursday'),
__('Friday'),
__('Saturday'),
);
}
/**
* Get the number of days to list.
*
* @param string Start date
* @param string End date
* @return int Number of days
*/
function getDayNumber($start, $end)
{
Pluf::loadFunction('Pluf_Date_Compare');
$diff = Pluf_Date_Compare($start.' 00:00:00', $end.' 00:00:00');
return (int) $diff/86400;
}
/**
* Get the start and end dates based on the event list.
*
* @return array (start day, end day)
*/
function getStartEndDays()
{
$start = '9999-12-31';
$end = '0000-01-01';
if (!isset($this->opts['start-day'])
or !isset($this->opts['end-day'])) {
foreach ($this->events as $event) {
$t_start = substr($event['start'], 0, 10);
$t_end = substr($event['end'], 0, 10);
if ($t_start < $start) {
$start = $t_start;
}
if ($t_end > $end) {
$end = $t_end;
}
}
}
if (isset($this->opts['start-day'])) {
$start = $this->opts['start-day'];
} else {
$this->opts['start-day'] = $start;
}
if (isset($this->opts['end-day'])) {
$end = $this->opts['end-day'];
} else {
$this->opts['end-day'] = $end;
}
return array($start, $end);
}
/**
* Clean event list.
*/
function cleanEventList()
{
list($start, $end) = $this->getStartEndDays();
$this->_events = array();
foreach ($this->events as $event) {
$e_dstart = substr($event['start'], 0, 10);
$e_dend = substr($event['end'], 0, 10);
if ($e_dend < $start or $e_dstart > $end) {
continue;
}
$this->_events[] = $event;
}
return true;
}
/**
* Get the time intervals. They span all the groups.
*/
function getTimeIntervals($start='', $end='')
{
if (count($this->_time_intervals)) {
return $this->_time_intervals;
}
$intervals = array();
foreach ($this->_events as $event) {
$t = substr($event['start'], 11, 5);
if (!in_array($t, $intervals)) {
$intervals[] = $t;
}
$t = substr($event['end'], 11, 5);
if (!in_array($t, $intervals)) {
$intervals[] = $t;
}
}
sort($intervals);
$this->_time_intervals = $intervals;
return $intervals;
}
/**
* Get simultaneous events at the same time slot and same group.
*/
function getSimultaneous()
{
foreach ($this->getGroups() as $group) {
$this->_simultaneous[$group] = array();
foreach ($this->_time_intervals as $inter) {
$this->_simultaneous[$group][] = array('time' => $inter,
'start' => 0,
'continued' => 0);
}
}
foreach ($this->_events as $event) {
$group = $this->getEventGroup($event);
$e_tstart = substr($event['start'], 11, 5);
$e_tend = substr($event['end'], 11, 5);
foreach ($this->_simultaneous[$group] as $index=>$inter) {
if ($e_tstart == $inter['time']) {
$inter['start'] += 1;
$this->_simultaneous[$group][$index] = $inter;
continue;
}
if ($e_tstart < $inter['time'] and $e_tend > $inter['time']) {
$inter['continued'] += 1;
$this->_simultaneous[$group][$index] = $inter;
continue;
}
}
}
return $this->_simultaneous;
}
/**
* Get maximum simultaneous events
*/
function getMaxSimultaneous()
{
if (count($this->_max_simultaneous) > 0) {
return $this->_max_simultaneous;
}
foreach ($this->getGroups() as $group) {
$this->_max_simultaneous[$group] = 0;
}
foreach ($this->_simultaneous as $group=>$choices) {
foreach ($choices as $count) {
if ($this->_max_simultaneous[$group] < $count['start'] + $count['continued']) {
$this->_max_simultaneous[$group] = $count['start'] + $count['continued'];
}
}
}
return $this->_max_simultaneous;
}
/**
* Overloading of the get method.
*
* @param string Property to get
*/
function __get($prop)
{
if ($prop == 'render') return $this->render();
return $this->$prop;
}
}

111
pluf/src/Pluf/Crypt.php Normal file
View File

@@ -0,0 +1,111 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple encryption class.
*
* Very simple encryption class to perform simple encryption. It can
* be used for example when you request a valid email address to
* register. The validation link can contain the encrypted email.
*
* DO NOT EVER USE IT FOR REALLY IMPORTANT DATA!!!
*
* Credit Anonymous on http://www.php.net/mcrypt
*/
class Pluf_Crypt
{
public $key = '';
/**
* Construct the encryption object.
*
* @param string The encryption key ('')
*/
function __construct($key='')
{
$this->key = $key;
}
/**
* Encrypt a string with a key.
*
* If the key is not given, $this->key is used. If $this->key is
* empty an exception is raised.
*
* @param string String to encode
* @param string Encryption key ('')
* @return string Encoded string
*/
function encrypt($string, $key='')
{
if ($key == '') {
$key = $this->key;
}
if ($key == '') {
throw new Exception('No encryption key provided.');
}
$result = '';
$strlen = strlen($string);
$keylen = strlen($key);
for($i=0; $i<$strlen; $i++) {
$char = substr($string, $i, 1);
$keychar = substr($key, ($i % $keylen)-1, 1);
$char = chr(ord($char)+ord($keychar));
$result.=$char;
}
$result = base64_encode($result);
return str_replace(array('+','/','='), array('-','_','~'), $result);
}
/**
* Decrypt a string with a key.
*
* If the key is not given, $this->key is used. If $this->key is
* empty an exception is raised.
*
* @param string String to decode
* @param string Encryption key ('')
* @return string Decoded string
*/
function decrypt($string, $key='')
{
if ($key == '') {
$key = $this->key;
}
if ($key == '') {
throw new Exception('No encryption key provided.');
}
$result = '';
$string = str_replace(array('-','_','~'), array('+','/','='), $string);
$string = base64_decode($string);
$strlen = strlen($string);
$keylen = strlen($key);
for($i=0; $i<$strlen; $i++) {
$char = substr($string, $i, 1);
$keychar = substr($key, ($i % $keylen)-1, 1);
$char = chr(ord($char)-ord($keychar));
$result.=$char;
}
return $result;
}
}

225
pluf/src/Pluf/DB.php Normal file
View File

@@ -0,0 +1,225 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Database class.
*
* Depending of the parameters, the database object will connect to a MySQL
* or SQLite database.
*/
class Pluf_DB
{
/**
* Get a database connection.
*/
static function get($engine, $server, $database, $login, $password,
$prefix, $debug=false, $version='')
{
$engine = 'Pluf_DB_'.$engine;
$con = new $engine($login, $password, $server, $database,
$prefix, $debug, $version);
return $con;
}
}
/**
* Get the default DB connection.
*
* The default database connection is defined in the configuration file
* through the following configuration variables:
* - db_login : Login to connect to the database
* - db_password : Password to the database
* - db_server : Name of the server
* - db_database : Name of the database
* - db_table_prefix : Prefix for the table names
* - db_version : Version of the database engine
* - db_engine : Engine for exampe 'MySQL', 'SQLite'
*
* Once the first connection is created the following calls to Pluf::db()
* are getting the same connection.
*
*/
function Pluf_DB_getConnection($extra=null)
{
if (isset($GLOBALS['_PX_db']) &&
(is_resource($GLOBALS['_PX_db']->con_id) or is_object($GLOBALS['_PX_db']->con_id))) {
return $GLOBALS['_PX_db'];
}
$GLOBALS['_PX_db'] = Pluf_DB::get(Pluf::f('db_engine'),
Pluf::f('db_server'),
Pluf::f('db_database'),
Pluf::f('db_login'),
Pluf::f('db_password'),
Pluf::f('db_table_prefix'),
Pluf::f('db_debug'),
Pluf::f('db_version'));
return $GLOBALS['_PX_db'];
}
/**
* Returns an array of default typecast and quoting for the database ORM.
*
* Foreach field type you need to provide an array with 2 functions,
* the from_db, the to_db.
*
* $value = from_db($value);
* $escaped_value = to_db($value, $dbobject);
*
* $escaped_value is ready to be put in the SQL, that is if this is a
* string, the value is quoted and escaped for example with SQLite:
* 'my string'' is escaped' or with MySQL 'my string\' is escaped' the
* starting ' and ending ' are included!
*
* @return array Default typecast.
*/
function Pluf_DB_defaultTypecast()
{
return array(
'Pluf_DB_Field_Boolean' =>
array('Pluf_DB_BooleanFromDb', 'Pluf_DB_BooleanToDb'),
'Pluf_DB_Field_Date' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_Datetime' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_Email' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_File' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_Float' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_Foreignkey' =>
array('Pluf_DB_IntegerFromDb', 'Pluf_DB_IntegerToDb'),
'Pluf_DB_Field_Integer' =>
array('Pluf_DB_IntegerFromDb', 'Pluf_DB_IntegerToDb'),
'Pluf_DB_Field_Password' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_PasswordToDb'),
'Pluf_DB_Field_Sequence' =>
array('Pluf_DB_IntegerFromDb', 'Pluf_DB_IntegerToDb'),
'Pluf_DB_Field_Slug' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_SlugToDb'),
'Pluf_DB_Field_Text' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_Varchar' =>
array('Pluf_DB_IdentityFromDb', 'Pluf_DB_IdentityToDb'),
'Pluf_DB_Field_Serialized' =>
array('Pluf_DB_SerializedFromDb', 'Pluf_DB_SerializedToDb'),
'Pluf_DB_Field_Compressed' =>
array('Pluf_DB_CompressedFromDb', 'Pluf_DB_CompressedToDb'),
);
}
/**
* Identity function.
*
* @param mixed Value
* @return mixed Value
*/
function Pluf_DB_IdentityFromDb($val)
{
return $val;
}
/**
* Identity function.
*
* @param mixed Value.
* @param object Database handler.
* @return string Ready to use for SQL.
*/
function Pluf_DB_IdentityToDb($val, $db)
{
if (null === $val) {
return 'NULL';
}
return $db->esc($val);
}
function Pluf_DB_SerializedFromDb($val)
{
if ($val) {
return unserialize($val);
}
return $val;
}
function Pluf_DB_SerializedToDb($val, $db)
{
if (null === $val) {
return 'NULL';
}
return $db->esc(serialize($val));
}
function Pluf_DB_CompressedFromDb($val)
{
return ($val) ? gzinflate($val) : $val;
}
function Pluf_DB_CompressedToDb($val, $db)
{
return (null === $val) ? 'NULL' : $db->esc(gzdeflate($val, 9));
}
function Pluf_DB_BooleanFromDb($val) {
if ($val) {
return true;
}
return false;
}
function Pluf_DB_BooleanToDb($val, $db) {
if (null === $val) {
return 'NULL';
}
if ($val) {
return $db->esc('1');
}
return $db->esc('0');
}
function Pluf_DB_IntegerFromDb($val) {
return (null === $val) ? null : (int) $val;
}
function Pluf_DB_IntegerToDb($val, $db) {
return (null === $val) ? 'NULL' : (string)(int)$val;
}
function Pluf_DB_PasswordToDb($val, $db) {
//$exp = explode(':', $val);
//if (in_array($exp[0], array('sha1', 'md5', 'crc32'))) {
// return $db->esc($val);
//}
// We need to hash the value.
//$salt = Pluf_Utils::getRandomString(5);
//return $db->esc('sha1:'.$salt.':'.sha1($salt.$val));
if (base64_encode(base64_decode($val)) == $val)
return $db->esc($val);
else
return $db->esc(base64_encode(sha1($val, TRUE)));
}
function Pluf_DB_SlugToDB($val, $db) {
return $db->esc(Pluf_DB_Field_Slug::slugify($val));
}

112
pluf/src/Pluf/DB/Field.php Normal file
View File

@@ -0,0 +1,112 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Default database field.
*/
class Pluf_DB_Field
{
/**
* The types are defined in the $mappings member variable of the
* schema class of your database engine, for example
* Pluf_DB_Schema_MySQL.
*/
public $type = '';
/**
* The column name of the field.
*/
public $column = '';
/**
* Current value of the field.
*/
public $value;
/**
* All the extra parameters of the field.
*/
public $extra = array();
/**
* The extra methods added to the model by the field.
*/
public $methods = array();
/**
* Constructor.
*
* @param mixed Value ('')
* @param string Column name ('')
*/
function __construct($value='', $column='', $extra=array())
{
$this->value = $value;
$this->column = $column;
if ($extra) {
$this->extra = array_merge($this->extra, $extra);
}
}
/**
* Get the form field for this field.
*
* We put this method at the field level as it allows us to easily
* create a new DB field and a new Form field and use them without
* the need to modify another place where the mapping would be
* performed.
*
* @param array Definition of the field.
* @param string Form field class.
*/
function formField($def, $form_field='Pluf_Form_Field_Varchar')
{
Pluf::loadClass('Pluf_Form_BoundField'); // To get mb_ucfirst
$defaults = array('required' => !$def['blank'],
'label' => mb_ucfirst($def['verbose']),
'help_text' => $def['help_text']);
unset($def['blank'], $def['verbose'], $def['help_text']);
if (isset($def['default'])) {
$defaults['initial'] = $def['default'];
unset($def['default']);
}
if (isset($def['choices'])) {
$defaults['widget'] = 'Pluf_Form_Widget_SelectInput';
if (isset($def['widget_attrs'])) {
$def['widget_attrs']['choices'] = $def['choices'];
} else {
$def['widget_attrs'] = array('choices' => $def['choices']);
}
}
foreach (array_keys($def) as $key) {
if (!in_array($key, array('widget', 'label', 'required', 'multiple',
'initial', 'choices', 'widget_attrs'))) {
unset($def[$key]);
}
}
$params = array_merge($defaults, $def);
return new $form_field($params);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Boolean extends Pluf_DB_Field
{
public $type = 'boolean';
function formField($def, $form_field='Pluf_Form_Field_Boolean')
{
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* This field will automatically inflate/deflate its content.
*
* This can be used to store large text bodies where you do not need
* to directly search into the content using the standard SQL
* functions.
*/
class Pluf_DB_Field_Compressed extends Pluf_DB_Field
{
public $type = 'blob';
function formField($def, $form_field='Pluf_Form_Field_Varchar')
{
if (!isset($def['widget'])) {
$def['widget'] = 'Pluf_Form_Widget_TextareaInput';
}
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Date extends Pluf_DB_Field
{
public $type = 'date';
function formField($def, $form_field='Pluf_Form_Field_Date')
{
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Datetime extends Pluf_DB_Field
{
public $type = 'datetime';
function formField($def, $form_field='Pluf_Form_Field_Datetime')
{
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Email extends Pluf_DB_Field
{
public $type = 'varchar';
public $extra = array('size' => 200);
function formField($def, $form_field='Pluf_Form_Field_Email')
{
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,76 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_File extends Pluf_DB_Field
{
/**
* See definition in Pluf_DB_Field.
*/
public $type = 'file';
public $column = '';
public $value;
public $extra = array();
public $methods = array();
/**
* Constructor.
*
* @param mixed Value ('')
* @param string Column name ('')
*/
function __construct($value='', $column='', $extra=array())
{
parent::__construct($value, $column, $extra);
$this->methods = array(array(strtolower($column).'_url', 'Pluf_DB_Field_File_Url'),
array(strtolower($column).'_path', 'Pluf_DB_Field_File_Path')
);
}
function formField($def, $form_field='Pluf_Form_Field_File')
{
return parent::formField($def, $form_field);
}
}
/**
* Returns the url to access the file.
*/
function Pluf_DB_Field_File_Url($field, $method, $model, $args=null)
{
if (strlen($model->$field) != 0) {
return Pluf::f('upload_url').'/'.$model->$field;
}
return '';
}
/**
* Returns the path to access the file.
*/
function Pluf_DB_Field_File_Path($field, $method, $model, $args=null)
{
if (strlen($model->$field) != 0) {
return Pluf::f('upload_path').'/'.$model->$field;
}
return '';
}

View File

@@ -0,0 +1,27 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Float extends Pluf_DB_Field
{
public $type = 'float';
}

View File

@@ -0,0 +1,38 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Foreignkey extends Pluf_DB_Field
{
public $type = 'foreignkey';
function formField($def, $form_field='Pluf_Form_Field_Varchar')
{
$gmodel = new $def['model']();
$choices = array();
foreach ($gmodel->getList() as $item) {
$choices[(string) $item] = $item->id;
}
$def['choices'] = $choices;
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Integer extends Pluf_DB_Field
{
public $type = 'integer';
}

View File

@@ -0,0 +1,45 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Manytomany extends Pluf_DB_Field
{
public $type = 'manytomany';
function formField($def, $form_field='Pluf_Form_Field_Integer')
{
$method = 'get_'.$def['name'].'_list';
$def['multiple'] = true;
$def['initial'] = array();
foreach ($def['model_instance']->$method() as $item) {
$def['initial'][(string) $item] = $item->id;
}
$def['choices'] = array();
foreach (Pluf::factory($def['model'])->getList() as $item) {
$def['choices'][(string) $item] = $item->id;
}
if (!isset($def['widget'])) {
$def['widget'] = 'Pluf_Form_Widget_SelectMultipleInput';
}
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Password extends Pluf_DB_Field
{
public $type = 'varchar';
function formField($def, $form_field='Pluf_Form_Field_Varchar')
{
$def['widget'] = 'Pluf_Form_Widget_PasswordInput';
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Sequence extends Pluf_DB_Field
{
public $type = 'sequence';
/**
* It is never possible to manually set the id of a model, this
* should be passed through the URL.
*/
function formField($def, $form_field='')
{
return null;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Serialized extends Pluf_DB_Field
{
public $type = 'text';
function formField($def, $form_field='Pluf_Form_Field_Varchar')
{
if (!isset($def['widget'])) {
$def['widget'] = 'Pluf_Form_Widget_TextareaInput';
}
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,71 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* This field will automatically slugify its content.
*
* A slug is a short label for something, containing only letters,
* numbers, underscores or hyphens. They're generally used in URLs.
*
* In your model, you can specify `max_length` in the `widget_attrs`
* parameter. If `max_length` is not specified, Pluf will use a
* default length of 50.
*/
class Pluf_DB_Field_Slug extends Pluf_DB_Field
{
public $type = 'varchar';
/**
* @see Pluf_DB_Field::formField()
*/
function formField($def, $form_field = 'Pluf_Form_Field_Slug')
{
return parent::formField($def, $form_field);
}
/**
* Return a "URL friendly" version in lowercase.
*
* Define the words separator with the configuration
* option <code>slug-separator</code>. Default to <code>-</code>.
*
* @param $value string Value to convert
* @return string The slugify version.
*/
public static function slugify($value)
{
$separator = Pluf::f('slug-separator', '-');
$value = Pluf_Text_UTF8::romanize(Pluf_Text_UTF8::deaccent($value));
$value = preg_replace('#[^'.$separator.'\w]#u',
$separator,
mb_strtolower($value, Pluf::f('encoding', 'UTF-8')));
// remove redundant
$value = preg_replace('#'.$separator.'{2,}#u',
$separator,
trim($value, $separator));
return $value;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Text extends Pluf_DB_Field
{
public $type = 'text';
function formField($def, $form_field='Pluf_Form_Field_Varchar')
{
if (!isset($def['widget'])) {
$def['widget'] = 'Pluf_Form_Widget_TextareaInput';
}
return parent::formField($def, $form_field);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Field_Varchar extends Pluf_DB_Field
{
public $type = 'varchar';
}

View File

@@ -0,0 +1,52 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Introspect
{
protected $int = null;
protected $backend = '';
public function __construct($db)
{
$this->int = Pluf::factory('Pluf_DB_Introspect_'.$db->engine, $db);
$this->backend = $db->engine;
}
/**
* Get the list of tables in the current database. The search
* automatically limit the list to the visible ones.
*
* @param object DB connection.
* @return array List of tables.
*/
function listTables()
{
if (!method_exists($this->int, 'listTables')) {
throw new Pluf_Exception_NotImplemented();
}
return $this->int->listTables();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Introspect_MySQL
{
protected $db = null;
public function __construct($db)
{
$this->db = $db;
}
/**
* Get the list of tables in the current database.
*
* @param object DB connection.
* @return array List of tables.
*/
function listTables()
{
$sql = 'SHOW TABLES';
$res = $this->db->select($sql);
$tables = array();
foreach ($res as $t) {
$tables[] = array_pop($t);
}
return $tables;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_Introspect_PostgreSQL
{
protected $db = null;
public function __construct($db)
{
$this->db = $db;
}
/**
* Get the list of tables in the current database. The search
* automatically limit the list to the visible ones.
*
* @param object DB connection.
* @return array List of tables.
*/
function listTables()
{
$sql = 'SELECT c.relname AS name
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN (\'r\', \'v\', \'\')
AND n.nspname NOT IN (\'pg_catalog\', \'pg_toast\')
AND pg_catalog.pg_table_is_visible(c.oid)';
$res = $this->db->select($sql);
$tables = array();
foreach ($res as $t) {
$tables[] = $t['name'];
}
return $tables;
}
}

202
pluf/src/Pluf/DB/MySQL.php Normal file
View File

@@ -0,0 +1,202 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* MySQL connection class
*/
class Pluf_DB_MySQL
{
public $con_id;
public $pfx = '';
private $debug = true;
/** The last query, set with debug(). Used when an error is returned. */
public $lastquery = '';
public $engine = 'MySQL';
public $type_cast = array();
function __construct($user, $pwd, $server, $dbname, $pfx='', $debug=false)
{
Pluf::loadFunction('Pluf_DB_defaultTypecast');
$this->type_cast = Pluf_DB_defaultTypecast();
$this->debug('* MYSQL CONNECT');
$this->con_id = mysql_connect($server, $user, $pwd);
$this->debug = $debug;
$this->pfx = $pfx;
if (!$this->con_id) {
throw new Exception($this->getError());
}
$this->database($dbname);
$this->execute('SET NAMES \'utf8\'');
}
function database($dbname)
{
$db = mysql_select_db($dbname);
$this->debug('* USE DATABASE '.$dbname);
if (!$db) {
throw new Exception($this->getError());
}
return true;
}
/**
* Get the version of the MySQL server.
*
* @return string Version string
*/
function getServerInfo()
{
return mysql_get_server_info($this->con_id);
}
/**
* Log the queries. Keep track of the last query and if in debug mode
* keep track of all the queries in
* $GLOBALS['_PX_debug_data']['sql_queries']
*
* @param string Query to keep track
* @return bool true
*/
function debug($query)
{
$this->lastquery = $query;
if (!$this->debug) return true;
if (!isset($GLOBALS['_PX_debug_data']['sql_queries']))
$GLOBALS['_PX_debug_data']['sql_queries'] = array();
$GLOBALS['_PX_debug_data']['sql_queries'][] = $query;
return true;
}
function close()
{
if ($this->con_id) {
mysql_close($this->con_id);
return true;
} else {
return false;
}
}
function select($query)
{
$this->debug($query);
$cur = mysql_query($query, $this->con_id);
if ($cur) {
$res = array();
while ($row = mysql_fetch_assoc($cur)) {
$res[] = $row;
}
mysql_free_result($cur);
return $res;
} else {
throw new Exception($this->getError());
}
}
function execute($query)
{
$this->debug($query);
$cur = mysql_query($query, $this->con_id);
if (!$cur) {
throw new Exception($this->getError());
} else {
return true;
}
}
function getLastID()
{
$this->debug('* GET LAST ID');
return (int) mysql_insert_id($this->con_id);
}
/**
* Returns a string ready to be used in the exception.
*
* @return string Error string
*/
function getError()
{
if ($this->con_id) {
return mysql_errno($this->con_id).' - '
.mysql_error($this->con_id).' - '.$this->lastquery;
} else {
return mysql_errno().' - '
.mysql_error().' - '.$this->lastquery;
}
}
function esc($str)
{
return '\''.mysql_real_escape_string($str, $this->con_id).'\'';
}
/**
* Quote the column name.
*
* @param string Name of the column
* @return string Escaped name
*/
function qn($col)
{
return '`'.$col.'`';
}
/**
* Start a transaction.
*/
function begin()
{
if (Pluf::f('db_mysql_transaction', false)) {
$this->execute('BEGIN');
}
}
/**
* Commit a transaction.
*/
function commit()
{
if (Pluf::f('db_mysql_transaction', false)) {
$this->execute('COMMIT');
}
}
/**
* Rollback a transaction.
*/
function rollback()
{
if (Pluf::f('db_mysql_transaction', false)) {
$this->execute('ROLLBACK');
}
}
function __toString()
{
return '<Pluf_DB_MySQL('.$this->con_id.')>';
}
}

View File

@@ -0,0 +1,271 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* PostgreSQL connection class
*/
class Pluf_DB_PostgreSQL
{
/**
* The connection resource.
*/
public $con_id;
/**
* The prefix for the table names.
*/
public $pfx = '';
/**
* Debug mode.
*/
private $debug = false;
/**
* The last query, set with debug(). Used when an error is
* returned.
*/
public $lastquery = '';
/**
* Name of the engine.
*/
public $engine = 'PostgreSQL';
/**
* Used by the model to convert the values from and to the
* database.
*
* @see Pluf_DB_defaultTypecast
*/
public $type_cast = array();
/**
* Current query cursor.
*/
private $cur = null;
/**
* Current search path.
*/
public $search_path = 'public';
function __construct($user, $pwd, $server, $dbname, $pfx='', $debug=false)
{
Pluf::loadFunction('Pluf_DB_defaultTypecast');
$this->type_cast = Pluf_DB_defaultTypecast();
$this->type_cast['Pluf_DB_Field_Boolean'] =
array('Pluf_DB_PostgreSQL_BooleanFromDb', 'Pluf_DB_BooleanToDb');
$this->type_cast['Pluf_DB_Field_Compressed'] =
array('Pluf_DB_PostgreSQL_CompressedFromDb', 'Pluf_DB_PostgreSQL_CompressedToDb');
$this->debug('* POSTGRESQL CONNECT');
$cstring = '';
if ($server) {
$cstring .= 'host='.$server.' ';
}
$cstring .= 'dbname='.$dbname.' user='.$user;
if ($pwd) {
$cstring .= ' password='.$pwd;
}
$this->debug = $debug;
$this->pfx = $pfx;
$this->cur = null;
$this->con_id = @pg_connect($cstring);
if (!$this->con_id) {
throw new Exception($this->getError());
}
}
/**
* Get the version of the PostgreSQL server.
*
* Requires PostgreSQL 7.4 or later.
*
* @return string Version string
*/
function getServerInfo()
{
$ver = pg_version($this->con_id);
return $ver['server'];
}
/**
* Log the queries. Keep track of the last query and if in debug mode
* keep track of all the queries in
* $GLOBALS['_PX_debug_data']['sql_queries']
*
* @param string Query to keep track
* @return bool true
*/
function debug($query)
{
$this->lastquery = $query;
if (!$this->debug) return true;
if (!isset($GLOBALS['_PX_debug_data']['sql_queries']))
$GLOBALS['_PX_debug_data']['sql_queries'] = array();
$GLOBALS['_PX_debug_data']['sql_queries'][] = $query;
return true;
}
function close()
{
if ($this->con_id) {
pg_close($this->con_id);
return true;
} else {
return false;
}
}
function select($query)
{
$this->debug($query);
$this->cur = @pg_query($this->con_id, $query);
if (!$this->cur) {
throw new Exception($this->getError());
}
$res = array();
while ($row = pg_fetch_assoc($this->cur)) {
$res[] = $row;
}
@pg_free_result($this->cur);
$this->cur = null;
return $res;
}
function execute($query)
{
$this->debug($query);
$this->cur = @pg_query($this->con_id, $query);
if (!$this->cur) {
throw new Exception($this->getError());
}
return true;
}
function getLastID()
{
$this->debug('* GET LAST ID');
$res = $this->select('SELECT lastval() AS last_id');
return (int) $res[0]['last_id'];
}
/**
* Returns a string ready to be used in the exception.
*
* @return string Error string
*/
function getError()
{
if ($this->cur) {
return pg_result_error($this->cur).' - '.$this->lastquery;
}
if ($this->con_id) {
return pg_last_error($this->con_id).' - '.$this->lastquery;
} else {
return pg_last_error().' - '.$this->lastquery;
}
}
function esc($str)
{
return '\''.pg_escape_string($this->con_id, $str).'\'';
}
/**
* Set the current search path.
*/
function setSearchPath($search_path='public')
{
if (preg_match('/[^\w\s\,]/', $search_path)) {
throw new Exception('The search path: "'.$search_path.'" is not valid.');
}
$this->execute('SET search_path TO '.$search_path);
$this->search_path = $search_path;
return true;
}
/**
* Quote the column name.
*
* @param string Name of the column
* @return string Escaped name
*/
function qn($col)
{
return '"'.$col.'"';
}
/**
* Start a transaction.
*/
function begin()
{
$this->execute('BEGIN');
}
/**
* Commit a transaction.
*/
function commit()
{
$this->execute('COMMIT');
}
/**
* Rollback a transaction.
*/
function rollback()
{
$this->execute('ROLLBACK');
}
function __toString()
{
return '<Pluf_DB_PostgreSQL('.$this->con_id.')>';
}
}
function Pluf_DB_PostgreSQL_BooleanFromDb($val)
{
if (!$val) {
return false;
}
return (strtolower(substr($val, 0, 1)) == 't');
}
function Pluf_DB_PostgreSQL_CompressedToDb($val, $con)
{
if (is_null($val)) {
return 'NULL';
}
return "'".pg_escape_bytea(gzdeflate($val, 9))."'";
}
function Pluf_DB_PostgreSQL_CompressedFromDb($val)
{
return ($val) ? gzinflate(pg_unescape_bytea($val)) : $val;
}

178
pluf/src/Pluf/DB/SQLite.php Normal file
View File

@@ -0,0 +1,178 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* SQLite connection class
*/
class Pluf_DB_SQLite
{
public $con_id;
public $pfx = '';
private $debug = false;
/** The last query, set with debug(). Used when an error is returned. */
public $lastquery = '';
public $engine = 'SQLite';
public $type_cast = array();
function __construct($user, $pwd, $server, $dbname, $pfx='', $debug=false)
{
Pluf::loadFunction('Pluf_DB_defaultTypecast');
$this->type_cast = Pluf_DB_defaultTypecast();
$this->debug = $debug;
$this->pfx = $pfx;
$this->debug('* SQLITE OPEN');
$this->type_cast['Pluf_DB_Field_Compressed'] = array('Pluf_DB_CompressedFromDb', 'Pluf_DB_SQLite_CompressedToDb');
// Connect and let the Exception be thrown in case of problem
try {
$this->con_id = new PDO('sqlite:'.$dbname);
} catch (PDOException $e) {
throw $e;
}
}
/**
* Get the version of the SQLite library.
*
* @return string Version string
*/
function getServerInfo()
{
return $this->con_id->getAttribute(PDO::ATTR_SERVER_INFO);
}
/**
* Log the queries. Keep track of the last query and if in debug mode
* keep track of all the queries in
* $GLOBALS['_PX_debug_data']['sql_queries']
*
* @param string Query to keep track
* @return bool true
*/
function debug($query)
{
$this->lastquery = $query;
if (!$this->debug) return true;
if (!isset($GLOBALS['_PX_debug_data']['sql_queries']))
$GLOBALS['_PX_debug_data']['sql_queries'] = array();
$GLOBALS['_PX_debug_data']['sql_queries'][] = $query;
return true;
}
function close()
{
$this->con_id = null;
return true;
}
function select($query)
{
$this->debug($query);
if (false === ($cur = $this->con_id->query($query))) {
throw new Exception($this->getError());
}
return $cur->fetchAll(PDO::FETCH_ASSOC);
}
function execute($query)
{
$this->debug($query);
if (false === ($cur = $this->con_id->exec($query))) {
throw new Exception($this->getError());
}
return $cur;
}
function getLastID()
{
$this->debug('* GET LAST ID');
return (int) $this->con_id->lastInsertId();;
}
/**
* Returns a string ready to be used in the exception.
*
* @return string Error string
*/
function getError()
{
$err = $this->con_id->errorInfo();
$err[] = $this->lastquery;
return implode(' - ', $err);
}
function esc($str)
{
return $this->con_id->quote($str);
}
/**
* Quote the column name.
*
* @param string Name of the column
* @return string Escaped name
*/
function qn($col)
{
return '"'.$col.'"';
}
/**
* Start a transaction.
*/
function begin()
{
$this->execute('BEGIN');
}
/**
* Commit a transaction.
*/
function commit()
{
$this->execute('COMMIT');
}
/**
* Rollback a transaction.
*/
function rollback()
{
$this->execute('ROLLBACK');
}
function __toString()
{
return '<Pluf_DB_SQLite('.$this->con_id.')>';
}
}
function Pluf_DB_SQLite_CompressedToDb($val, $con)
{
if (is_null($val)) {
return 'NULL';
}
return 'X'.$con->esc(bin2hex(gzdeflate($val, 9)));
}

156
pluf/src/Pluf/DB/Schema.php Normal file
View File

@@ -0,0 +1,156 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Create the schema of a given Pluf_Model for a given database.
*/
class Pluf_DB_Schema
{
/**
* Database connection object.
*/
private $con = null;
/**
* Model from which the schema is generated.
*/
public $model = null;
/**
* Schema generator object corresponding to the database.
*/
public $schema = null;
function __construct($db, $model=null)
{
$this->con = $db;
$this->model = $model;
$this->schema = Pluf::factory('Pluf_DB_Schema_'.$db->engine, $db);
}
/**
* Get the schema generator.
*
* @return object Pluf_DB_Schema_XXXX
*/
function getGenerator()
{
return $this->schema;
}
/**
* Create the tables and indexes for the current model.
*
* @return mixed True if success or database error.
*/
function createTables()
{
$sql = $this->schema->getSqlCreate($this->model);
foreach ($sql as $k => $query) {
if (false === $this->con->execute($query)) {
throw new Exception($this->con->getError());
}
}
$sql = $this->schema->getSqlIndexes($this->model);
foreach ($sql as $k => $query) {
if (false === $this->con->execute($query)) {
throw new Exception($this->con->getError());
}
}
return true;
}
/**
* Creates the constraints for the current model.
* This should be done _after_ all tables of all models have been created.
*
* @throws Exception
*/
function createConstraints()
{
$sql = $this->schema->getSqlCreateConstraints($this->model);
foreach ($sql as $k => $query) {
if (false === $this->con->execute($query)) {
throw new Exception($this->con->getError());
}
}
}
/**
* Drop the tables and indexes for the current model.
*
* @return mixed True if success or database error.
*/
function dropTables()
{
$sql = $this->schema->getSqlDelete($this->model);
foreach ($sql as $k => $query) {
if (false === $this->con->execute($query)) {
throw new Exception($this->con->getError());
}
}
return true;
}
/**
* Drops the constraints for the current model.
* This should be done _before_ all tables of all models are dropped.
*
* @throws Exception
* @return boolean
*/
function dropConstraints()
{
$sql = $this->schema->getSqlDeleteConstraints($this->model);
foreach ($sql as $k => $query) {
if (false === $this->con->execute($query)) {
throw new Exception($this->con->getError());
}
}
return true;
}
/**
* Given a column name or a string with column names in the format
* "column1, column2, column3", returns the escaped correctly
* quoted column names. This is good for index creation.
*
* @param string Column
* @param Pluf_DB DB handler
* @return string Quoted for the DB column(s)
*/
public static function quoteColumn($col, $db)
{
if (false !== strpos($col, ',')) {
$cols = explode(',', $col);
} else {
$cols = array($col);
}
$res = array();
foreach ($cols as $col) {
$res[] = $db->qn(trim($col));
}
return implode(', ', $res);
}
}

View File

@@ -0,0 +1,319 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Generator of the schemas corresponding to a given model.
*
* This class is for MySQL, you can create a class on the same
* model for another database engine.
*/
class Pluf_DB_Schema_MySQL
{
/**
* Mapping of the fields.
*/
public $mappings = array(
'varchar' => 'varchar(%s)',
'sequence' => 'mediumint(9) unsigned not null auto_increment',
'boolean' => 'bool',
'date' => 'date',
'datetime' => 'datetime',
'file' => 'varchar(150)',
'manytomany' => null,
'foreignkey' => 'mediumint(9) unsigned',
'text' => 'longtext',
'html' => 'longtext',
'time' => 'time',
'integer' => 'integer',
'email' => 'varchar(150)',
'password' => 'varchar(150)',
'float' => 'numeric(%s, %s)',
'blob' => 'blob',
);
public $defaults = array(
'varchar' => "''",
'sequence' => null,
'boolean' => 1,
'date' => 0,
'datetime' => 0,
'file' => "''",
'manytomany' => null,
'foreignkey' => 0,
'text' => "''",
'html' => "''",
'time' => 0,
'integer' => 0,
'email' => "''",
'password' => "''",
'float' => 0.0,
'blob' => "''",
);
private $con = null;
function __construct($con)
{
$this->con = $con;
}
/**
* Get the SQL to generate the tables of the given model.
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlCreate($model)
{
$tables = array();
$cols = $model->_a['cols'];
$manytomany = array();
$sql = 'CREATE TABLE `'.$this->con->pfx.$model->_a['table'].'` (';
foreach ($cols as $col => $val) {
$field = new $val['type']();
if ($field->type != 'manytomany') {
$sql .= "\n".$this->con->qn($col).' ';
$_tmp = $this->mappings[$field->type];
if ($field->type == 'varchar') {
if (isset($val['size'])) {
$_tmp = sprintf($this->mappings['varchar'], $val['size']);
} else {
$_tmp = sprintf($this->mappings['varchar'], '150');
}
}
if ($field->type == 'float') {
if (!isset($val['max_digits'])) {
$val['max_digits'] = 32;
}
if (!isset($val['decimal_places'])) {
$val['decimal_places'] = 8;
}
$_tmp = sprintf($this->mappings['float'], $val['max_digits'], $val['decimal_places']);
}
$sql .= $_tmp;
if (empty($val['is_null'])) {
$sql .= ' NOT NULL';
}
if (isset($val['default'])) {
$sql .= ' default ';
$sql .= $model->_toDb($val['default'], $col);
} elseif ($field->type != 'sequence') {
$sql .= ' default '.$this->defaults[$field->type];
}
$sql .= ',';
} else {
$manytomany[] = $col;
}
}
$sql .= "\n".'PRIMARY KEY (`id`))';
$sql .= 'ENGINE=InnoDB DEFAULT CHARSET=utf8;';
$tables[$this->con->pfx.$model->_a['table']] = $sql;
// Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $hay[0].'_'.$hay[1].'_assoc';
$sql = 'CREATE TABLE `'.$this->con->pfx.$table.'` (';
$sql .= "\n".'`'.strtolower($model->_a['model']).'_id` '.$this->mappings['foreignkey'].' default 0,';
$sql .= "\n".'`'.strtolower($omodel->_a['model']).'_id` '.$this->mappings['foreignkey'].' default 0,';
$sql .= "\n".'PRIMARY KEY ('.strtolower($model->_a['model']).'_id, '.strtolower($omodel->_a['model']).'_id)';
$sql .= "\n".') ENGINE=InnoDB';
$sql .=' DEFAULT CHARSET=utf8;';
$tables[$this->con->pfx.$table] = $sql;
}
return $tables;
}
/**
* Get the SQL to generate the indexes of the given model.
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlIndexes($model)
{
$index = array();
foreach ($model->_a['idx'] as $idx => $val) {
if (!isset($val['col'])) {
$val['col'] = $idx;
}
$index[$this->con->pfx.$model->_a['table'].'_'.$idx] =
sprintf('CREATE INDEX `%s` ON `%s` (%s);',
$idx, $this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($val['col'], $this->con));
}
foreach ($model->_a['cols'] as $col => $val) {
$field = new $val['type']();
if ($field->type == 'foreignkey') {
$index[$this->con->pfx.$model->_a['table'].'_'.$col.'_foreignkey'] =
sprintf('CREATE INDEX `%s` ON `%s` (`%s`);',
$col.'_foreignkey_idx', $this->con->pfx.$model->_a['table'], $col);
}
if (isset($val['unique']) and $val['unique'] == true) {
$index[$this->con->pfx.$model->_a['table'].'_'.$col.'_unique'] =
sprintf('CREATE UNIQUE INDEX `%s` ON `%s` (%s);',
$col.'_unique_idx',
$this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($col, $this->con)
);
}
}
return $index;
}
/**
* Workaround for <http://bugs.mysql.com/bug.php?id=13942> which limits the
* length of foreign key identifiers to 64 characters.
*
* @param string
* @return string
*/
function getShortenedFKeyName($name)
{
if (strlen($name) <= 64) {
return $name;
}
return substr($name, 0, 55).'_'.substr(md5($name), 0, 8);
}
/**
* Get the SQL to create the constraints for the given model
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlCreateConstraints($model)
{
$table = $this->con->pfx.$model->_a['table'];
$constraints = array();
$alter_tbl = 'ALTER TABLE '.$table;
$cols = $model->_a['cols'];
$manytomany = array();
foreach ($cols as $col => $val) {
$field = new $val['type']();
// remember these for later
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
if ($field->type == 'foreignkey') {
// Add the foreignkey constraints
$referto = new $val['model']();
$constraints[] = $alter_tbl.' ADD CONSTRAINT '.$this->getShortenedFKeyName($table.'_'.$col.'_fkey').'
FOREIGN KEY ('.$this->con->qn($col).')
REFERENCES '.$this->con->pfx.$referto->_a['table'].' (id)
ON DELETE NO ACTION ON UPDATE NO ACTION';
}
}
// Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $this->con->pfx.$hay[0].'_'.$hay[1].'_assoc';
$alter_tbl = 'ALTER TABLE '.$table;
$constraints[] = $alter_tbl.' ADD CONSTRAINT '.$this->getShortenedFKeyName($table.'_fkey1').'
FOREIGN KEY ('.strtolower($model->_a['model']).'_id)
REFERENCES '.$this->con->pfx.$model->_a['table'].' (id)
ON DELETE NO ACTION ON UPDATE NO ACTION';
$constraints[] = $alter_tbl.' ADD CONSTRAINT '.$this->getShortenedFKeyName($table.'_fkey2').'
FOREIGN KEY ('.strtolower($omodel->_a['model']).'_id)
REFERENCES '.$this->con->pfx.$omodel->_a['table'].' (id)
ON DELETE NO ACTION ON UPDATE NO ACTION';
}
return $constraints;
}
/**
* Get the SQL to drop the tables corresponding to the model.
*
* @param Object Model
* @return string SQL string ready to execute.
*/
function getSqlDelete($model)
{
$cols = $model->_a['cols'];
$manytomany = array();
$sql = 'DROP TABLE IF EXISTS `'.$this->con->pfx.$model->_a['table'].'`';
foreach ($cols as $col => $val) {
$field = new $val['type']();
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
}
//Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $hay[0].'_'.$hay[1].'_assoc';
$sql .= ', `'.$this->con->pfx.$table.'`';
}
return array($sql);
}
/**
* Get the SQL to drop the constraints for the given model
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlDeleteConstraints($model)
{
$table = $this->con->pfx.$model->_a['table'];
$constraints = array();
$alter_tbl = 'ALTER TABLE '.$table;
$cols = $model->_a['cols'];
$manytomany = array();
foreach ($cols as $col => $val) {
$field = new $val['type']();
// remember these for later
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
if ($field->type == 'foreignkey') {
// Add the foreignkey constraints
$referto = new $val['model']();
$constraints[] = $alter_tbl.' DROP CONSTRAINT '.$this->getShortenedFKeyName($table.'_'.$col.'_fkey');
}
}
// Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $this->con->pfx.$hay[0].'_'.$hay[1].'_assoc';
$alter_tbl = 'ALTER TABLE '.$table;
$constraints[] = $alter_tbl.' DROP CONSTRAINT '.$this->getShortenedFKeyName($table.'_fkey1');
$constraints[] = $alter_tbl.' DROP CONSTRAINT '.$this->getShortenedFKeyName($table.'_fkey2');
}
return $constraints;
}
}

View File

@@ -0,0 +1,308 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Generator of the schemas corresponding to a given model.
*
* This class is for PostgreSQL, you can create a class on the same
* model for another database engine.
*/
class Pluf_DB_Schema_PostgreSQL
{
/**
* Mapping of the fields.
*/
public $mappings = array(
'varchar' => 'character varying',
'sequence' => 'serial',
'boolean' => 'boolean',
'date' => 'date',
'datetime' => 'timestamp',
'file' => 'character varying',
'manytomany' => null,
'foreignkey' => 'integer',
'text' => 'text',
'html' => 'text',
'time' => 'time',
'integer' => 'integer',
'email' => 'character varying',
'password' => 'character varying',
'float' => 'real',
'blob' => 'bytea',
);
public $defaults = array(
'varchar' => "''",
'sequence' => null,
'boolean' => 'FALSE',
'date' => "'0001-01-01'",
'datetime' => "'0001-01-01 00:00:00'",
'file' => "''",
'manytomany' => null,
'foreignkey' => 0,
'text' => "''",
'html' => "''",
'time' => "'00:00:00'",
'integer' => 0,
'email' => "''",
'password' => "''",
'float' => 0.0,
'blob' => "''",
);
private $con = null;
function __construct($con)
{
$this->con = $con;
}
/**
* Get the SQL to generate the tables of the given model.
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlCreate($model)
{
$tables = array();
$cols = $model->_a['cols'];
$manytomany = array();
$query = 'CREATE TABLE '.$this->con->pfx.$model->_a['table'].' (';
$sql_col = array();
foreach ($cols as $col => $val) {
$field = new $val['type']();
if ($field->type != 'manytomany') {
$sql = $this->con->qn($col).' ';
$sql .= $this->mappings[$field->type];
if (empty($val['is_null'])) {
$sql .= ' NOT NULL';
}
if (isset($val['default'])) {
$sql .= ' default ';
$sql .= $model->_toDb($val['default'], $col);
} elseif ($field->type != 'sequence') {
$sql .= ' default '.$this->defaults[$field->type];
}
$sql_col[] = $sql;
} else {
$manytomany[] = $col;
}
}
$sql_col[] = 'CONSTRAINT '.$this->con->pfx.$model->_a['table'].'_pkey PRIMARY KEY (id)';
$query = $query."\n".implode(",\n", $sql_col)."\n".');';
$tables[$this->con->pfx.$model->_a['table']] = $query;
// Now for the many to many
// FIXME add index on the second column
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $hay[0].'_'.$hay[1].'_assoc';
$sql = 'CREATE TABLE '.$this->con->pfx.$table.' (';
$sql .= "\n".strtolower($model->_a['model']).'_id '.$this->mappings['foreignkey'].' default 0,';
$sql .= "\n".strtolower($omodel->_a['model']).'_id '.$this->mappings['foreignkey'].' default 0,';
$sql .= "\n".'CONSTRAINT '.$this->getShortenedIdentifierName($this->con->pfx.$table.'_pkey').' PRIMARY KEY ('.strtolower($model->_a['model']).'_id, '.strtolower($omodel->_a['model']).'_id)';
$sql .= "\n".');';
$tables[$this->con->pfx.$table] = $sql;
}
return $tables;
}
/**
* Get the SQL to generate the indexes of the given model.
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlIndexes($model)
{
$index = array();
foreach ($model->_a['idx'] as $idx => $val) {
if (!isset($val['col'])) {
$val['col'] = $idx;
}
if ($val['type'] == 'unique') {
$unique = 'UNIQUE ';
} else {
$unique = '';
}
$index[$this->con->pfx.$model->_a['table'].'_'.$idx] =
sprintf('CREATE '.$unique.'INDEX %s ON %s (%s);',
$this->con->pfx.$model->_a['table'].'_'.$idx,
$this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($val['col'], $this->con)
);
}
foreach ($model->_a['cols'] as $col => $val) {
$field = new $val['type']();
if (isset($val['unique']) and $val['unique'] == true) {
$index[$this->con->pfx.$model->_a['table'].'_'.$col.'_unique'] =
sprintf('CREATE UNIQUE INDEX %s ON %s (%s);',
$this->con->pfx.$model->_a['table'].'_'.$col.'_unique_idx',
$this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($col, $this->con)
);
}
}
return $index;
}
/**
* All identifiers in Postgres must not exceed 64 characters in length.
*
* @param string
* @return string
*/
function getShortenedIdentifierName($name)
{
if (strlen($name) <= 64) {
return $name;
}
return substr($name, 0, 55).'_'.substr(md5($name), 0, 8);
}
/**
* Get the SQL to create the constraints for the given model
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlCreateConstraints($model)
{
$table = $this->con->pfx.$model->_a['table'];
$constraints = array();
$alter_tbl = 'ALTER TABLE '.$table;
$cols = $model->_a['cols'];
$manytomany = array();
foreach ($cols as $col => $val) {
$field = new $val['type']();
// remember these for later
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
if ($field->type == 'foreignkey') {
// Add the foreignkey constraints
$referto = new $val['model']();
$constraints[] = $alter_tbl.' ADD CONSTRAINT '.$this->getShortenedIdentifierName($table.'_'.$col.'_fkey').'
FOREIGN KEY ('.$this->con->qn($col).')
REFERENCES '.$this->con->pfx.$referto->_a['table'].' (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION';
}
}
// Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $this->con->pfx.$hay[0].'_'.$hay[1].'_assoc';
$alter_tbl = 'ALTER TABLE '.$table;
$constraints[] = $alter_tbl.' ADD CONSTRAINT '.$this->getShortenedIdentifierName($table.'_fkey1').'
FOREIGN KEY ('.strtolower($model->_a['model']).'_id)
REFERENCES '.$this->con->pfx.$model->_a['table'].' (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION';
$constraints[] = $alter_tbl.' ADD CONSTRAINT '.$this->getShortenedIdentifierName($table.'_fkey2').'
FOREIGN KEY ('.strtolower($omodel->_a['model']).'_id)
REFERENCES '.$this->con->pfx.$omodel->_a['table'].' (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION';
}
return $constraints;
}
/**
* Get the SQL to drop the tables corresponding to the model.
*
* @param Object Model
* @return string SQL string ready to execute.
*/
function getSqlDelete($model)
{
$cols = $model->_a['cols'];
$manytomany = array();
$sql = array();
$sql[] = 'DROP TABLE IF EXISTS '.$this->con->pfx.$model->_a['table'].' CASCADE';
foreach ($cols as $col => $val) {
$field = new $val['type']();
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
}
//Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $hay[0].'_'.$hay[1].'_assoc';
$sql[] = 'DROP TABLE IF EXISTS '.$this->con->pfx.$table.' CASCADE';
}
return $sql;
}
/**
* Get the SQL to drop the constraints for the given model
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlDeleteConstraints($model)
{
$table = $this->con->pfx.$model->_a['table'];
$constraints = array();
$alter_tbl = 'ALTER TABLE '.$table;
$cols = $model->_a['cols'];
$manytomany = array();
foreach ($cols as $col => $val) {
$field = new $val['type']();
// remember these for later
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
if ($field->type == 'foreignkey') {
// Add the foreignkey constraints
$referto = new $val['model']();
$constraints[] = $alter_tbl.' DROP CONSTRAINT '.$this->getShortenedIdentifierName($table.'_'.$col.'_fkey');
}
}
// Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $this->con->pfx.$hay[0].'_'.$hay[1].'_assoc';
$alter_tbl = 'ALTER TABLE '.$table;
$constraints[] = $alter_tbl.' DROP CONSTRAINT '.$this->getShortenedIdentifierName($table.'_fkey1');
$constraints[] = $alter_tbl.' DROP CONSTRAINT '.$this->getShortenedIdentifierName($table.'_fkey2');
}
return $constraints;
}
}

View File

@@ -0,0 +1,246 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Generator of the schemas corresponding to a given model.
*
* This class is for SQLite, you can create a class on the same
* model for another database engine.
*/
class Pluf_DB_Schema_SQLite
{
/**
* Mapping of the fields.
*/
public $mappings = array(
'varchar' => 'varchar(%s)',
'sequence' => 'integer primary key autoincrement',
'boolean' => 'bool',
'date' => 'date',
'datetime' => 'datetime',
'file' => 'varchar(150)',
'manytomany' => null,
'foreignkey' => 'integer',
'text' => 'text',
'html' => 'text',
'time' => 'time',
'integer' => 'integer',
'email' => 'varchar(150)',
'password' => 'varchar(150)',
'float' => 'real',
'blob' => 'blob',
);
public $defaults = array(
'varchar' => "''",
'sequence' => null,
'boolean' => 1,
'date' => 0,
'datetime' => 0,
'file' => "''",
'manytomany' => null,
'foreignkey' => 0,
'text' => "''",
'html' => "''",
'time' => 0,
'integer' => 0,
'email' => "''",
'password' => "''",
'float' => 0.0,
'blob' => "''",
);
private $con = null;
function __construct($con)
{
$this->con = $con;
}
/**
* Get the SQL to generate the tables of the given model.
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlCreate($model)
{
$tables = array();
$cols = $model->_a['cols'];
$manytomany = array();
$query = 'CREATE TABLE '.$this->con->pfx.$model->_a['table'].' (';
$sql_col = array();
foreach ($cols as $col => $val) {
$field = new $val['type']();
if ($field->type != 'manytomany') {
$sql = $this->con->qn($col).' ';
$_tmp = $this->mappings[$field->type];
if ($field->type == 'varchar') {
if (isset($val['size'])) {
$_tmp = sprintf($this->mappings['varchar'], $val['size']);
} else {
$_tmp = sprintf($this->mappings['varchar'], '150');
}
}
if ($field->type == 'float') {
if (!isset($val['max_digits'])) {
$val['max_digits'] = 32;
}
if (!isset($val['decimal_places'])) {
$val['decimal_places'] = 8;
}
$_tmp = sprintf($this->mappings['float'], $val['max_digits'], $val['decimal_places']);
}
$sql .= $_tmp;
if (empty($val['is_null'])) {
$sql .= ' not null';
}
if (isset($val['default'])) {
$sql .= ' default '.$model->_toDb($val['default'], $col);
} elseif ($field->type != 'sequence') {
$sql .= ' default '.$this->defaults[$field->type];
}
$sql_col[] = $sql;
} else {
$manytomany[] = $col;
}
}
$query = $query."\n".implode(",\n", $sql_col)."\n".');';
$tables[$this->con->pfx.$model->_a['table']] = $query;
//Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $hay[0].'_'.$hay[1].'_assoc';
$sql = 'CREATE TABLE '.$this->con->pfx.$table.' (';
$sql .= "\n".strtolower($model->_a['model']).'_id '.$this->mappings['foreignkey'].' default 0,';
$sql .= "\n".strtolower($omodel->_a['model']).'_id '.$this->mappings['foreignkey'].' default 0,';
$sql .= "\n".'primary key ('.strtolower($model->_a['model']).'_id, '.strtolower($omodel->_a['model']).'_id)';
$sql .= "\n".');';
$tables[$this->con->pfx.$table] = $sql;
}
return $tables;
}
/**
* SQLite cannot add foreign key constraints to already existing tables,
* so we skip their creation completely.
*
* @param Object Model
* @return array
*/
function getSqlCreateConstraints($model)
{
return array();
}
/**
* Get the SQL to generate the indexes of the given model.
*
* @param Object Model
* @return array Array of SQL strings ready to execute.
*/
function getSqlIndexes($model)
{
$index = array();
foreach ($model->_a['idx'] as $idx => $val) {
if (!isset($val['col'])) {
$val['col'] = $idx;
}
$unique = (isset($val['type']) && ($val['type'] == 'unique')) ? 'UNIQUE ' : '';
$index[$this->con->pfx.$model->_a['table'].'_'.$idx] =
sprintf('CREATE %sINDEX %s ON %s (%s);',
$unique,
$this->con->pfx.$model->_a['table'].'_'.$idx,
$this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($val['col'], $this->con)
);
}
foreach ($model->_a['cols'] as $col => $val) {
$field = new $val['type']();
if ($field->type == 'foreignkey') {
$index[$this->con->pfx.$model->_a['table'].'_'.$col.'_foreignkey'] =
sprintf('CREATE INDEX %s ON %s (%s);',
$this->con->pfx.$model->_a['table'].'_'.$col.'_foreignkey_idx',
$this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($col, $this->con));
}
if (isset($val['unique']) and $val['unique'] == true) {
$index[$this->con->pfx.$model->_a['table'].'_'.$col.'_unique'] =
sprintf('CREATE UNIQUE INDEX %s ON %s (%s);',
$this->con->pfx.$model->_a['table'].'_'.$col.'_unique_idx',
$this->con->pfx.$model->_a['table'],
Pluf_DB_Schema::quoteColumn($col, $this->con)
);
}
}
return $index;
}
/**
* Get the SQL to drop the tables corresponding to the model.
*
* @param Object Model
* @return string SQL string ready to execute.
*/
function getSqlDelete($model)
{
$cols = $model->_a['cols'];
$manytomany = array();
$sql = array();
$sql[] = 'DROP TABLE IF EXISTS '.$this->con->pfx.$model->_a['table'];
foreach ($cols as $col => $val) {
$field = new $val['type']();
if ($field->type == 'manytomany') {
$manytomany[] = $col;
}
}
//Now for the many to many
foreach ($manytomany as $many) {
$omodel = new $cols[$many]['model']();
$hay = array(strtolower($model->_a['model']), strtolower($omodel->_a['model']));
sort($hay);
$table = $hay[0].'_'.$hay[1].'_assoc';
$sql[] = 'DROP TABLE IF EXISTS '.$this->con->pfx.$table;
}
return $sql;
}
/**
* SQLite cannot drop foreign keys from existing tables,
* so we skip their deletion completely.
*
* @param Object Model
* @return array
*/
function getSqlDeleteConstraints($model)
{
return array();
}
}

View File

@@ -0,0 +1,53 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_DB_SchemaInfo extends Pluf_Model
{
public $_model = __CLASS__;
function init()
{
$this->_a['table'] = 'schema_info';
$this->_a['model'] = 'Pluf_DB_SchemaInfo';
$this->_a['cols'] = array(
// It is mandatory to have an "id" column.
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
//It is automatically added.
'blank' => true,
),
'application' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
'unique' => true,
),
'version' =>
array(
'type' => 'Pluf_DB_Field_Integer',
'blank' => false,
),
);
}
}

View File

@@ -0,0 +1,84 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Database statistics class.
*
* This class is just a wrapper which will pass the queries to the
* underlying database class but keeping timing information. This is
* very good to track your slow queries and improve your code.
*
*/
class Pluf_DB_Stats
{
/**
* The real database connection.
*/
protected $_rdb = null;
public function __construct($db)
{
$this->_rdb = $db;
}
public function __call($name, $args)
{
if (!in_array($name, array('execute', 'select'))) {
return call_user_func_array(array($this->_rdb, $name), $args);
}
Pluf_Log::stime('timer');
$res = call_user_func_array(array($this->_rdb, $name), $args);
Pluf_Log::perf(array('Pluf_DB_Stats', $this->_rdb->lastquery, Pluf_Log::etime('timer', 'total_sql')));
Pluf_Log::inc('sql_query');
return $res;
}
public function __get($name)
{
return $this->_rdb->$name;
}
public function __set($name, $value)
{
return $this->_rdb->$name = $value;
}
}
function Pluf_DB_Stats_getConnection($extra=null)
{
if (isset($GLOBALS['_PX_db']) &&
(is_resource($GLOBALS['_PX_db']->con_id) or is_object($GLOBALS['_PX_db']->con_id))) {
return $GLOBALS['_PX_db'];
}
$GLOBALS['_PX_db'] = new Pluf_DB_Stats(
Pluf_DB::get(Pluf::f('db_engine'),
Pluf::f('db_server'),
Pluf::f('db_database'),
Pluf::f('db_login'),
Pluf::f('db_password'),
Pluf::f('db_table_prefix'),
Pluf::f('db_debug'),
Pluf::f('db_version'))
);
return $GLOBALS['_PX_db'];
}

212
pluf/src/Pluf/Date.php Normal file
View File

@@ -0,0 +1,212 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Date
{
/**
* Get a GM Date in the format YYYY-MM-DD HH:MM:SS and returns a
* string with the given format in the current timezone.
*
* @param string GMDate
* @param string Format to be given to strftime ('%Y-%m-%d %H:%M:%S')
* @return string Formated GMDate into the local time
*/
public static function gmDateToString($gmdate, $format='%Y-%m-%d %H:%M:%S')
{
$time = strtotime($gmdate.'Z');
return strftime($format, $time);
}
/**
* Get a GM Date in the format YYYY-MM-DD HH:MM:SS and returns a
* string with the given format in GMT.
*
* @param string GMDate
* @param string Format to be given to date ('c')
* @return string Formated GMDate into GMT
*/
public static function gmDateToGmString($gmdate, $format='c')
{
$time = strtotime($gmdate.'Z');
return date($format, $time);
}
/**
* Day compare.
*
* Compare if the first date is before or after the second date.
* Returns:
* 0 if the days are the same.
* 1 if the first date is before the second.
* -1 if the first date is after the second.
*
* @param string YYYY-MM-DD date.
* @param string YYYY-MM-DD date (today local time).
* @return int
*/
public static function dayCompare($date1, $date2=null)
{
$date2 = (is_null($date2)) ? date('Y-m-d') : $date2;
if ($date2 == $date1) return 0;
if ($date1 > $date2) return -1;
return 1;
}
}
/**
* Set of functions to manage dates.
*/
/**
* Compare two date and returns the number of seconds between the
* first and the second. If only the date is given without time, the
* end of the day is used (23:59:59).
*
* @param string Date to compare for ex: '2006-09-17 18:42:00'
* @param string Second date to compare if null use now (null)
* @return int Number of seconds between the two dates. Negative
* value if the second date is before the first.
*/
function Pluf_Date_Compare($date1, $date2=null)
{
if (strlen($date1) == 10) {
$date1 .= ' 23:59:59';
}
if (is_null($date2)) {
$date2 = time();
} else {
if (strlen($date2) == 10) {
$date2 .= ' 23:59:59';
}
$date2 = strtotime(str_replace('-', '/', $date2));
}
$date1 = strtotime(str_replace('-', '/', $date1));
return $date2 - $date1;
}
/**
* Display a date in the format:
* X days Y hours ago
* X hours Y minutes ago
* X hours Y minutes left
*
* "resolution" is year, month, day, hour, minute.
*
* If not time is given, only the day, the end of the day is
* used: 23:59:59.
*
* @param string Date to compare with ex: '2006-09-17 18:42:00'
* @param string Reference date to compare with by default now (null)
* @param int Maximum number of elements to show (2)
* @param string If no delay between the two dates display ('now')
* @param bool Show ago/left suffix
* @return string Formatted date
*/
function Pluf_Date_Easy($date, $ref=null, $blocks=2, $notime='now', $show=true)
{
if (strlen($date) == 10) {
$date .= ' 23:59:59';
}
if (is_null($ref)) {
$ref = date('Y-m-d H:i:s');
$tref = time();
} else {
if (strlen($ref) == 10) {
$ref .= ' 23:59:59';
}
$tref = strtotime(str_replace('-', '/', $ref));
}
$tdate = strtotime(str_replace('-', '/', $date));
$past = true;
if ($tref < $tdate) {
// date in the past
$past = false;
$_tmp = $ref;
$ref = $date;
$date = $_tmp;
}
$ref = str_replace(array(' ', ':'), '-', $ref);
$date = str_replace(array(' ', ':'), '-', $date);
$refs = explode('-', $ref);
$dates = explode('-', $date);
// Modulo on the month is dynamically calculated after
$modulos = array(365, 12, 31, 24, 60, 60);
// day in month
$month = $refs[1] - 1;
$modulos[2] = date('t', mktime(0, 0, 0, $month, 1, $refs[0]));
$diffs = array();
for ($i=0; $i<6; $i++) {
$diffs[$i] = $refs[$i] - $dates[$i];
}
$retain = 0;
for ($i=5; $i>-1; $i--) {
$diffs[$i] = $diffs[$i] - $retain;
$retain = 0;
if ($diffs[$i] < 0) {
$diffs[$i] = $modulos[$i] + $diffs[$i];
$retain = 1;
}
}
$res = '';
$total = 0;
for ($i=0; $i<5; $i++) {
if ($diffs[$i] > 0) {
$total++;
$res .= $diffs[$i].' ';
switch ($i) {
case 0:
$res .= _n('year', 'years', $diffs[$i]);
break;
case 1:
$res .= _n('month', 'months', $diffs[$i]);
break;
case 2:
$res .= _n('day', 'days', $diffs[$i]);
break;
case 3:
$res .= _n('hour', 'hours', $diffs[$i]);
break;
case 4:
$res .= _n('minute', 'minutes', $diffs[$i]);
break;
case 5:
$res .= _n('second', 'seconds', $diffs[$i]);
break;
}
$res .= ' ';
}
if ($total >= $blocks) break;
}
if (strlen($res) == 0) {
return $notime;
}
if ($show) {
if ($past) {
$res = sprintf(__('%s ago'), $res);
} else {
$res = sprintf(__('%s left'), $res);
}
}
return $res;
}

View File

@@ -0,0 +1,223 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Dispatcher
{
/**
* The unique method to call.
*
* @param string Query string ('')
*/
public static function dispatch($query='')
{
try {
$query = preg_replace('#^(/)+#', '/', '/'.$query);
$req = new Pluf_HTTP_Request($query);
$middleware = array();
foreach (Pluf::f('middleware_classes', array()) as $mw) {
$middleware[] = new $mw();
}
$skip = false;
foreach ($middleware as $mw) {
if (method_exists($mw, 'process_request')) {
$response = $mw->process_request($req);
if ($response !== false) {
// $response is a response
if (Pluf::f('pluf_runtime_header', false)) {
$response->headers['X-Perf-Runtime'] = sprintf('%.5f', (microtime(true) - $GLOBALS['_PX_starttime']));
}
$response->render($req->method != 'HEAD' and !defined('IN_UNIT_TESTS'));
$skip = true;
break;
}
}
}
if ($skip === false) {
$response = self::match($req);
if (!empty($req->response_vary_on)) {
$response->headers['Vary'] = $req->response_vary_on;
}
$middleware = array_reverse($middleware);
foreach ($middleware as $mw) {
if (method_exists($mw, 'process_response')) {
$response = $mw->process_response($req, $response);
}
}
if (Pluf::f('pluf_runtime_header', false)) {
$response->headers['X-Perf-Runtime'] = sprintf('%.5f', (microtime(true) - $GLOBALS['_PX_starttime']));
}
$response->render($req->method != 'HEAD' and !defined('IN_UNIT_TESTS'));
}
} catch (Exception $e) {
if (Pluf::f('debug', false) == true) {
$response = new Pluf_HTTP_Response_ServerErrorDebug($e);
} else {
$response = new Pluf_HTTP_Response_ServerError($e);
}
$response->render($req->method != 'HEAD' and !defined('IN_UNIT_TESTS'));
if (defined('IN_UNIT_TESTS')) {
throw $e;
}
}
/**
* [signal]
*
* Pluf_Dispatcher::postDispatch
*
* [sender]
*
* Pluf_Dispatcher
*
* [description]
*
* This signal is sent after the rendering of a request. This
* means you cannot affect the response but you can use this
* hook to do some cleaning.
*
* [parameters]
*
* array('request' => $request,
* 'response' => $response)
*
*/
$params = array('request' => $req,
'response' => $response);
Pluf_Signal::send('Pluf_Dispatcher::postDispatch',
'Pluf_Dispatcher', $params);
return array($req, $response);
}
/**
* Match a query against the actions controllers.
*
* @see Pluf_HTTP_URL_reverse
*
* @param Pluf_HTTP_Request Request object
* @return Pluf_HTTP_Response Response object
*/
public static function match($req, $firstpass=true)
{
try {
$views = $GLOBALS['_PX_views'];
$to_match = $req->query;
$n = count($views);
$i = 0;
while ($i<$n) {
$ctl = $views[$i];
if (preg_match($ctl['regex'], $to_match, $match)) {
if (!isset($ctl['sub'])) {
return self::send($req, $ctl, $match);
} else {
// Go in the subtree
$views = $ctl['sub'];
$i = 0;
$n = count($views);
$to_match = substr($to_match, strlen($match[0]));
continue;
}
}
$i++;
}
} catch (Pluf_HTTP_Error404 $e) {
// Need to add a 404 error handler
// something like Pluf::f('404_handler', 'class::method')
}
if ($firstpass and substr($req->query, -1) != '/') {
$req->query .= '/';
$res = self::match($req, false);
if ($res->status_code != 404) {
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
$name = (isset($req->view[0]['name'])) ?
$req->view[0]['name'] :
$req->view[0]['model'].'::'.$req->view[0]['method'];
$url = Pluf_HTTP_URL_urlForView($name, array_slice($req->view[1], 1));
return new Pluf_HTTP_Response_Redirect($url, 301);
}
}
return new Pluf_HTTP_Response_NotFound($req);
}
/**
* Call the view found by self::match.
*
* The called view can throw an exception. This is fine and
* normal.
*
* @param Pluf_HTTP_Request Current request
* @param array The url definition matching the request
* @param array The match found by preg_match
* @return Pluf_HTTP_Response Response object
*/
public static function send($req, $ctl, $match)
{
$req->view = array($ctl, $match);
$m = new $ctl['model']();
if (isset($m->{$ctl['method'].'_precond'})) {
// Here we have preconditions to respects. If the "answer"
// is true, then ok go ahead, if not then it a response so
// return it or an exception so let it go.
$preconds = $m->{$ctl['method'].'_precond'};
if (!is_array($preconds)) {
$preconds = array($preconds);
}
foreach ($preconds as $precond) {
if (!is_array($precond)) {
$res = call_user_func_array(
explode('::', $precond),
array(&$req)
);
} else {
$res = call_user_func_array(
explode('::', $precond[0]),
array_merge(array(&$req),
array_slice($precond, 1))
);
}
if ($res !== true) {
return $res;
}
}
}
if (!isset($ctl['params'])) {
return $m->$ctl['method']($req, $match);
} else {
return $m->$ctl['method']($req, $match, $ctl['params']);
}
}
/**
* Load the controllers.
*
* @param string File including the views.
* @return bool Success.
*/
public static function loadControllers($file)
{
if (file_exists($file)) {
$GLOBALS['_PX_views'] = include $file;
return true;
}
return false;
}
}

186
pluf/src/Pluf/Encoder.php Normal file
View File

@@ -0,0 +1,186 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Validators are functions used to validate user/program input.
*
* A validator signature is:
* my_validator($field_data, $params=array())
* with $params an associative array of parameters.
*
*
* A validator must fail on an empty string by raising an
* Pluf_Form_Invalid Exception or return the data in the right format
* (string, bool, whatever).
*
* FIXME: Escape the strings when bad strings are sent in the error message.
*/
class Pluf_Encoder
{
/**
* Store the complete form data if validation is coming from a form.
*/
protected $form = array();
/**
* Set the form data.
*
* @param &array Reference to the form data
*/
function setFormData(&$form)
{
$this->form = $form;
}
/**
* Check if could be empty or not.
*/
function checkEmpty($data, $form=array(), $p=array())
{
if (strlen($data) == 0
and isset($p['blank']) and false == $p['blank']) {
throw new Pluf_Form_Invalid(__('The value must not be empty.'));
}
return true;
}
/**
* Validate an url.
* Only the structure is checked, no check of availability of the
* url is performed. It is a really basic validation.
*/
static function url($url, $form=array(), $p=array())
{
$ip = '(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.'
.'(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}';
$dom = '([a-z0-9\.\-]+)';
if (preg_match('!^(http|https|ftp|gopher)\://('.$ip.'|'.$dom.')!i', $url)) {
return $url;
} else {
throw new Pluf_Form_Invalid(sprintf(__('The URL <em>%s</em> is not valid.'), htmlspecialchars($url)));
}
}
static function varchar($string, $form=array(), $p=array())
{
if (isset($p['size']) && strlen($string) > $p['size']) {
throw new Pluf_Form_Invalid(sprintf(__('The value should not be more than <em>%s</em> characters long.'), $p['size']));
}
return $string;
}
static function password($string, $form=array(), $p=array())
{
if (strlen($string) < 6) {
throw new Pluf_Form_Invalid(sprintf(__('The password must be at least <em>%s</em> characters long.'), '6'));
}
return $string;
}
static function email($string, $form=array(), $p=array())
{
if (preg_match('/^[A-Z0-9._%-][+A-Z0-9._%-]*@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$/i', $string)) {
return $string;
} else {
throw new Pluf_Form_Invalid(sprintf(__('The email address "%s" is not valid.'),
$string));
}
}
static function text($string, $form=array(), $p=array())
{
return Pluf_Encoder::varchar($string, $form, $p);
}
static function sequence($id, $form=array(), $p=array())
{
return Pluf_Encoder::integer($id, $p);
}
static function boolean($bool, $form=array(), $p=array())
{
if (in_array($bool, array('on', 'y', '1', 1, true))) {
return true;
}
return false;
}
static function foreignkey($id, $form=array(), $p=array())
{
return Pluf_Encoder::integer($id, $p);
}
static function integer($int, $form=array(), $p=array())
{
if (!preg_match('/[0-9]+/', $int)) {
throw new Pluf_Form_Invalid(__('The value must be an integer.'));
}
return (int) $int;
}
static function datetime($datetime, $form=array(), $p=array())
{
if (false === ($stamp = strtotime($datetime))) {
throw new Pluf_Form_Invalid(sprintf(__('The date and time <em>%s</em> are not valid.'), htmlspecialchars($datetime)));
}
//convert to GMT
return gmdate('Y-m-d H:i:s', $stamp);
}
static function date($date, $form=array(), $p=array())
{
$ymd = explode('-', $date);
if (count($ymd) != 3 or strlen($ymd[0]) != 4
or false === checkdate($ymd[1], $ymd[2], $ymd[0])) {
throw new Pluf_Form_Invalid(sprintf(__('The date <em>%s</em> is not valid.'), htmlspecialchars($date)));
}
return $date;
}
static function manytomany($vals, $form=array(), $p=array())
{
$res = array();
foreach ($vals as $val) {
$res[] = Pluf_Encoder::integer($val);
}
return $res;
}
static function float($val, $form=array(), $p=array())
{
return (float) $val;
}
/*
'file' => "''",
'manytomany' => null,
'foreignkey' => 0,
'text' => "''",
'html' => "''",
'time' => 0,
'integer' => 0,
);
*/
}

117
pluf/src/Pluf/Error.php Normal file
View File

@@ -0,0 +1,117 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume CMS, a website management application.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume CMS is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume CMS 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Error handling class.
*
* @credits Basis idea from Olivier Meunier
*/
class Pluf_Error
{
private $error = array(); /**< Current errors. */
/**
* Reset the errors
*/
function resetError()
{
$this->error = array();
}
/**
* Set an error.
*
* By convention the number is 4xx if the error is coming from
* the user or 5xx if coming from the system (database error for ex.)
*
* @param string Error message
* @param int Error number (0)
*/
function setError($msg, $no=0)
{
$this->error[] = array($no,$msg);
}
/**
* Returns the errors.
*
* @param bool Errors as HTML list (false)
* @param bool Show numbers (true)
* @return mixed array of errors, HTML list, or false if no errors
*/
function error($html=false, $with_nb=true)
{
if (count($this->error) > 0) {
if (!$html) {
return $this->error;
} else {
$res = '<ul>'."\n";
foreach($this->error as $v) {
$res .= '<li>'.
(($with_nb) ?
'<span class="errno">'.$v[0].'</span> - ' :
'').
'<span class="errmsg">'.$v[1].'</span></li>'."\n";
}
return $res."</ul>\n";
}
} else {
return false;
}
}
/**
* Helper function to set the error from the DB.
*
* @param string Error message from the DB
*/
function setDbError($db_error_msg)
{
$this->setError(__('DB error:').' '.$db_error_msg, 500);
}
/**
* Bulk set errors.
*
* Used when you went to recopy the errors of one object into
* another. You can call that way:
* $object->bulkSetErrors($otherobject->error());
*
* @param array List of errors
* @return bool Success
*/
function bulkSetError($errors)
{
if (!is_array($errors)) {
return false;
}
foreach ($errors as $e) {
$this->setError($e[1], $e[0]);
}
return true;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Exception extends Exception
{
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Exception_DoesNotExist extends Pluf_Exception
{
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Exception_NotImplemented extends Pluf_Exception
{
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Exception_SettingError extends Pluf_Exception
{
}

414
pluf/src/Pluf/Form.php Normal file
View File

@@ -0,0 +1,414 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Form validation class.
*
* This class is used to generate a form. You basically build it the
* same way you build a model.
*
* The form handling is heavily inspired by the Django form handling.
*
*/
class Pluf_Form implements Iterator, ArrayAccess
{
/**
* The fields of the form.
*
* They are the fully populated Pluf_Form_Field_* of the form. You
* define them in the initFields method.
*/
public $fields = array();
/**
* Prefix for the names of the fields.
*/
public $prefix = '';
public $id_fields = 'id_%s';
public $data = array();
public $cleaned_data = array();
public $errors = array();
public $is_bound = false;
public $f = null;
public $label_suffix = ':';
protected $is_valid = null;
function __construct($data=null, $extra=array(), $label_suffix=null)
{
if ($data !== null) {
$this->data = $data;
$this->is_bound = true;
}
if ($label_suffix !== null) $this->label_suffix = $label_suffix;
$this->initFields($extra);
$this->f = new Pluf_Form_FieldProxy($this);
}
function initFields($extra=array())
{
throw new Exception('Definition of the fields not implemented.');
}
/**
* Add the prefix to the form names.
*
* @param string Field name.
* @return string Field name or field name with form prefix.
*/
function addPrefix($field_name)
{
if ('' !== $this->prefix) {
return $this->prefix.'-'.$field_name;
}
return $field_name;
}
/**
* Check if the form is valid.
*
* It is also encoding the data in the form to be then saved. It
* is very simple as it leaves the work to the field. It means
* that you can easily extend this form class to have a more
* complex validation procedure like checking if a field is equals
* to another in the form (like for password confirmation) etc.
*
* @param array Associative array of the request
* @return array Array of errors
*/
function isValid()
{
if ($this->is_valid !== null) {
return $this->is_valid;
}
$this->cleaned_data = array();
$this->errors = array();
$form_methods = get_class_methods($this);
$form_vars = get_object_vars($this);
foreach ($this->fields as $name=>$field) {
$value = $field->widget->valueFromFormData($this->addPrefix($name),
$this->data);
try {
$value = $field->clean($value);
$this->cleaned_data[$name] = $value;
$method = 'clean_'.$name;
if (in_array($method, $form_methods)) {
$value = $this->$method();
$this->cleaned_data[$name] = $value;
} else if (array_key_exists($method, $form_vars) &&
is_callable($this->$method)) {
$value = call_user_func($this->$method, $this);
$this->cleaned_data[$name] = $value;
}
} catch (Pluf_Form_Invalid $e) {
if (!isset($this->errors[$name])) $this->errors[$name] = array();
$this->errors[$name][] = $e->getMessage();
if (isset($this->cleaned_data[$name])) {
unset($this->cleaned_data[$name]);
}
}
}
if (empty($this->errors)) {
try {
$this->cleaned_data = $this->clean();
} catch (Pluf_Form_Invalid $e) {
if (!isset($this->errors['__all__'])) $this->errors['__all__'] = array();
$this->errors['__all__'][] = $e->getMessage();
}
}
if (empty($this->errors)) {
$this->is_valid = true;
return true;
}
// as some errors, we do not have cleaned data available.
$this->failed();
$this->cleaned_data = array();
$this->is_valid = false;
return false;
}
/**
* Form wide cleaning function. That way you can check that if an
* input is given, then another one somewhere is also given,
* etc. If the cleaning is not ok, your method must throw a
* Pluf_Form_Invalid exception.
*
* @return array Cleaned data.
*/
public function clean()
{
return $this->cleaned_data;
}
/**
* Method just called after the validation if the validation
* failed. This can be used to remove uploaded
* files. $this->['cleaned_data'] will be available but of course
* not fully populated and with possible garbage due to the error.
*
*/
public function failed()
{
}
/**
* Get initial data for a given field.
*
* @param string Field name.
* @return string Initial data or '' of not defined.
*/
public function initial($name)
{
if (isset($this->fields[$name])) {
return $this->fields[$name]->initial;
}
return '';
}
/**
* Get the top errors.
*/
public function render_top_errors()
{
$top_errors = (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array();
array_walk($top_errors, 'Pluf_Form_htmlspecialcharsArray');
return new Pluf_Template_SafeString(Pluf_Form_renderErrorsAsHTML($top_errors), true);
}
/**
* Get the top errors.
*/
public function get_top_errors()
{
return (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array();
}
/**
* Helper function to render the form.
*
* See render_p() for a usage example.
*
* @credit Django Project (http://www.djangoproject.com/)
* @param string Normal row.
* @param string Error row.
* @param string Row ender.
* @param string Help text HTML.
* @param bool Should we display errors on a separate row.
* @return string HTML of the form.
*/
protected function htmlOutput($normal_row, $error_row, $row_ender,
$help_text_html, $errors_on_separate_row)
{
$top_errors = (isset($this->errors['__all__'])) ? $this->errors['__all__'] : array();
array_walk($top_errors, 'Pluf_Form_htmlspecialcharsArray');
$output = array();
$hidden_fields = array();
foreach ($this->fields as $name=>$field) {
$bf = new Pluf_Form_BoundField($this, $field, $name);
$bf_errors = $bf->errors;
array_walk($bf_errors, 'Pluf_Form_htmlspecialcharsArray');
if ($field->widget->is_hidden) {
foreach ($bf_errors as $_e) {
$top_errors[] = sprintf(__('(Hidden field %1$s) %2$s'),
$name, $_e);
}
$hidden_fields[] = $bf; // Not rendered
} else {
if ($errors_on_separate_row and count($bf_errors)) {
$output[] = sprintf($error_row, Pluf_Form_renderErrorsAsHTML($bf_errors));
}
if (strlen($bf->label) > 0) {
$label = htmlspecialchars($bf->label, ENT_COMPAT, 'UTF-8');
if ($this->label_suffix) {
if (!in_array(mb_substr($label, -1, 1),
array(':','?','.','!'))) {
$label .= $this->label_suffix;
}
}
$label = $bf->labelTag($label);
} else {
$label = '';
}
if ($bf->help_text) {
// $bf->help_text can contains HTML and is not
// escaped.
$help_text = sprintf($help_text_html, $bf->help_text);
} else {
$help_text = '';
}
$errors = '';
if (!$errors_on_separate_row and count($bf_errors)) {
$errors = Pluf_Form_renderErrorsAsHTML($bf_errors);
}
$output[] = sprintf($normal_row, $errors, $label,
$bf->render_w(), $help_text);
}
}
if (count($top_errors)) {
$errors = sprintf($error_row,
Pluf_Form_renderErrorsAsHTML($top_errors));
array_unshift($output, $errors);
}
if (count($hidden_fields)) {
$_tmp = '';
foreach ($hidden_fields as $hd) {
$_tmp .= $hd->render_w();
}
if (count($output)) {
$last_row = array_pop($output);
$last_row = substr($last_row, 0, -strlen($row_ender)).$_tmp
.$row_ender;
$output[] = $last_row;
} else {
$output[] = $_tmp;
}
}
return new Pluf_Template_SafeString(implode("\n", $output), true);
}
/**
* Render the form as a list of paragraphs.
*/
public function render_p()
{
return $this->htmlOutput('<p>%1$s%2$s %3$s%4$s</p>', '%s', '</p>',
' %s', true);
}
/**
* Render the form as a list without the <ul></ul>.
*/
public function render_ul()
{
return $this->htmlOutput('<li>%1$s%2$s %3$s%4$s</li>', '<li>%s</li>',
'</li>', ' %s', false);
}
/**
* Render the form as a table without <table></table>.
*/
public function render_table()
{
return $this->htmlOutput('<tr><th>%2$s</th><td>%1$s%3$s%4$s</td></tr>',
'<tr><td colspan="2">%s</td></tr>',
'</td></tr>', '<br /><span class="helptext">%s</span>', false);
}
/**
* Overloading of the get method.
*
* The overloading is to be able to use property call in the
* templates.
*/
function __get($prop)
{
if (!in_array($prop, array('render_p', 'render_ul', 'render_table', 'render_top_errors', 'get_top_errors'))) {
return $this->$prop;
}
return $this->$prop();
}
/**
* Get a given field by key.
*/
public function field($key)
{
return new Pluf_Form_BoundField($this, $this->fields[$key], $key);
}
/**
* Iterator method to iterate over the fields.
*
* Get the current item.
*/
public function current()
{
$field = current($this->fields);
$name = key($this->fields);
return new Pluf_Form_BoundField($this, $field, $name);
}
public function key()
{
return key($this->fields);
}
public function next()
{
next($this->fields);
}
public function rewind()
{
reset($this->fields);
}
public function valid()
{
// We know that the boolean false will not be stored as a
// field, so we can test against false to check if valid or
// not.
return (false !== current($this->fields));
}
public function offsetUnset($index)
{
unset($this->fields[$index]);
}
public function offsetSet($index, $value)
{
$this->fields[$index] = $value;
}
public function offsetGet($index)
{
if (!isset($this->fields[$index])) {
throw new Exception('Undefined index: '.$index);
}
return $this->fields[$index];
}
public function offsetExists($index)
{
return (isset($this->fields[$index]));
}
}
function Pluf_Form_htmlspecialcharsArray(&$item, $key)
{
$item = htmlspecialchars($item, ENT_COMPAT, 'UTF-8');
}
function Pluf_Form_renderErrorsAsHTML($errors)
{
$tmp = array();
foreach ($errors as $err) {
$tmp[] = '<li>'.$err.'</li>';
}
return '<ul class="errorlist">'.implode("\n", $tmp).'</ul>';
}

View File

@@ -0,0 +1,156 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* A class to store field, widget and data.
*
* Used when rendering a form.
*/
class Pluf_Form_BoundField
{
public $form = null;
public $field = null;
public $name = null;
public $html_name = null;
public $label = null;
public $help_text = null;
public $errors = array();
public function __construct($form, $field, $name)
{
$this->form = $form;
$this->field = $field;
$this->name = $name;
$this->html_name = $this->form->addPrefix($name);
if ($this->field->label == '') {
$this->label = mb_ereg_replace('/\_/', '/ /', mb_ucfirst($name));
} else {
$this->label = $this->field->label;
}
$this->help_text = ($this->field->help_text) ? $this->field->help_text : '';
if (isset($this->form->errors[$name])) {
$this->errors = $this->form->errors[$name];
}
}
public function render_w($widget=null, $attrs=array())
{
if ($widget === null) {
$widget = $this->field->widget;
}
$id = $this->autoId();
if ($id and !array_key_exists('id', $attrs)
and !array_key_exists('id', $widget->attrs)) {
$attrs['id'] = $id;
}
if (!$this->form->is_bound) {
$data = $this->form->initial($this->name);
} else {
$data = $this->field->widget->valueFromFormData($this->html_name, $this->form->data);
}
return $widget->render($this->html_name, $data, $attrs);
}
/**
* Returns the HTML of the label tag. Wraps the given contents in
* a <label>, if the field has an ID attribute. Does not
* HTML-escape the contents. If contents aren't given, uses the
* field's HTML-escaped label. If attrs are given, they're used as
* HTML attributes on the <label> tag.
*
* @param string Content of the label, will not be escaped (null).
* @param array Extra attributes.
* @return string HTML of the label.
*/
public function labelTag($contents=null, $attrs=array())
{
$contents = ($contents) ? $contents : htmlspecialchars($this->label);
$widget = $this->field->widget;
$id = (isset($widget->attrs['id'])) ? $widget->attrs['id'] : $this->autoId();
$_tmp = array();
foreach ($attrs as $attr=>$val) {
$_tmp[] = $attr.'="'.$val.'"';
}
if (count($_tmp)) {
$attrs = ' '.implode(' ', $_tmp);
} else {
$attrs = '';
}
return new Pluf_Template_SafeString(sprintf('<label for="%s"%s>%s</label>',
$widget->idForLabel($id), $attrs, $contents), true);
}
/**
* Calculates and returns the ID attribute for this BoundField, if
* the associated Form has specified auto_id. Returns an empty
* string otherwise.
*
* @return string Id or empty string if no auto id defined.
*/
public function autoId()
{
$id_fields = $this->form->id_fields;
if (false !== strpos($id_fields, '%s')) {
return sprintf($id_fields, $this->html_name);
} elseif ($id_fields) {
return $this->html_name;
}
return '';
}
/**
* Return HTML to display the errors.
*/
public function fieldErrors()
{
Pluf::loadFunction('Pluf_Form_renderErrorsAsHTML');
return new Pluf_Template_SafeString(Pluf_Form_renderErrorsAsHTML($this->errors), true);
}
/**
* Overloading of the property access.
*/
public function __get($prop)
{
if (!in_array($prop, array('labelTag', 'fieldErrors', 'render_w'))) {
return $this->$prop;
}
return $this->$prop();
}
/**
* Render as string.
*/
public function __toString()
{
return (string)$this->render_w();
}
}
if (!function_exists('mb_ucfirst')) {
function mb_ucfirst($str) {
return mb_strtoupper(mb_substr($str, 0, 1)).mb_substr($str, 1);
}
}

View File

@@ -0,0 +1,187 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Default form field.
*
* A form field is providing a defined set of methods and properties
* to be used in the rendering of the fields in forms, in the
* conversion of the data from the user input to a form usable by the
* models.
*/
class Pluf_Form_Field
{
/**
* Store the name of the class.
*/
public $class = 'Pluf_Form_Field';
/**
* Widget. The way to "present" the field to the user.
*/
public $widget = 'Pluf_Form_Widget_TextInput';
public $label = ''; /**< The label of the field. */
public $required = false; /**< Allowed to be blank. */
public $help_text = ''; /**< Help text for the field. */
public $initial = ''; /**< Default value when empty. */
public $choices = null; /**< Predefined choices for the field. */
/*
* Following member variables are more for internal cooking.
*/
public $hidden_widget = 'Pluf_Form_Widget_HiddenInput';
public $value = ''; /**< Current value of the field. */
/**
* Returning multiple values (select multiple etc.)
*/
public $multiple = false;
protected $empty_values = array('', null, array());
/**
* Constructor.
*
* Example:
* $field = new Your_Field(array('required'=>true,
* 'widget'=>'Pluf_Form_Widget_TextInput',
* 'initial'=>'your name here',
* 'label'=>__('Your name'),
* 'help_text'=>__('You are?'));
*
* @param array Params of the field.
*/
function __construct($params=array())
{
// We basically take the parameters, for each one we grab the
// corresponding member variable and populate the $default
// array with. Then we merge with the values given in the
// parameters and update the member variables.
// This allows to pass extra parameters likes 'min_size'
// etc. and update the member variables accordingly. This is
// practical when you extend this class with your own class.
$default = array();
foreach ($params as $key=>$in) {
if ($key !== 'widget_attrs')
$default[$key] = $this->$key; // Here on purpose it
// will fail if a
// parameter not needed
// for this field is
// passed.
}
$m = array_merge($default, $params);
foreach ($params as $key=>$in) {
if ($key !== 'widget_attrs')
$this->$key = $m[$key];
}
// Set the widget to be an instance and not the string name.
$widget_name = $this->widget;
if (isset($params['widget_attrs'])) {
$attrs = $params['widget_attrs'];
} else {
$attrs = array();
}
$widget = new $widget_name($attrs);
$attrs = $this->widgetAttrs($widget);
if (count($attrs)) {
$widget->attrs = array_merge($widget->attrs, $attrs);
}
$this->widget = $widget;
}
/**
* Validate some possible input for the field.
*
* @param mixed Value to clean.
* @return mixed Cleaned data or throw a Pluf_Form_Invalid exception.
*/
function clean($value)
{
if (!$this->multiple and $this->required
and in_array($value, $this->empty_values)) {
throw new Pluf_Form_Invalid(__('This field is required.'));
}
if ($this->multiple and $this->required and empty($value)) {
throw new Pluf_Form_Invalid(__('This field is required.'));
}
return $value;
}
/**
* Set the default empty value for a field.
*
* @param mixed Value
* @return mixed Value
*/
function setDefaultEmpty($value)
{
if (in_array($value, $this->empty_values) and !$this->multiple) {
$value = '';
}
if (in_array($value, $this->empty_values) and $this->multiple) {
$value = array();
}
return $value;
}
/**
* Multi-clean a value.
*
* If you are getting multiple values, you need to go through all
* of them and validate them against the requirements. This will
* do that for you. Basically, it is cloning the field, marking it
* as not multiple and validate each value. It will throw an
* exception in case of failure.
*
* If you are implementing your own field which could be filled by
* a "multiple" widget, you need to perform a check on
* $this->multiple.
*
* @see Pluf_Form_Field_Integer::clean
*
* @param array Values
* @return array Values
*/
public function multiClean($value)
{
$field = clone($this);
$field->multiple = false;
reset($value);
while (list($i, $val) = each($value)) {
$value[$i] = $field->clean($val);
}
reset($value);
return $value;
}
/**
* Returns the HTML attributes to add to the field.
*
* @param object Widget
* @return array HTML attributes.
*/
public function widgetAttrs($widget)
{
return array();
}
}

View File

@@ -0,0 +1,36 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Boolean extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_CheckboxInput';
public function clean($value)
{
//parent::clean($value);
if (in_array($value, array('on', 'y', '1', 1, true))) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,55 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Date extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public $input_formats = array(
'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', // 2006-10-25, 10/25/2006, 10/25/06
'%b %d %Y', '%b %d, %Y', // 'Oct 25 2006', 'Oct 25, 2006'
'%d %b %Y', '%d %b, %Y', // '25 Oct 2006', '25 Oct, 2006'
'%B %d %Y', '%B %d, %Y', // 'October 25 2006', 'October 25, 2006'
'%d %B %Y', '%d %B, %Y', // '25 October 2006', '25 October, 2006'
);
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
return '';
}
foreach ($this->input_formats as $format) {
if (false !== ($date = strptime($value, $format))) {
$day = $date['tm_mday'];
$month = $date['tm_mon'] + 1;
$year = $date['tm_year'] + 1900;
if (checkdate($month, $day, $year)) {
return str_pad($year, 4, '0', STR_PAD_LEFT).'-'.
str_pad($month, 2, '0', STR_PAD_LEFT).'-'.
str_pad($day, 2, '0', STR_PAD_LEFT);
}
}
}
throw new Pluf_Form_Invalid(__('Enter a valid date.'));
}
}

View File

@@ -0,0 +1,68 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Datetime extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_DatetimeInput';
public $input_formats = array(
'%Y-%m-%d %H:%M:%S', // '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M', // '2006-10-25 14:30'
'%Y-%m-%d', // '2006-10-25'
'%m/%d/%Y %H:%M:%S', // '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M', // '10/25/2006 14:30'
'%m/%d/%Y', // '10/25/2006'
'%m/%d/%y %H:%M:%S', // '10/25/06 14:30:59'
'%m/%d/%y %H:%M', // '10/25/06 14:30'
'%m/%d/%y', // '10/25/06'
);
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
return '';
}
foreach ($this->input_formats as $format) {
if (false !== ($date = strptime($value, $format))) {
$day = $date['tm_mday'];
$month = $date['tm_mon'] + 1;
$year = $date['tm_year'] + 1900;
// PHP's strptime has various quirks, e.g. it doesn't check
// gregorian dates for validity and it also allows '60' in
// the seconds part
if (checkdate($month, $day, $year) && $date['tm_sec'] < 60) {
$date = str_pad($year, 4, '0', STR_PAD_LEFT).'-'.
str_pad($month, 2, '0', STR_PAD_LEFT).'-'.
str_pad($day, 2, '0', STR_PAD_LEFT).' '.
str_pad($date['tm_hour'], 2, '0', STR_PAD_LEFT).':'.
str_pad($date['tm_min'], 2, '0', STR_PAD_LEFT).':';
str_pad($date['tm_sec'], 2, '0', STD_PAD_LEFT);
// we internally use GMT, so we convert it to a GMT date.
return gmdate('Y-m-d H:i:s', strtotime($date));
}
}
}
throw new Pluf_Form_Invalid(__('Enter a valid date/time.'));
}
}

View File

@@ -0,0 +1,42 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Email extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
$value = '';
}
if ($value == '') {
return $value;
}
if (!Pluf_Utils::isValidEmail($value)) {
throw new Pluf_Form_Invalid(__('Enter a valid email address.'));
}
return $value;
}
}

View File

@@ -0,0 +1,151 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_File extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_FileInput';
public $move_function = 'Pluf_Form_Field_File_moveToUploadFolder';
public $max_size = 2097152; // 2MB
public $move_function_params = array();
/**
* Validate some possible input for the field.
*
* @param mixed Input
* @return string Path to the file relative to 'upload_path'
*/
function clean($value)
{
parent::clean($value);
if (is_null($value) and !$this->required) {
return ''; // no file
} elseif (is_null($value) and $this->required) {
throw new Pluf_Form_Invalid(__('No files were uploaded. Please try to send the file again.'));
}
$errors = array();
$no_files = false;
switch ($value['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_INI_SIZE:
throw new Pluf_Form_Invalid(sprintf(__('The uploaded file is too large. Reduce the size of the file to %s and send it again.'),
Pluf_Utils::prettySize(ini_get('upload_max_filesize'))));
break;
case UPLOAD_ERR_FORM_SIZE:
throw new Pluf_Form_Invalid(sprintf(__('The uploaded file is too large. Reduce the size of the file to %s and send it again.'),
Pluf_Utils::prettySize($_REQUEST['MAX_FILE_SIZE'])));
break;
case UPLOAD_ERR_PARTIAL:
throw new Pluf_Form_Invalid(__('The upload did not complete. Please try to send the file again.'));
break;
case UPLOAD_ERR_NO_FILE:
if ($this->required) {
throw new Pluf_Form_Invalid(__('No files were uploaded. Please try to send the file again.'));
} else {
return ''; // no file
}
break;
case UPLOAD_ERR_NO_TMP_DIR:
case UPLOAD_ERR_CANT_WRITE:
throw new Pluf_Form_Invalid(__('The server has no temporary folder correctly configured to store the uploaded file.'));
break;
case UPLOAD_ERR_EXTENSION:
throw new Pluf_Form_Invalid(__('The uploaded file has been stopped by an extension.'));
break;
default:
throw new Pluf_Form_Invalid(__('An error occured when upload the file. Please try to send the file again.'));
}
if ($value['size'] > $this->max_size) {
throw new Pluf_Form_Invalid(sprintf(__('The uploaded file is to big (%1$s). Reduce the size to less than %2$s and try again.'),
Pluf_Utils::prettySize($value['size']),
Pluf_Utils::prettySize($this->max_size)));
}
// copy the file to the final destination and updated $value
// with the final path name. 'final_name' is relative to
// Pluf::f('upload_path')
Pluf::loadFunction($this->move_function);
// Should throw a Pluf_Form_Invalid exception if error or the
// value to be stored in the database.
return call_user_func($this->move_function, $value,
$this->move_function_params);
}
}
/**
* Default move function. The file name is sanitized.
*
* In the extra parameters, options can be used so that this function is
* matching most of the needs:
*
* * 'upload_path': The path in which the uploaded file will be
* stored.
* * 'upload_path_create': If set to true, try to create the
* upload path if not existing.
*
* * 'upload_overwrite': Set it to true if you want to allow overwritting.
*
* * 'file_name': Force the file name to this name and do not use the
* original file name. If this name contains '%s' for
* example 'myid-%s', '%s' will be replaced by the
* original filename. This can be used when for
* example, you want to prefix with the id of an
* article all the files attached to this article.
*
* If you combine those options, you can dynamically generate the path
* name in your form (for example date base) and let this upload
* function create it on demand.
*
* @param array Upload value of the form.
* @param array Extra parameters. If upload_path key is set, use it. (array())
* @return string Name relative to the upload path.
*/
function Pluf_Form_Field_File_moveToUploadFolder($value, $params=array())
{
$name = Pluf_Utils::cleanFileName($value['name']);
$upload_path = Pluf::f('upload_path', '/tmp');
if (isset($params['file_name'])) {
if (false !== strpos($params['file_name'], '%s')) {
$name = sprintf($params['file_name'], $name);
} else {
$name = $params['file_name'];
}
}
if (isset($params['upload_path'])) {
$upload_path = $params['upload_path'];
}
$dest = $upload_path.'/'.$name;
if (isset($params['upload_path_create'])
and !is_dir(dirname($dest))) {
if (false == @mkdir(dirname($dest), 0777, true)) {
throw new Pluf_Form_Invalid(__('An error occured when creating the upload path. Please try to send the file again.'));
}
}
if ((!isset($params['upload_overwrite']) or $params['upload_overwrite'] == false) and file_exists($dest)) {
throw new Pluf_Form_Invalid(sprintf(__('A file with the name "%s" has already been uploaded.'), $name));
}
if (@!move_uploaded_file($value['tmp_name'], $dest)) {
throw new Pluf_Form_Invalid(__('An error occured when uploading the file. Please try to send the file again.'));
}
@chmod($dest, 0666);
return $name;
}

View File

@@ -0,0 +1,48 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Float extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public $max_value = null;
public $min_value = null;
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
$value = '';
}
if (!is_numeric($value)) {
throw new Pluf_Form_Invalid(__('Enter a number.'));
}
$value = (float) $value;
if ($this->max_value !== null and $this->max_value < $value) {
throw new Pluf_Form_Invalid(sprintf(__('Ensure this value is less than or equal to %s.'), $this->max_value));
}
if ($this->min_value !== null and $this->min_value > $value) {
throw new Pluf_Form_Invalid(sprintf(__('Ensure this value is greater than or equal to %s.'), $this->min_value));
}
return $value;
}
}

View File

@@ -0,0 +1,56 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Integer extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public $max = null;
public $min = null;
public function clean($value)
{
parent::clean($value);
$value = $this->setDefaultEmpty($value);
if ($this->multiple) {
return $this->multiClean($value);
} else {
if ($value == '') return $value;
if (!preg_match('/^[\+\-]?[0-9]+$/', $value)) {
throw new Pluf_Form_Invalid(__('The value must be an integer.'));
}
$this->checkMinMax($value);
}
return (int) $value;
}
protected function checkMinMax($value)
{
if ($this->max !== null and $value > $this->max) {
throw new Pluf_Form_Invalid(sprintf(__('Ensure that this value is not greater than %1$d.'), $this->max));
}
if ($this->min !== null and $value < $this->min) {
throw new Pluf_Form_Invalid(sprintf(__('Ensure that this value is not lower than %1$d.'), $this->min));
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Add ReCaptcha control to your forms.
*
* You need first to get a ReCaptcha account, create a domain and get
* the API keys for your domain. Check http://recaptcha.net/ for more
* information.
*
* The recaptcha field needs to know the IP address of the user
* submitting the form and if the request is made over SSL or
* not. This means that you need to provide the $request object in the
* extra parameters of your form.
*
* To add the ReCaptcha field to your form, simply add the following
* to your form object (note the use of $extra['request']):
*
* <pre>
* $ssl = (!empty($extra['request']->SERVER['HTTPS'])
* and $extra['request']->SERVER['HTTPS'] != 'off');
*
* $this->fields['recaptcha'] = new Pluf_Form_Field_ReCaptcha(
* array('required' => true,
* 'label' => __('Please solve this challenge'),
* 'privkey' => 'PRIVATE_RECAPTCHA_KEY_HERE',
* 'remoteip' => $extra['request']->remote_addr,
* 'widget_attrs' => array(
* 'pubkey' => 'PUBLIC_RECAPTCHA_KEY_HERE',
* ),
* ));
* </pre>
*
* Then in your template, you simply need to add the ReCaptcha field:
*
* <pre>
* {if $form.f.recaptcha.errors}{$form.f.recaptcha.fieldErrors}{/if}
* {$form.f.recaptcha|safe}
* </pre>
*
* Based on http://recaptcha.googlecode.com/files/recaptcha-php-1.10.zip
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*/
class Pluf_Form_Field_ReCaptcha extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_ReCaptcha';
public $privkey = '';
public $remoteip = '';
public $extra_params = array();
public function clean($value)
{
// will throw the Pluf_Form_Invalid exception in case of
// error.
self::checkAnswer($this->privkey, $this->remoteip,
$value[0], $value[1], $this->extra_params);
return $value;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
*
* @param string Host
* @param string Path
* @param array Data
* @param int port (80
* @return array response
*/
public static function httpPost($host, $path, $data, $port=80)
{
$req = self::qsencode($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
if (false === ($fs=@fsockopen($host, $port, $errno, $errstr, 10))) {
throw new Pluf_Form_Invalid(__('Cannot connect to the reCaptcha server for validation.'));
}
fwrite($fs, $http_request);
$response = '';
while (!feof($fs)) {
$response .= fgets($fs, 1160); // One TCP-IP packet
}
fclose($fs);
return explode("\r\n\r\n", $response, 2);
}
/**
* Encodes the given data into a query string format
*
* @param array Array of string elements to be encoded
* @return string Encoded request
*/
public static function qsencode($data)
{
$d = array();
foreach ($data as $key => $value) {
$d[] = $key.'='.urlencode(stripslashes($value));
}
return implode('&', $d);
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* @param string $privkey
* @param string $remoteip
* @param string $challenge
* @param string $response
* @param array $extra_params an array of extra variables to post to the server
* @return ReCaptchaResponse
*/
public static function checkAnswer($privkey, $remoteip, $challenge, $response, $extra_params=array())
{
if ($privkey == '') {
throw new Pluf_Form_Invalid(__('To use reCAPTCHA you must set your API key.'));
}
if ($remoteip == '') {
throw new Pluf_Form_Invalid(__('For security reasons, you must pass the remote ip to reCAPTCHA.'));
}
//discard spam submissions
if (strlen($challenge) == 0 || strlen($response) == 0) {
return false;
}
$response = self::httpPost('api-verify.recaptcha.net', '/verify',
array(
'privatekey' => $privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode("\n", $response[1]);
if (trim($answers[0]) == 'true') {
return true;
} else {
throw new Pluf_Form_Invalid($answers[1]);
}
}
}

View File

@@ -0,0 +1,111 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2010 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Slug extends Pluf_Form_Field
{
/**
* Name of the widget to use for build the forms.
*
* @var string
*/
public $widget = 'Pluf_Form_Widget_TextInput';
/**
* Minimum size of field.
*
* Default to 1.
*
* @var int
**/
public $min_size = 1;
/**
* Maximum size of field.
*
* Default to 50.
*
* @var int
**/
public $max_size = 50;
protected $_error_messages = array();
public function __construct($params=array())
{
if (in_array($this->help_text, $this->empty_values)) {
$this->help_text = __('The &#8220;slug&#8221; is the URL-friendly'.
' version of the name, consisting of '.
'letters, numbers, underscores or hyphens.');
}
$this->_error_messages = array(
'min_size' => __('Ensure this value has at most %1$d characters (it has %2$d).'),
'max_size' => __('Ensure this value has at least %1$d characters (it has %2$d).')
);
parent::__construct($params);
}
/**
* Removes any character not allowed and valid the size of the field.
*
* @see Pluf_Form_Field::clean()
* @throws Pluf_Form_Invalid If the lenght of the field has not a valid size.
*/
public function clean($value)
{
parent::clean($value);
if ($value) {
$value = Pluf_DB_Field_Slug::slugify($value);
$len = mb_strlen($value, Pluf::f('encoding', 'UTF-8'));
if ($this->max_size < $len) {
throw new Pluf_Form_Invalid(sprintf($this->_error_messages['max_size'],
$this->max_size,
$len));
}
if ($this->min_size > $len) {
throw new Pluf_Form_Invalid(sprintf($this->_error_messages['min_size'],
$this->min_size,
$len));
}
}
else
$value = '';
return $value;
}
/**
* @see Pluf_Form_Field::widgetAttrs()
*/
public function widgetAttrs($widget)
{
$attrs = array();
if (!isset($widget->attrs['maxlength'])) {
$attrs['maxlength'] = $this->max_size;
} else {
$this->max_size = $widget->attrs['maxlength'];
}
return $attrs;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Url extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
return '';
}
if (!Pluf_Utils::isValidUrl($value)) {
throw new Pluf_Form_Invalid(__('Enter a valid address.'));
}
return $value;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Field_Varchar extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public $max_length = null;
public $min_length = null;
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
$value = '';
}
$value_length = mb_strlen($value);
if ($this->max_length !== null and $value_length > $this->max_length) {
throw new Pluf_Form_Invalid(sprintf(__('Ensure this value has at most %1$d characters (it has %2$d).'), $this->max_length, $value_length));
}
if ($this->min_length !== null and $value_length < $this->min_length) {
throw new Pluf_Form_Invalid(sprintf(__('Ensure this value has at least %1$d characters (it has %2$d).'), $this->min_length, $value_length));
}
return $value;
}
public function widgetAttrs($widget)
{
if ($this->max_length !== null and
in_array(get_class($widget),
array('Pluf_Form_Widget_TextInput',
'Pluf_Form_Widget_PasswordInput'))) {
return array('maxlength'=>$this->max_length);
}
return array();
}
}

View File

@@ -0,0 +1,48 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Field proxy to access a form field through {$form.f.fieldname} in a
* template.
*/
class Pluf_Form_FieldProxy
{
protected $form = null;
public function __construct(&$form)
{
$this->form = $form;
}
/**
* No control are performed. If you access a non existing field it
* will simply throw an error.
*/
public function __get($field)
{
return new Pluf_Form_BoundField($this->form,
$this->form->fields[$field],
$field);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Form_Invalid extends Exception
{
}

View File

@@ -0,0 +1,87 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Dynamic form validation class.
*
* This class is used to generate a form for a given model.
*/
class Pluf_Form_Model extends Pluf_Form
{
/**
* The model for which the form applies.
*/
public $model = null;
function initFields($extra=array())
{
$this->model = $extra['model'];
if (isset($extra['fields'])) {
// Only display a subset of the fields
$cols = array();
foreach ($extra['fields'] as $field) {
$cols[$field] = $this->model->_a['cols'][$field];
}
} else {
$cols = $this->model->_a['cols'];
}
foreach ($cols as $name=>$def) {
$db_field = new $def['type']('', $name);
$def = array_merge(array('blank' => true,
'verbose' => $name,
'help_text' => '',
'editable' => true),
$def);
if ($def['editable']) {
// The 'model_instance' and 'name' are used by the
// ManyToMany field.
$def['model_instance'] = $this->model;
$def['name'] = $name;
if (null !== ($form_field=$db_field->formField($def))) {
$this->fields[$name] = $form_field;
}
}
}
}
/**
* Save the model in the database.
*
* @param bool Commit in the database or not. If not, the object
* is returned but not saved in the database.
* @return Object Model with data set from the form.
*/
function save($commit=true)
{
if ($this->isValid()) {
$this->model->setFromFormData($this->cleaned_data);
if ($commit && $this->model->id) {
$this->model->update();
} elseif ($commit) {
$this->model->create();
}
return $this->model;
}
throw new Exception(__('Cannot save the model from an invalid form.'));
}
}

View File

@@ -0,0 +1,116 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Base class to display a form field.
*
*/
class Pluf_Form_Widget
{
public $is_hidden = false; /**< Is an hidden field? */
public $needs_multipart_form = false; /**< Do we need multipart? */
public $input_type = ''; /**< Input type of the field. */
public $attrs = array(); /**< HTML attributes for the widget. */
public function __construct($attrs=array())
{
$this->attrs = $attrs;
}
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
throw new Exception('Not Implemented.');
}
/**
* Build the list of attributes for the form.
* It should be called this way:
* $this->buildAttrs(array('name'=>$name, 'type'=>$this->input_type),
* $extra_attrs);
*
* @param array Contains the name and type attributes.
* @param array Extra attributes, like 'class' for example.
* @return array The attributes for the field.
*/
protected function buildAttrs($attrs, $extra_attrs=array())
{
return array_merge($this->attrs, $attrs, $extra_attrs);
}
/**
* A widget can split itself in multiple input form. For example
* you can have a datetime value in your model and you use 2
* inputs one for the date and one for the time to input the
* value. So the widget must know how to get back the values from
* the submitted form.
*
* @param string Name of the form.
* @param array Submitted form data.
* @return mixed Value or null if not defined.
*/
public function valueFromFormData($name, $data)
{
if (isset($data[$name])) {
return $data[$name];
}
return null;
}
/**
* Returns the HTML ID attribute of this Widget for use by a
* <label>, given the ID of the field. Returns None if no ID is
* available.
*
* This hook is necessary because some widgets have multiple HTML
* elements and, thus, multiple IDs. In that case, this method
* should return an ID value that corresponds to the first ID in
* the widget's tags.
*/
public function idForLabel($id)
{
return $id;
}
}
/**
* Convert an array in a string ready to use for HTML attributes.
*
* As all the widget will extend the Pluf_Form_Widget class, it means
* that this function is available directly in the extended class.
*/
function Pluf_Form_Widget_Attrs($attrs)
{
$_tmp = array();
foreach ($attrs as $attr=>$val) {
$_tmp[] = $attr.'="'.$val.'"';
}
return ' '.implode(' ', $_tmp);
}

View File

@@ -0,0 +1,66 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple checkbox.
*/
class Pluf_Form_Widget_CheckboxInput extends Pluf_Form_Widget_Input
{
public $input_type = 'checkbox';
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
if ((bool)$value) {
// We consider that if a value can be boolean casted to
// true, then we check the box.
$extra_attrs['checked'] = 'checked';
}
// Value of a checkbox is always "1" but when not checked, the
// corresponding key in the form associative array is not set.
return parent::render($name, '1', $extra_attrs);
}
/**
* A non checked checkbox is simply not returned in the form array.
*
* @param string Name of the form.
* @param array Submitted form data.
* @return mixed Value or null if not defined.
*/
public function valueFromFormData($name, $data)
{
if (!isset($data[$name]) or false === $data[$name]
or (string)$data[$name] === '0' or $data[$name] == '') {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,50 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple input of type datetime.
*/
class Pluf_Form_Widget_DatetimeInput extends Pluf_Form_Widget_Input
{
public $input_type = 'text';
public $format = 'Y-m-d H:i'; // '2006-10-25 14:30' by default do
// not show the seconds.
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
// Internally we use GMT, so we convert back to the current
// timezone.
if (strlen($value) > 0) {
$value = date($this->format, strtotime($value.' GMT'));
}
return parent::render($name, $value, $extra_attrs);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple input of type file.
*/
class Pluf_Form_Widget_FileInput extends Pluf_Form_Widget_Input
{
public $input_type = 'file';
public $needs_multipart_form = true;
public function render($name, $value, $extra_attrs=array())
{
$value = '';
return parent::render($name, $value, $extra_attrs);
}
}

View File

@@ -0,0 +1,31 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple input of type text.
*/
class Pluf_Form_Widget_HiddenInput extends Pluf_Form_Widget_Input
{
public $input_type = 'hidden';
public $is_hidden = true;
}

View File

@@ -0,0 +1,49 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Base class for all the input widgets. (Except radio and checkbox).
*/
class Pluf_Form_Widget_Input extends Pluf_Form_Widget
{
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
if ($value === null) $value = '';
$final_attrs = $this->buildAttrs(array('name' => $name,
'type' => $this->input_type),
$extra_attrs);
if ($value !== '') {
$value = htmlspecialchars($value, ENT_COMPAT, 'UTF-8');
$final_attrs['value'] = $value;
}
return new Pluf_Template_SafeString('<input'.Pluf_Form_Widget_Attrs($final_attrs).' />', true);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple input of type text.
*/
class Pluf_Form_Widget_PasswordInput extends Pluf_Form_Widget_Input
{
public $input_type = 'password';
public $render_value = true;
public function __construct($attrs=array())
{
$this->render_value = (isset($attrs['render_value'])) ? $attrs['render_value'] : $this->render_value;
unset($attrs['render_value']);
parent::__construct($attrs);
}
public function render($name, $value, $extra_attrs=array())
{
if ($this->render_value === false) {
$value = '';
}
return parent::render($name, $value, $extra_attrs);
}
}

View File

@@ -0,0 +1,106 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* reCAPTCHA input for your forms.
*
* Based on http://recaptcha.googlecode.com/files/recaptcha-php-1.10.zip
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*
* @see Pluf_Form_Field_ReCaptcha
*
*/
class Pluf_Form_Widget_ReCaptcha extends Pluf_Form_Widget_Input
{
public $input_type = 'text';
public $ssl = false;
public $pubkey = '';
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
return Pluf_Template::markSafe(self::getHtml($this->attrs['pubkey']));
}
/**
* Gets the challenge HTML (javascript and non-javascript
* version). This is called from the browser, and the resulting
* reCAPTCHA HTML widget is embedded within the HTML form it was
* called from.
*
* @param string A public key for reCAPTCHA
* @param string The error given by reCAPTCHA (null)
* @param boolean Should the request be made over ssl? (false)
* @return string The HTML to be embedded in the user's form.
*/
public static function getHtml($pubkey, $error=null, $use_ssl=false)
{
$server = ($use_ssl) ? 'https://api-secure.recaptcha.net'
: 'http://api.recaptcha.net';
$errorpart = ($error) ? '&amp;error='.$error : '';
return '<script type="text/javascript" src="'.$server.'/challenge?k='
.$pubkey.$errorpart.'"></script>
<noscript>
<iframe src="'.$server.'/noscript?k='.$pubkey.$errorpart
.'" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* Get the form data from the reCaptcha fields.
*
* We need to get back two fields from the POST request
* 'recaptcha_challenge_field' and 'recaptcha_response_field'.
*
* They are hardcoded, so we do not even bother checking something
* else.
*
* @param string Name of the form
* @param array Submitted form data
* @return array Challenge and answer
*/
public function valueFromFormData($name, $data)
{
$res = array('', '');
$res[0] = isset($data['recaptcha_challenge_field'])
? $data['recaptcha_challenge_field'] : '';
$res[1] = isset($data['recaptcha_response_field'])
? $data['recaptcha_response_field'] : '';
return $res;
}
}

View File

@@ -0,0 +1,78 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple checkbox with grouping.
*/
class Pluf_Form_Widget_SelectInput extends Pluf_Form_Widget
{
public $choices = array();
public function __construct($attrs=array())
{
$this->choices = $attrs['choices'];
unset($attrs['choices']);
parent::__construct($attrs);
}
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @param array Extra choices (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array(),
$choices=array())
{
$output = array();
if ($value === null) {
$value = '';
}
$final_attrs = $this->buildAttrs(array('name' => $name), $extra_attrs);
$output[] = '<select'.Pluf_Form_Widget_Attrs($final_attrs).'>';
$groups = $this->choices + $choices;
foreach($groups as $option_group => $c) {
if (!is_array($c)) {
$subchoices = array($option_group => $c);
} else {
$output[] = '<optgroup label="'.htmlspecialchars($option_group, ENT_COMPAT, 'UTF-8').'">';
$subchoices = $c;
}
foreach ($subchoices as $option_label=>$option_value) {
$selected = ($option_value == $value) ? ' selected="selected"':'';
$output[] = sprintf('<option value="%s"%s>%s</option>',
htmlspecialchars($option_value, ENT_COMPAT, 'UTF-8'),
$selected,
htmlspecialchars($option_label, ENT_COMPAT, 'UTF-8'));
}
if (is_array($c)) {
$output[] = '</optgroup>';
}
}
$output[] = '</select>';
return new Pluf_Template_SafeString(implode("\n", $output), true);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple checkbox.
*/
class Pluf_Form_Widget_SelectMultipleInput extends Pluf_Form_Widget
{
public $choices = array();
public function __construct($attrs=array())
{
$this->choices = $attrs['choices'];
unset($attrs['choices']);
parent::__construct($attrs);
}
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param array Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @param array Extra choices (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array(),
$choices=array())
{
$output = array();
if ($value === null) {
$value = array();
}
$final_attrs = $this->buildAttrs(array('name' => $name.'[]'),
$extra_attrs);
$output[] = '<select multiple="multiple"'
.Pluf_Form_Widget_Attrs($final_attrs).'>';
$choices = array_merge($this->choices, $choices);
foreach ($choices as $option_label=>$option_value) {
$selected = (in_array($option_value, $value)) ? ' selected="selected"':'';
$output[] = sprintf('<option value="%s"%s>%s</option>',
htmlspecialchars($option_value, ENT_COMPAT, 'UTF-8'),
$selected,
htmlspecialchars($option_label, ENT_COMPAT, 'UTF-8'));
}
$output[] = '</select>';
return new Pluf_Template_SafeString(implode("\n", $output), true);
}
public function valueFromFormData($name, $data)
{
if (isset($data[$name]) and is_array($data[$name])) {
return $data[$name];
}
return null;
}
}

View File

@@ -0,0 +1,74 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple checkbox.
*/
class Pluf_Form_Widget_SelectMultipleInput_Checkbox extends Pluf_Form_Widget_SelectMultipleInput
{
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param array Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @param array Extra choices (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array(),
$choices=array())
{
$output = array();
if ($value === null or $value == '') {
$value = array();
}
$final_attrs = $this->buildAttrs($extra_attrs);
$output[] = '<ul>';
$choices = array_merge($this->choices, $choices);
$i=0;
$base_id = $final_attrs['id'];
foreach ($choices as $option_label=>$option_value) {
$final_attrs['id'] = $base_id.'_'.$i;
$final_attrs['value'] = htmlspecialchars($option_value, ENT_COMPAT, 'UTF-8');
$checkbox = new Pluf_Form_Widget_CheckboxInput($final_attrs);
$rendered = $checkbox->render($name.'[]', in_array($option_value, $value));
$output[] = sprintf('<li><label>%s %s</label></li>', $rendered,
htmlspecialchars($option_label, ENT_COMPAT, 'UTF-8'));
$i++;
}
$output[] = '</ul>';
return new Pluf_Template_SafeString(implode("\n", $output), true);
}
public function idForLabel($id)
{
if ($id) {
$id += '_0';
}
return $id;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Simple input of type text.
*/
class Pluf_Form_Widget_TextInput extends Pluf_Form_Widget_Input
{
public $input_type = 'text';
}

View File

@@ -0,0 +1,55 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Textarea.
*/
class Pluf_Form_Widget_TextareaInput extends Pluf_Form_Widget
{
public function __construct($attrs=array())
{
$this->attrs = array_merge(array('cols' => '40', 'rows' => '10'),
$attrs);
}
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
if ($value === null) $value = '';
$final_attrs = $this->buildAttrs(array('name' => $name),
$extra_attrs);
return new Pluf_Template_SafeString(
sprintf('<textarea%s>%s</textarea>',
Pluf_Form_Widget_Attrs($final_attrs),
htmlspecialchars($value, ENT_COMPAT, 'UTF-8')),
true);
}
}

View File

@@ -0,0 +1,98 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Textarea with TinyMCE addition.
*/
class Pluf_Form_Widget_TinyMCEInput extends Pluf_Form_Widget
{
public $tiny_mceurl = '/media/js/editor/tiny_mce.js';
public $mode = 'textareas';
public $theme = 'simple';
public $include_tinymce = true;
public function __construct($attrs=array())
{
$defaults = array('cols' => '70',
'rows' => '20');
$config = array('tinymce_url', 'mode', 'theme', 'include_tinymce');
foreach ($config as $cfg) {
if (isset($attrs[$cfg])) {
$this->$cfg = $attrs[$cfg];
unset($attrs[$cfg]);
}
}
$this->attrs = array_merge($defaults, $attrs);
}
/**
* Renders the HTML of the input.
*
* @param string Name of the field.
* @param mixed Value for the field, can be a non valid value.
* @param array Extra attributes to add to the input form (array())
* @return string The HTML string of the input.
*/
public function render($name, $value, $extra_attrs=array())
{
if ($value === null) $value = '';
$extra_config = '';
if (isset($this->attrs['editor_config'])) {
$_ec = $this->attrs['editor_config'];
unset($this->attrs['editor_config']);
$_st = array();
foreach ($_ec as $key=>$val) {
if (is_bool($val)) {
if ($val) {
$_st[] = $key.' : true';
} else {
$_st[] = $key.' : false';
}
} else {
$_st[] = $key.' : "'.$val.'"';
}
}
if ($_st) {
$extra_config = ",\n".implode(",\n", $_st);
}
}
$final_attrs = $this->buildAttrs(array('name' => $name),
$extra_attrs);
// The special include for tinyMCE
$out = '';
if ($this->include_tinymce) {
$out .= '<script language="javascript" type="text/javascript" src="'.$this->tinymce_url.'"></script>'."\n";
}
$out .='<script language="javascript" type="text/javascript">
tinyMCE.init({
mode : "'.$this->mode.'",
theme : "'.$this->theme.'"'.$extra_config.'
});
</script>';
return new Pluf_Template_SafeString(
$out.sprintf('<textarea%s>%s</textarea>',
Pluf_Form_Widget_Attrs($final_attrs),
htmlspecialchars($value, ENT_COMPAT, 'UTF-8')),
true);
}
}

90
pluf/src/Pluf/Group.php Normal file
View File

@@ -0,0 +1,90 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_Group extends Pluf_Model
{
public $_model = 'Pluf_Group';
function init()
{
$this->_a['verbose'] = __('group');
$this->_a['table'] = 'groups';
$this->_a['model'] = 'Pluf_Group';
$this->_a['cols'] = array(
// It is mandatory to have an "id" column.
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
//It is automatically added.
'blank' => true,
),
'name' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
'size' => 50,
'verbose' => __('name'),
),
'description' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
'size' => 250,
'verbose' => __('description'),
),
'permissions' =>
array(
'type' => 'Pluf_DB_Field_Manytomany',
'blank' => true,
'model' => 'Pluf_Permission',
),
);
if (Pluf::f('pluf_custom_group',false)) $this->extended_init();
}
/**
* Hook for extended class
*/
function extended_init()
{
return;
}
function __toString()
{
return $this->name;
}
/**
* Predelete to drop the row level permissions.
*/
function preDelete()
{
if (Pluf::f('pluf_use_rowpermission', false)) {
$_rpt = Pluf::factory('Pluf_RowPermission')->getSqlTable();
$sql = new Pluf_SQL('owner_class=%s AND owner_id=%s',
array($this->_a['model'], $this->_data['id']));
$this->_con->execute('DELETE FROM '.$_rpt.' WHERE '.$sql->gen());
}
}
}

91
pluf/src/Pluf/HTTP.php Normal file
View File

@@ -0,0 +1,91 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Base HTTP tools.
*/
class Pluf_HTTP
{
/**
* Break magic_quotes
*
* @credit Olivier Meunier
*/
function removeTheMagic()
{
if (get_magic_quotes_gpc()) {
if (!empty($_GET)) {
array_walk($_GET, 'Pluf_HTTP_magicStrip');
}
if (!empty($_POST)) {
array_walk($_POST, 'Pluf_HTTP_magicStrip');
}
if (!empty($_REQUEST)) {
array_walk($_REQUEST, 'Pluf_HTTP_magicStrip');
}
if (!empty($_COOKIE)) {
array_walk($_COOKIE, 'Pluf_HTTP_magicStrip');
}
}
if (function_exists('ini_set')) {
@ini_set('session.use_cookies', '1');
@ini_set('session.use_only_cookies', '1');
@ini_set('session.use_trans_sid', '0');
@ini_set('url_rewriter.tags', '');
}
}
}
/**
* Break magic_quotes
*
* @credit Olivier Meunier
*/
function Pluf_HTTP_magicStrip(&$k, $key)
{
$k = Pluf_HTTP_handleMagicQuotes($k);
}
/**
* Break magic_quotes
*
* @credit Olivier Meunier
*/
function Pluf_HTTP_handleMagicQuotes(&$value)
{
if (is_array($value)) {
$result = array();
foreach ($value as $k => $v) {
if (is_array($v)) {
$result[$k] = Pluf_HTTP_handleMagicQuotes($v);
} else {
$result[$k] = stripslashes($v);
}
}
return $result;
} else {
return stripslashes($value);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Error404 extends Exception
{
}

View File

@@ -0,0 +1,26 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Error500 extends Exception
{
}

View File

@@ -0,0 +1,64 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* The request object.
*
* It is given as first arguments to the view as first argument.
*/
class Pluf_HTTP_Request
{
public $POST = array();
public $GET = array();
public $REQUEST = array();
public $COOKIE = array();
public $FILES = array();
public $query = '';
public $method = '';
public $uri = '';
public $view = '';
public $remote_addr = '';
public $http_host = '';
public $SERVER = array();
public $uid = '';
public $time = '';
function __construct($query)
{
$http = new Pluf_HTTP();
$http->removeTheMagic();
$this->POST =& $_POST;
$this->GET =& $_GET;
$this->REQUEST =& $_REQUEST;
$this->COOKIE =& $_COOKIE;
$this->FILES =& $_FILES;
$this->query = $query;
$this->method = $_SERVER['REQUEST_METHOD'];
$this->uri = $_SERVER['REQUEST_URI'];
$this->remote_addr = $_SERVER['REMOTE_ADDR'];
$this->http_host = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
$this->SERVER =& $_SERVER;
$this->uid = $GLOBALS['_PX_uniqid'];
$this->time = (isset($_SERVER['REQUEST_TIME'])) ? $_SERVER['REQUEST_TIME'] : time();
}
}

View File

@@ -0,0 +1,174 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Response object to be constructed by the views.
*
* When constructing a view, the response object must be populated and
* returned. The response is then displayed to the visitor.
* The interest of using a response object is that we can run a post
* filter action on the response. For example you can run a filter that
* is checking that all the output is valid HTML and write a logfile if
* this is not the case.
*/
class Pluf_HTTP_Response
{
/**
* Content of the response.
*/
public $content = '';
/**
* Array of the headers to add.
*
* For example $this->headers['Content-Type'] = 'text/html; charset=utf-8';
*/
public $headers = array();
/**
* Status code of the answer.
*/
public $status_code = 200;
/**
* Cookies to send.
*
* $this->cookies['my_cookie'] = 'content of the cookie';
*/
public $cookies = array();
/**
* Status code list.
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*/
public $status_code_list = array(
'100' => 'CONTINUE',
'101' => 'SWITCHING PROTOCOLS',
'200' => 'OK',
'201' => 'CREATED',
'202' => 'ACCEPTED',
'203' => 'NON-AUTHORITATIVE INFORMATION',
'204' => 'NO CONTENT',
'205' => 'RESET CONTENT',
'206' => 'PARTIAL CONTENT',
'300' => 'MULTIPLE CHOICES',
'301' => 'MOVED PERMANENTLY',
'302' => 'FOUND',
'303' => 'SEE OTHER',
'304' => 'NOT MODIFIED',
'305' => 'USE PROXY',
'306' => 'RESERVED',
'307' => 'TEMPORARY REDIRECT',
'400' => 'BAD REQUEST',
'401' => 'UNAUTHORIZED',
'402' => 'PAYMENT REQUIRED',
'403' => 'FORBIDDEN',
'404' => 'NOT FOUND',
'405' => 'METHOD NOT ALLOWED',
'406' => 'NOT ACCEPTABLE',
'407' => 'PROXY AUTHENTICATION REQUIRED',
'408' => 'REQUEST TIMEOUT',
'409' => 'CONFLICT',
'410' => 'GONE',
'411' => 'LENGTH REQUIRED',
'412' => 'PRECONDITION FAILED',
'413' => 'REQUEST ENTITY TOO LARGE',
'414' => 'REQUEST-URI TOO LONG',
'415' => 'UNSUPPORTED MEDIA TYPE',
'416' => 'REQUESTED RANGE NOT SATISFIABLE',
'417' => 'EXPECTATION FAILED',
'500' => 'INTERNAL SERVER ERROR',
'501' => 'NOT IMPLEMENTED',
'502' => 'BAD GATEWAY',
'503' => 'SERVICE UNAVAILABLE',
'504' => 'GATEWAY TIMEOUT',
'505' => 'HTTP VERSION NOT SUPPORTED'
);
/**
* Constructor of the response.
*
* @param string Content of the response ('')
* @param string MimeType of the response (null) if not given will
* default to the one given in the configuration 'mimetype'
*/
function __construct($content='', $mimetype=null)
{
if (is_null($mimetype)) {
$mimetype = Pluf::f('mimetype', 'text/html').'; charset=utf-8';
}
$this->content = $content;
$this->headers['Content-Type'] = $mimetype;
$this->headers['X-Powered-By'] = 'Pluf - http://pluf.org/';
$this->status_code = 200;
$this->cookies = array();
}
/**
* Render a response object.
*/
function render($output_body=true)
{
if ($this->status_code >= 200
&& $this->status_code != 204
&& $this->status_code != 304) {
$this->headers['Content-Length'] = strlen($this->content);
}
$this->outputHeaders();
if ($output_body) {
echo $this->content;
}
}
/**
* Output headers.
*/
function outputHeaders()
{
if (!defined('IN_UNIT_TESTS')) {
header('HTTP/1.0 '.$this->status_code.' '
.$this->status_code_list[$this->status_code],
true, $this->status_code);
foreach ($this->headers as $header => $ch) {
header($header.': '.$ch);
}
foreach ($this->cookies as $cookie => $data) {
// name, data, expiration, path, domain, secure, http only
$expire = (null == $data) ? time()-31536000 : time()+31536000;
$data = (null == $data) ? '' : $data;
setcookie($cookie, $data, $expire,
Pluf::f('cookie_path', '/'),
Pluf::f('cookie_domain', null),
Pluf::f('cookie_secure', false),
Pluf::f('cookie_httponly', true));
}
} else {
$_COOKIE = array();
foreach ($this->cookies as $cookie => $data) {
$_COOKIE[$cookie] = $data;
}
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Special response object to output the return value of a command.
*
* You need to use escapeshellarg() and escapeshellcmd() to provide a
* "clean" command. The Content-Length will not be set as it is not
* possible to predict it.
*/
class Pluf_HTTP_Response_CommandPassThru extends Pluf_HTTP_Response
{
/**
* The command argument must be a safe string!
*
* @param string Command to run.
* @param string Mimetype (null)
*/
function __construct($command, $mimetype=null)
{
parent::__construct($command, $mimetype);
}
/**
* Render a response object.
*/
function render($output_body=true)
{
$this->outputHeaders();
if ($output_body) {
passthru($this->content);
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_File extends Pluf_HTTP_Response
{
public $delete_file = false;
function __construct($filepath, $mimetype=null, $delete_file=false)
{
parent::__construct($filepath, $mimetype);
$this->delete_file = $delete_file;
}
/**
* Render a response object.
*/
function render($output_body=true)
{
$this->headers['Content-Length'] = (string)filesize($this->content);
$this->outputHeaders();
if ($output_body) {
$fp = fopen($this->content, 'rb');
fpassthru($fp);
fclose($fp);
}
if ($this->delete_file) {
@unlink($this->content);
}
}
}

View File

@@ -0,0 +1,42 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_Forbidden extends Pluf_HTTP_Response
{
function __construct($request)
{
$content = '';
try {
$context = new Pluf_Template_Context(array('query' => $request->query));
$tmpl = new Pluf_Template('403.html');
$content = $tmpl->render($context);
$mimetype = null;
} catch (Exception $e) {
$mimetype = 'text/plain';
$content = 'You are not authorized to view this page. You do not have permission'."\n"
.'to view the requested directory or page using the credentials supplied.'."\n\n".'403 - Forbidden';
}
parent::__construct($content, $mimetype);
$this->status_code = 403;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_Json extends Pluf_HTTP_Response
{
/**
* @param mixed Values, will be encoded using json_encode
*/
function __construct($data, $mimetype=null)
{
if (null == $mimetype) {
$mimetype = Pluf::f('mimetype_json', 'application/json').'; charset=utf-8';
}
parent::__construct(json_encode($data), $mimetype);
}
}

View File

@@ -0,0 +1,44 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_NotAvailable extends Pluf_HTTP_Response
{
function __construct($request)
{
$content = '';
try {
$context = new Pluf_Template_Context(array('query' => $request->query));
$tmpl = new Pluf_Template('503.html');
$content = $tmpl->render($context);
$mimetype = null;
} catch (Exception $e) {
$mimetype = 'text/plain';
$content = sprintf('The requested URL %s is not available at the moment.'."\n"
.'Please try again later.'."\n\n".'503 - Service Unavailable',
Pluf_esc($request->query));
}
parent::__construct($content, $mimetype);
$this->status_code = 503;
$this->headers['Retry-After'] = 300; // retry after 5 minutes
}
}

View File

@@ -0,0 +1,43 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_NotFound extends Pluf_HTTP_Response
{
function __construct($request)
{
$content = '';
try {
$context = new Pluf_Template_Context(array('query' => $request->query));
$tmpl = new Pluf_Template('404.html');
$content = $tmpl->render($context);
$mimetype = null;
} catch (Exception $e) {
$mimetype = 'text/plain';
$content = sprintf('The requested URL %s was not found on this server.'."\n"
.'Please check the URL and try again.'."\n\n".'404 - Not Found',
Pluf_esc($request->query));
}
parent::__construct($content, $mimetype);
$this->status_code = 404;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_Redirect extends Pluf_HTTP_Response
{
/**
* Redirect response to a given URL.
*
* @param string URL
* @paran int Redirect code (302) or 301 for permanent
*/
function __construct($url, $code=302)
{
$content = sprintf(__('<a href="%s">Please, click here to be redirected</a>.'), $url);
parent::__construct($content);
$this->headers['Location'] = $url;
$this->status_code = $code;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Can be used as a response to return when a user must be logged to
* access a page.
*/
class Pluf_HTTP_Response_RedirectToLogin extends Pluf_HTTP_Response
{
/**
* The $request object is used to know what the post login
* redirect url should be.
*
* If the action url of the login page is not set, it will try to
* get the url from the login view from the 'login_view'
* configuration key.
*
* @param Pluf_HTTP_Request The request object of the current page.
* @param string The full url of the login page (null)
*/
function __construct($request, $loginurl=null)
{
if ($loginurl !== null) {
$murl = new Pluf_HTTP_URL();
$url = $murl->generate($loginurl, array('_redirect_after' => $request->uri), false);
$encoded = $murl->generate($loginurl, array('_redirect_after' => $request->uri));
} else {
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
$url = Pluf_HTTP_URL_urlForView(Pluf::f('login_view', 'login_view'),
array(),
array('_redirect_after' => $request->uri), false);
$encoded = Pluf_HTTP_URL_urlForView(Pluf::f('login_view', 'login_view'),
array(),
array('_redirect_after' => $request->uri));
}
$content = sprintf(__('<a href="%s">Please, click here to be redirected</a>.'), $encoded);
parent::__construct($content);
$this->headers['Location'] = $url;
$this->status_code = 302;
}
}

View File

@@ -0,0 +1,171 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_ServerError extends Pluf_HTTP_Response
{
function __construct($exception, $mimetype=null)
{
$content = '';
$admins = Pluf::f('admins', array());
if (count($admins) > 0) {
// Get a nice stack trace and send it by emails.
$stack = Pluf_HTTP_Response_ServerError_Pretty($exception);
$subject = $exception->getMessage();
$subject = substr(strip_tags(nl2br($subject)), 0, 50).'...';
foreach ($admins as $admin) {
$email = new Pluf_Mail($admin[1], $admin[1], $subject);
$email->addTextMessage($stack);
$email->sendMail();
}
}
try {
$context = new Pluf_Template_Context(array('message' => $exception->getMessage()));
$tmpl = new Pluf_Template('500.html');
$content = $tmpl->render($context);
$mimetype = null;
} catch (Exception $e) {
$mimetype = 'text/plain';
$content = 'The server encountered an unexpected condition which prevented it from fulfilling your request.'."\n\n"
.'An email has been sent to the administrators, we will correct this error as soon as possible. Thank you for your comprehension.'
."\n\n".'500 - Internal Server Error';
}
parent::__construct($content, $mimetype);
$this->status_code = 500;
}
}
function Pluf_HTTP_Response_ServerError_Pretty($e)
{
$sub = create_function('$f','$loc="";if(isset($f["class"])){
$loc.=$f["class"].$f["type"];}
if(isset($f["function"])){$loc.=$f["function"];}
return $loc;');
$parms = create_function('$f','$params=array();if(isset($f["function"])){
try{if(isset($f["class"])){
$r=new ReflectionMethod($f["class"]."::".$f["function"]);}
else{$r=new ReflectionFunction($f["function"]);}
return $r->getParameters();}catch(Exception $e){}}
return $params;');
$src2lines = create_function('$file','$src=nl2br(highlight_file($file,TRUE));
return explode("<br />",$src);');
$clean = create_function('$line','return html_entity_decode(str_replace("&nbsp;", " ", $line));');
$desc = get_class($e)." making ".$_SERVER['REQUEST_METHOD']." request to ".$_SERVER['REQUEST_URI'];
$out = $desc."\n";
if ($e->getCode()) {
$out .= $e->getCode(). ' : ';
}
$out .= $e->getMessage()."\n\n";
$out .= 'PHP: '.$e->getFile().', line '.$e->getLine()."\n";
$out .= 'URI: '.$_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI']."\n\n";
$out .= '** Stacktrace **'."\n\n";
$frames = $e->getTrace();
foreach ($frames as $frame_id=>$frame) {
if (!isset($frame['file'])) {
$frame['file'] = 'No File';
$frame['line'] = '0';
}
$out .= '* '.$sub($frame).'
['.$frame['file'].', line '.$frame['line'].'] *'."\n";
if (is_readable($frame['file']) ) {
$out .= '* Src *'."\n";
$lines = $src2lines($frame['file']);
$start = $frame['line'] < 5 ?
0 : $frame['line'] -5; $end = $start + 10;
$out2 = '';
$i = 0;
foreach ( $lines as $k => $line ) {
if ( $k > $end ) { break; }
$line = trim(strip_tags($line));
if ( $k < $start && isset($frames[$frame_id+1]["function"])
&& preg_match('/function( )*'.preg_quote($frames[$frame_id+1]["function"]).'/',
$line) ) {
$start = $k;
}
if ( $k >= $start ) {
if ( $k != $frame['line'] ) {
$out2 .= ($start+$i).': '.$clean($line)."\n";
} else {
$out2 .= '>> '.($start+$i).': '.$clean($line)."\n";
}
$i++;
}
}
$out .= $out2;
} else {
$out .= 'No src available.';
}
$out .= "\n";
}
$out .= "\n\n\n\n";
$out .= '** Request **'."\n\n";
if ( function_exists('apache_request_headers') ) {
$out .= '* Request (raw) *'."\n\n";
$req_headers = apache_request_headers();
$out .= 'HEADERS'."\n";
if ( count($req_headers) > 0 ) {
foreach ($req_headers as $req_h_name => $req_h_val) {
$out .= $req_h_name.': '.$req_h_val."\n";
}
$out .= "\n";
} else {
$out .= 'No headers.'."\n";
}
$req_body = file_get_contents('php://input');
if ( strlen( $req_body ) > 0 ) {
$out .= 'Body'."\n";
$out .= $req_body."\n";
}
}
$out .= "\n".'* Request (parsed) *'."\n\n";
$superglobals = array('$_GET','$_POST','$_COOKIE','$_SERVER','$_ENV');
foreach ( $superglobals as $sglobal ) {
$sfn = create_function('','return '.$sglobal.';');
$out .= $sglobal."\n";
if ( count($sfn()) > 0 ) {
foreach ( $sfn() as $k => $v ) {
$out .= 'Variable: '.$k."\n";
$out .= 'Value: '.print_r($v,TRUE)."\n";
}
$out .= "\n";
} else {
$out .= 'No data'."\n\n";
}
}
if ( function_exists('headers_list') ) {
$out .= "\n\n\n\n";
$out .= '** Response **'."\n\n";
$out .= '* Headers *'."\n\n";
$resp_headers = headers_list();
if (count($resp_headers) > 0) {
foreach ( $resp_headers as $resp_h ) {
$out .= $resp_h."\n";
}
$out .= "\n";
} else {
$out .= 'No headers.'."\n";
}
}
return $out;
}

View File

@@ -0,0 +1,376 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
class Pluf_HTTP_Response_ServerErrorDebug extends Pluf_HTTP_Response
{
/**
* Debug version of a server error.
*
* @param Exception The exception being raised.
* @param string Mime type
*/
function __construct($e, $mimetype=null)
{
$this->status_code = 500;
$this->content = Pluf_HTTP_Response_ServerErrorDebug_Pretty($e);
}
}
/**
* @credits http://www.sitepoint.com/blogs/2006/04/04/pretty-blue-screen/
*/
function Pluf_HTTP_Response_ServerErrorDebug_Pretty($e)
{
$o = create_function('$in','return htmlspecialchars($in);');
$sub = create_function('$f','$loc="";if(isset($f["class"])){
$loc.=$f["class"].$f["type"];}
if(isset($f["function"])){$loc.=$f["function"];}
if(!empty($loc)){$loc=htmlspecialchars($loc);
$loc="<strong>$loc</strong>";}return $loc;');
$parms = create_function('$f','$params=array();if(isset($f["function"])){
try{if(isset($f["class"])){
$r=new ReflectionMethod($f["class"]."::".$f["function"]);}
else{$r=new ReflectionFunction($f["function"]);}
return $r->getParameters();}catch(Exception $e){}}
return $params;');
$src2lines = create_function('$file','$src=nl2br(highlight_file($file,TRUE));
return explode("<br />",$src);');
$clean = create_function('$line','return trim(strip_tags($line));');
$desc = get_class($e)." making ".$_SERVER['REQUEST_METHOD']." request to ".
$_SERVER['REQUEST_URI'];
$out = '
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="robots" content="NONE,NOARCHIVE" />
<title>'.$o($desc).'</title>
<style type="text/css">
html * { padding:0; margin:0; }
body * { padding:10px 20px; }
body * * { padding:0; }
body { font:small sans-serif; background: #70DBFF; }
body>div { border-bottom:1px solid #ddd; }
h1 { font-weight:normal; }
h2 { margin-bottom:.8em; }
h2 span { font-size:80%; color:#666; font-weight:normal; }
h2 a { text-decoration:none; }
h3 { margin:1em 0 .5em 0; }
h4 { margin:0.5em 0 .5em 0; font-weight: normal; font-style: italic; }
table {
border:1px solid #ccc; border-collapse: collapse; background:white; }
tbody td, tbody th { vertical-align:top; padding:2px 3px; }
thead th {
padding:1px 6px 1px 3px; background:#70FF94; text-align:left;
font-weight:bold; font-size:11px; border:1px solid #ddd; }
tbody th { text-align:right; color:#666; padding-right:.5em; }
table.vars { margin:5px 0 2px 40px; }
table.vars td, table.req td { font-family:monospace; }
table td { background: #70FFDB; }
table td.code { width:95%;}
table td.code div { overflow:hidden; }
table.source th { color:#666; }
table.source td {
font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
ul.traceback { list-style-type:none; }
ul.traceback li.frame { margin-bottom:1em; }
div.context { margin:5px 0 2px 40px; background-color:#70FFDB; }
div.context ol {
padding-left:30px; margin:0 10px; list-style-position: inside; }
div.context ol li {
font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
div.context li.current-line { color:black; background-color:#70FF94; }
div.commands { margin-left: 40px; }
div.commands a { color:black; text-decoration:none; }
p.headers { background: #70FFDB; font-family:monospace; }
#summary { background: #00B8F5; }
#summary h2 { font-weight: normal; color: #666; }
#traceback { background:#eee; }
#request { background:#f6f6f6; }
#response { background:#eee; }
#summary table { border:none; background:#00B8F5; }
#summary td { background:#00B8F5; }
.switch { text-decoration: none; }
.whitemsg { background:white; color:black;}
</style>
<script type="text/javascript">
//<!--
function getElementsByClassName(oElm, strTagName, strClassName){
// Written by Jonathan Snook, http://www.snook.ca/jon;
// Add-ons by Robert Nyman, http://www.robertnyman.com
var arrElements = (strTagName == "*" && document.all)? document.all :
oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
strClassName = strClassName.replace(/\-/g, "\\-");
var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
var oElement;
for(var i=0; i<arrElements.length; i++){
oElement = arrElements[i];
if(oRegExp.test(oElement.className)){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
}
function hideAll(elems) {
for (var e = 0; e < elems.length; e++) {
elems[e].style.display = \'none\';
}
}
function toggle() {
for (var i = 0; i < arguments.length; i++) {
var e = document.getElementById(arguments[i]);
if (e) {
e.style.display = e.style.display == \'none\' ? \'block\' : \'none\';
}
}
return false;
}
function varToggle(link, id, prefix) {
toggle(prefix + id);
var s = link.getElementsByTagName(\'span\')[0];
var uarr = String.fromCharCode(0x25b6);
var darr = String.fromCharCode(0x25bc);
s.innerHTML = s.innerHTML == uarr ? darr : uarr;
return false;
}
function sectionToggle(span, section) {
toggle(section);
var span = document.getElementById(span);
var uarr = String.fromCharCode(0x25b6);
var darr = String.fromCharCode(0x25bc);
span.innerHTML = span.innerHTML == uarr ? darr : uarr;
return false;
}
window.onload = function() {
hideAll(getElementsByClassName(document, \'table\', \'vars\'));
hideAll(getElementsByClassName(document, \'div\', \'context\'));
hideAll(getElementsByClassName(document, \'ul\', \'traceback\'));
hideAll(getElementsByClassName(document, \'div\', \'section\'));
}
//-->
</script>
</head>
<body>
<div id="summary">
<h1>'.$o($desc).'</h1>
<h2>';
if ($e->getCode()) {
$out .= $o($e->getCode()). ' : ';
}
$out .= ' '.$o($e->getMessage()).'</h2>
<table>
<tr>
<th>PHP</th>
<td>'.$o($e->getFile()).', line '.$o($e->getLine()).'</td>
</tr>
<tr>
<th>URI</th>
<td>'.$o($_SERVER['REQUEST_METHOD'].' '.
$_SERVER['REQUEST_URI']).'</td>
</tr>
</table>
</div>
<div id="traceback">
<h2>Stacktrace
<a href=\'#\' onclick="return sectionToggle(\'tb_switch\',\'tb_list\')">
<span id="tb_switch">▶</span></a></h2>
<ul id="tb_list" class="traceback">';
$frames = $e->getTrace();
foreach ($frames as $frame_id=>$frame) {
if (!isset($frame['file'])) {
$frame['file'] = 'No File';
$frame['line'] = '0';
}
$out .= '<li class="frame">'.$sub($frame).'
['.$o($frame['file']).', line '.$o($frame['line']).']';
if (isset($frame['args']) && count($frame['args']) > 0) {
$params = $parms($frame);
$out .= '
<div class="commands">
<a href=\'#\' onclick="return varToggle(this, \''.
$o($frame_id).'\',\'v\')"><span>▶</span> Args</a>
</div>
<table class="vars" id="v'.$o($frame_id).'">
<thead>
<tr>
<th>Arg</th>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>';
foreach ($frame['args'] as $k => $v) {
$name = (isset($params[$k]) and isset($params[$k]->name)) ? '$'.$params[$k]->name : '?';
$out .= '
<tr>
<td>'.$o($k).'</td>
<td>'.$o($name).'</td>
<td class="code">
<pre>'.Pluf_esc(print_r($v, true)).'</pre>
</td>
</tr>';
}
$out .= '</tbody></table>';
}
if (is_readable($frame['file']) ) {
$out .= '
<div class="commands">
<a href=\'#\' onclick="return varToggle(this, \''
.$o($frame_id).'\',\'c\')"><span>▶</span> Src</a>
</div>
<div class="context" id="c'.$o($frame_id).'">';
$lines = $src2lines($frame['file']);
$start = $frame['line'] < 5 ?
0 : $frame['line'] -5; $end = $start + 10;
$out2 = '';
foreach ( $lines as $k => $line ) {
if ( $k > $end ) { break; }
$line = trim(strip_tags($line));
if ( $k < $start && isset($frames[$frame_id+1]["function"])
&& preg_match('/function( )*'.preg_quote($frames[$frame_id+1]["function"]).'/',
$line) ) {
$start = $k;
}
if ( $k >= $start ) {
if ( $k != $frame['line'] ) {
$out2 .= '<li><code>'.$clean($line).'</code></li>'."\n"; }
else {
$out2 .= '<li class="current-line"><code>'.
$clean($line).'</code></li>'."\n"; }
}
}
$out .= "<ol start=\"$start\">\n".$out2. "</ol>\n";
$out .= '</div>';
} else {
$out .= '<div class="commands">No src available</div>';
}
$out .= '</li>';
} // End of foreach $frames
$out .= '
</ul>
</div>
<div id="request">
<h2>Request
<a href=\'#\' onclick="return sectionToggle(\'req_switch\',\'req_list\')">
<span id="req_switch">▶</span></a></h2>
<div id="req_list" class="section">';
if ( function_exists('apache_request_headers') ) {
$out .= '<h3>Request <span>(raw)</span></h3>';
$req_headers = apache_request_headers();
$out .= '<h4>HEADERS</h4>';
if ( count($req_headers) > 0 ) {
$out .= '<p class="headers">';
foreach ($req_headers as $req_h_name => $req_h_val) {
$out .= $o($req_h_name.': '.$req_h_val);
$out .= '<br>';
}
$out .= '</p>';
} else {
$out .= '<p>No headers.</p>';
}
$req_body = file_get_contents('php://input');
if ( strlen( $req_body ) > 0 ) {
$out .='
<h4>Body</h4>
<p class="req" style="padding-bottom: 2em"><code>
'.$o($req_body).'
</code></p>';
}
}
$out .= '
<h3>Request <span>(parsed)</span></h3>';
$superglobals = array('$_GET','$_POST','$_COOKIE','$_SERVER','$_ENV');
foreach ( $superglobals as $sglobal ) {
$sfn = create_function('','return '.$sglobal.';');
$out .= '<h4>'.$sglobal.'</h4>';
if ( count($sfn()) > 0 ) {
$out .= '
<table class="req">
<thead>
<tr>
<th>Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody>';
foreach ( $sfn() as $k => $v ) {
$out .= '<tr>
<td>'.$o($k).'</td>
<td class="code">
<div>'.$o(print_r($v,TRUE)).'</div>
</td>
</tr>';
}
$out .= '
</tbody>
</table>';
} else {
$out .= '
<p class="whitemsg">No data</p>';
}
}
$out .= '
</div>
</div>';
if ( function_exists('headers_list') ) {
$out .= '
<div id="response">
<h2>Response
<a href=\'#\' onclick="return sectionToggle(\'resp_switch\',\'resp_list\')">
<span id="resp_switch">▶</span></a></h2>
<div id="resp_list" class="section">
<h3>Headers</h3>';
$resp_headers = headers_list();
if (count($resp_headers) > 0) {
$out .= '
<p class="headers">';
foreach ( $resp_headers as $resp_h ) {
$out .= $o($resp_h);
$out .= '<br>';
}
$out .= ' </p>';
} else {
$out .= '
<p>No headers.</p>';
}
$out .= '
</div>';
}
$out .= '
</body>
</html>
';
return $out;
}

173
pluf/src/Pluf/HTTP/URL.php Normal file
View File

@@ -0,0 +1,173 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Generate a ready to use URL to be used in location/redirect or forms.
*
* When redirecting a user, depending of the format of the url with
* mod_rewrite or not, the parameters must all go in the GET or
* everything but the action. This class provide a convinient way to
* generate those url and parse the results for the dispatcher.
*/
class Pluf_HTTP_URL
{
/**
* Generate the URL.
*
* The & is encoded as &amp; in the url.
*
* @param string Action url
* @param array Associative array of the parameters (array())
* @param bool Encode the & in the url (true)
* @return string Ready to use URL.
*/
public static function generate($action, $params=array(), $encode=true)
{
$url = $action;
if (count($params)) {
$url .= '?' . http_build_query($params, '', ($encode) ? '&amp;' : '&');
}
return $url;
}
/**
* Get the action of the request.
*
* We directly get the PATH_INFO variable or return '/'
*
* @return string Action
*/
public static function getAction()
{
if (isset($_GET['_pluf_action'])) {
return $_GET['_pluf_action'];
}
return (isset($_SERVER['PATH_INFO'])) ?
$_SERVER['PATH_INFO'] : '/';
}
}
/**
* Provide the full URL (without domain) to a view.
*
* @param string View.
* @param array Parameters for the view (array()).
* @param array Extra GET parameters for the view (array()).
* @param bool Should the URL be encoded (true).
* @return string URL.
*/
function Pluf_HTTP_URL_urlForView($view, $params=array(),
$get_params=array(), $encoded=true)
{
return Pluf_HTTP_URL::generate(Pluf_HTTP_URL_reverse($view, $params),
$get_params, $encoded);
}
/**
* Reverse an URL.
*
* @param string View in the form 'class::method' or string of the name.
* @param array Possible parameters for the view (array()).
* @return string URL.
*/
function Pluf_HTTP_URL_reverse($view, $params=array())
{
$model = '';
$method = '';
if (false !== strpos($view, '::')) {
list($model, $method) = explode('::', $view);
}
$vdef = array($model, $method, $view);
$regbase = array('', array());
$regbase = Pluf_HTTP_URL_find($GLOBALS['_PX_views'], $vdef, $regbase);
if ($regbase === false) {
throw new Exception(sprintf('Error, the view: %s has not been found.', $view));
}
$url = '';
foreach ($regbase[1] as $regex) {
$url .= Pluf_HTTP_URL_buildReverseUrl($regex, $params);
}
if (!defined('IN_UNIT_TESTS')) {
$url = $regbase[0].$url;
}
return $url;
}
/**
* Go in the list of views to find the matching one.
*
* @param array Views
* @param array View definition array(model, method, name)
* @param array Regex of the view up to now and base
* @return mixed Regex of the view or false
*/
function Pluf_HTTP_URL_find($views, $vdef, $regbase)
{
foreach ($views as $dview) {
if (isset($dview['sub'])) {
$regbase2 = $regbase;
if (empty($regbase2[0])) {
$regbase2[0] = $dview['base'];
}
$regbase2[1][] = $dview['regex'];
$res = Pluf_HTTP_URL_find($dview['sub'], $vdef, $regbase2);
if ($res) {
return $res;
}
continue;
}
if (
(isset($dview['name']) && $dview['name'] == $vdef[2])
or
($dview['model'] == $vdef[0] && $dview['method'] == $vdef[1])
) {
$regbase[1][] = $dview['regex'];
if (!empty($dview['base'])) {
$regbase[0] = $dview['base'];
}
return $regbase;
}
}
return false;
}
/**
* Build the reverse URL without the path base.
*
* Credits to Django, again...
*
* @param string Regex for the URL.
* @param array Parameters
* @return string URL filled with the parameters.
*/
function Pluf_HTTP_URL_buildReverseUrl($url_regex, $params=array())
{
$url = str_replace(array('\\.', '\\-'), array('.', '-'), $url_regex);
if (count($params)) {
$groups = array_fill(0, count($params), '#\(([^)]+)\)#');
$url = preg_replace($groups, $params, $url, 1);
}
preg_match('/^#\^?([^#\$]+)/', $url, $matches);
return $matches[1];
}

104
pluf/src/Pluf/Image.php Normal file
View File

@@ -0,0 +1,104 @@
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of Plume Framework, a simple PHP Application Framework.
# Copyright (C) 2001-2007 Loic d'Anterroches and contributors.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
/**
* Image object to wrap some simple convertion operations.
*
* Complex operations should be performed with the gd functions directly.
*
*/
class Pluf_Image
{
protected $dir = ''; /**< Path to the thumbnail folder. */
protected $filename = ''; /**< Filename of the last created thumbnail. */
public $source = ''; /**< Full path to the source file. */
/**
* Init the image class.
*/
public function __construct($source)
{
$this->source = $source;
}
/**
* Convert the image as a png file.
*
* @param string Output file.
*/
public function asPng($output)
{
$this->saveAs($output, 'png');
}
/**
* Convert the image as a given type.
*
* Types are 'gif', 'jpg' or 'png'
*
* @param string Output file.
* @param string Type.
*/
public function saveAs($output, $type='png')
{
$types = array('gif' => '1',
'jpg' => '2',
'png' => '3');
$output_func = array('gif' => 'imagegif',
'jpg' => 'imagejpeg',
'png' => 'imagepng');
if (!file_exists($this->source)) {
throw new Exception(sprintf('Image source "%s" unavailable.',
$this->source));
}
if (($size = @getimagesize($this->source)) === false) {
throw new Exception(sprintf('Image source "%s" is not an image.',
$this->source));
}
$source_type = $size[2];
if ($source_type == $types[$type]) {
// Simply the source to the output.
if (false === @copy($this->source, $output)) {
throw new Exception(sprintf('Failed to copy %s to %s.',
$this->source, $output));
}
return;
}
if ($source_type == '1') {
$function = 'imagecreatefromgif';
} elseif ($source_type == '2') {
$function = 'imagecreatefromjpeg';
} elseif ($source_type == '3') {
$function = 'imagecreatefrompng';
} else {
throw new Exception('The source image is not of a recognized type.');
}
if (($img = @$function($this->source)) == false) {
throw new Exception('Cannot read the source image.');
}
if (!@$output_func[$type]($img, $output)) {
throw new Exception('Cannot write the output image.');
}
}
}

Some files were not shown because too many files have changed in this diff Show More