Compare commits

...

179 Commits

Author SHA1 Message Date
Sven Slootweg 87a0cadb18 starts_with, notice backtraces, better database error reporting and return values 9 years ago
Sven Slootweg 37b404c2dd Make random_string cryptographically secure by default 9 years ago
Sven Slootweg 4a97d7b0ee Correctly return HTTP 500 on uncaught exception pages, and also display tracebacks for nested exceptions. 9 years ago
Sven Slootweg 7076e8d0fa Fixes for CSRF protection and FormHandler (including calling CSRF validation in FormHandler by default), Switch_/Case_ statements for FormHandler, custom FormHandler error messages for standard validators 9 years ago
Sven Slootweg 4ffa38e442 Add custom error message map functionality to form handler 9 years ago
Sven Slootweg c0b077dc9f Templater and form handler updates 9 years ago
Sven Slootweg 2db9f1bb7f Slight change in GetGroupedValues API 10 years ago
Sven Slootweg a6c87d62a5 WTF? 10 years ago
Sven Slootweg 7c87c4716e Add regex validator 10 years ago
Sven Slootweg 996054f69f Error handling and a bunch of validators 10 years ago
Sven Slootweg 24e018330c Implement AbortIfErrors statement for form validator 10 years ago
Sven Slootweg fc318180f7 Bugfix 10 years ago
Sven Slootweg 5c6445a023 Fix bug in operators 10 years ago
Sven Slootweg 57b11d4c58 I must be crazy. Reimplemented the whole thing with promises. 10 years ago
Sven Slootweg 081b8b6ec8 First bits of FormHandler 10 years ago
Sven Slootweg 35fcf51b53 Fixed a stupid comparison bug 10 years ago
Sven Slootweg 4423ff7a22 Merge branch 'bugfix/float-casting' into feature/orm-uuid 10 years ago
Sven Slootweg 1eb1427de4 Fix float casting bug 10 years ago
Sven Slootweg 7b3e986f65 Merge branch 'bugfix/int-overflow' into feature/orm-uuid 10 years ago
Sven Slootweg 4eacdbf612 Merge branch 'bugfix/int-overflow' into develop 10 years ago
Sven Slootweg 4e45466d9e Patch for integer overflow when auto-casting in a PDO query. 10 years ago
Sven Slootweg 898506fb0b Fix bug with UUIDs... 10 years ago
Sven Slootweg ea88a51e66 Also insert the Id when using UUIDs or other pre-specified IDs for new rows 10 years ago
Sven Slootweg 7cdb3507af Change ID handling, in preparation of UUID support 10 years ago
Sven Slootweg eaadadded0 Also use PDO parameterization for the row ID in UPDATE queries 10 years ago
Sven Slootweg 138bf9949e Update some comments and deprecation info 10 years ago
Sven Slootweg 6822c353c3 Add a 'forced' option to InsertIntoDatabase, to pre-fill all data instead of lazy-loading 10 years ago
Sven Slootweg 161dd60fd7 Be quiet about memcache connection failures 10 years ago
Sven Slootweg f6d92110dd Store a normalized version of the request method in the router object for external access 10 years ago
Sven Slootweg 03cf41519f Allow preset form values to be specified outside of the POST data. 10 years ago
Sven Slootweg c8566e4822 Properly handle errors during reading of configuration, and suppress PHP notices. 10 years ago
Sven Slootweg c7c2e252b9 Why was there even a limit on the amount of CSRF token insertions? 10 years ago
Sven Slootweg ce13fa4f29 Proper error reporting for database queries 10 years ago
Sven Slootweg ca82a9e0c8 Add basic autoloader 10 years ago
Sven Slootweg 6bfe6ccb4d Allow omission of the '0' when creating a blank object from a CPHP class. 10 years ago
Sven Slootweg c2ea87c4af Fix a notice 10 years ago
Sven Slootweg 68964d3022 Properly include database query error messages 10 years ago
Sven Slootweg bded80405e Add support for (cached) HTMLPurifier 10 years ago
Sven Slootweg 5f343edfcd Check strpos result explicitly, whoops 10 years ago
Sven Slootweg 238195c19a Add a patch for lighttpds strange behaviour on server.error-handler-404 routing. 10 years ago
Sven Slootweg 9ec934e8c7 The magic quotes undo should apply to GET variables as well. 10 years ago
Sven Slootweg 21f3cea18f Merge branch 'master' of git.cryto.net:projects/joepie91/cphp 10 years ago
Sven Slootweg a90ffa590d Throw a DatabaseException when an object is specified as a query parameter. 10 years ago
Sven Slootweg 58cfffd3d8 Throw a templater exception when a template attempts to access a non-existent key in a collection. 10 years ago
Sven Slootweg d42eecad3d Swap the class and procedural code in the PDO include, to avoid breakage 10 years ago
Sven Slootweg 539f54eac1 Resolve another notice 10 years ago
Sven Slootweg dbe5662a85 Resolve a bunch of notices and E_STRICT warnings 10 years ago
Sven Slootweg ca171e8275 Add HTTP 422 status code 10 years ago
Sven Slootweg 4b02357739 Include an error message in the exception when a database query fails. 10 years ago
Sven Slootweg bfadf150b4 Fix insertion of simplehtml, html, and nl2br data types 10 years ago
Sven Slootweg 2680c4538c Add support for restricting routes to specific methods 10 years ago
Sven Slootweg a80368e7c2 Only check the last JSON error if the function for it exists 10 years ago
Sven Slootweg 113404d563 Remove old mysql_ cache purging code, fix type inconsistency bug in cache purging, and fix a bug in the debugger (oh, the irony) 10 years ago
Sven Slootweg 3fbfad8656 Bypass cache on data reload, and fix a bug where a difference between column name and variable name would cause the clearing of old data in an object to fail 10 years ago
Sven Slootweg 7db7d5a60a Make CPHP deal properly with non-integer numeric values 10 years ago
Sven Slootweg 4aa82d0a86 Remove all mysql_ functionality and make insertion/updating use PDO instead. 10 years ago
Sven Slootweg da6ed16c34 Add TODO 10 years ago
Sven Slootweg 5729adac81 Add todo item 10 years ago
Sven Slootweg d2b511d9b3 Also add 'id' parameter override support for <select> elements 10 years ago
Sven Slootweg 85371b3394 Support NULL values for non-string database fields 10 years ago
Sven Slootweg 6e923629e0 Resolve conflicting variable name with 'value' parameter for input elements, and add support for 'id' parameter overrides 10 years ago
Sven Slootweg 249284e488 Always return an array from CreateFromQuery unless specifically the first result is requested 11 years ago
Sven Slootweg 4efacc178b Add a function for returning HTTP status code headers 11 years ago
Sven Slootweg 9aac04d33e Make the CreateFromQuery function return an array of results or one result if explicitly defined 11 years ago
Sven Slootweg 55de2ba21c Actually use the current class instead of the base class 11 years ago
Sven Slootweg ee8c40ebe1 Add function to spawn a new object from a custom query 11 years ago
Sven Slootweg 8e75ee9ee7 Add function to set a global templater variable 11 years ago
Sven Slootweg 75a5f0b7e7 Skip memcache retrieval if the expiry time is defined as 0 (after all, we clearly don't want stale data) 11 years ago
Sven Slootweg f54722d1a7 Get rid of magic_quotes nonsense 11 years ago
Sven Slootweg 52497d05b4 Implement variable hooks 11 years ago
Sven Slootweg c7ee85eab1 Fix nested subconstruct bugs and implement more debugging 11 years ago
Sven Slootweg 442a180f1e Implement a step-by-step debugger 11 years ago
Sven Slootweg a56c06a76e Fix parsing bug for constructs with subconstructs 11 years ago
Sven Slootweg 9d85fb8bc9 Make the CachedQuery function throw an exception when a query fails, instead of just returning null 11 years ago
Sven Slootweg 061516281a Implement select and option elements 11 years ago
Sven Slootweg 38112ba6e3 Fix bug with broken variable 11 years ago
Sven Slootweg aa6bb1fc85 Fix bug in fetching stand-alone variables and handle input values properly. 11 years ago
Sven Slootweg a55ce3778d Match all input element properties and properly deal with type attributes 11 years ago
Sven Slootweg fa8aa24e1b The form builder is retired :) 11 years ago
Sven Slootweg 29ea38ebc9 Remove excessive whitespace 11 years ago
Sven Slootweg db4d084163 Get rid of some stuff we don't need anymore 11 years ago
Sven Slootweg 5212ae353e Include field name in generated input elements 11 years ago
Sven Slootweg 3bf5d768cb Rewrite templater to support elseif/else constructs, input element generator, and extensible syntax. Also removed deprecated legacy code. 11 years ago
Sven Slootweg 533148edb1 Throw a RouterException if no suitable route was found 11 years ago
Sven Slootweg c62d6a9cec Deprecate the Export function 11 years ago
Sven Slootweg cb050ebdca Make code parameter optional when creating a new TemplateException 11 years ago
Sven Slootweg 46ea50e6b0 Store the authentication status internally in the router so that it can be used outside the included file 11 years ago
Sven Slootweg 9d08020a8d Use the new template parser for the errorhandler component 11 years ago
Sven Slootweg 4c6f46efe6 Also support global template variables in the new template parser 11 years ago
Sven Slootweg 18cd2f8066 Fix some PDO implementation stuff 11 years ago
Sven Slootweg 5417ccd5f6 Add a 'replace last occurrence' function 11 years ago
Sven Slootweg 95f9d81288 Fix parsing bug where characters after an opening curly brace were omitted in the output. 11 years ago
Sven Slootweg 7b4b4231db Make the PDO object cast nulls to empty strings to work around PHP retardedness 11 years ago
Sven Slootweg f14f916017 Fix mysql_ PDO wrapper 11 years ago
Sven Slootweg d80a4e487b Add redirect and ceil_precision functions 11 years ago
Sven Slootweg c59aad3be6 Fix horribly broken implementation of the PDO mysql_ abstraction - this REALLY needs to be done properly. 11 years ago
Sven Slootweg 224769ebb4 Fix yet another bug 11 years ago
Sven Slootweg d3d094a474 Fix bug in PDO mysql_ abstraction 11 years ago
Sven Slootweg 98f2145938 Fix a bug that would make database insertion break when using PDO 11 years ago
Sven Slootweg abb0712c97 Add no-expiry option to cached query functions, and fix cache invalidation bug 11 years ago
Sven Slootweg 4385243b9c Remove old config files, implement PDO shim, and implement better time handling 11 years ago
Sven Slootweg 4bbeffbd57 Create a new stdClass object before assigning properties 11 years ago
Sven Slootweg cc25349d30 Implement PDO in object retrieval 11 years ago
Sven Slootweg c53ffd9afb Make the CachedQuery function return null or false when an error condition occurs 11 years ago
Sven Slootweg d6ddb80b04 Make parameters optional and implement PDO properly 11 years ago
Sven Slootweg b3218ed1c3 Fix bug where class map in configuration is not recognized due to variable scope 11 years ago
Sven Slootweg 0dd070a809 Only retrieve query results as an associative array, omitting the numeric index 11 years ago
Sven Slootweg 1f45289ea3 Implement cacheable PDO object 11 years ago
Sven Slootweg c6b00de70b Fix localization code to actually use the parsed configuration file instead of relying on hardcoded configuration variables 11 years ago
Sven Slootweg 81fd2500ea Check if the strings array is actually a valid array before attempting to use it. 11 years ago
Sven Slootweg 63bb67a108 Also include locale handling code 11 years ago
Sven Slootweg 855d39c038 Fix spacing on timezone list 11 years ago
Sven Slootweg 52b6216054 Use a configuration parser instead of hardcoded configuration variables 11 years ago
Sven Slootweg 2e5590ddeb Add CSRF protection mechanism 11 years ago
Sven Slootweg 1a07c64d17 Remove PHP closing tags 11 years ago
Sven Slootweg 956933fe9b Add ends_with function 11 years ago
Sven Slootweg 2a629d63d3 Return null on query errors, instead of false 11 years ago
Sven Slootweg 6dbbfb4ebd Add correct null handling to templater 11 years ago
Sven Slootweg 5a3bacf2e7 Make the pagination function more compact, using less temporary variables. 11 years ago
Sven Slootweg a5f2e14a6d Add pagination calculation function. 11 years ago
Sven Slootweg 8a46f5d630 Make database insertion play nice with autoloading. 11 years ago
Sven Slootweg 4caf68e6ff Properly refresh data when using autoloading by unsetting all internal variables. 11 years ago
Sven Slootweg d3c970a551 Implement autoloading 11 years ago
Sven Slootweg a8937630e3 Set proper default for 'none' field type 11 years ago
Sven Slootweg c0a40b2bd4 Set proper defaults for html and nl2br field types 11 years ago
Sven Slootweg 110ba159d2 Implement isempty operation 11 years ago
Sven Slootweg ecb95ca151 Implement isset operation in template If statements 11 years ago
Sven Slootweg 7034837966 Throw proper exceptions if a variable in a template cannot be found. 11 years ago
Sven Slootweg 890296f25e Add fix_utf8 function. 11 years ago
Sven Slootweg bc68bf8969 We shouldn't be pretty_dump()ing the query in production code 11 years ago
Sven Slootweg a1efe9b400 Throw an exception when the class prototype does not match the database schema. 11 years ago
Sven Slootweg ca9808f9e2 Also default to null when no defaultable array is specified, for the ConstructDataset function 11 years ago
Sven Slootweg 67c2b55ab6 Fix some stray spaces 11 years ago
Sven Slootweg 7a933cd60d Fix years calculation and use properties instead of formatting function for time difference calculation. 11 years ago
Sven Slootweg bd3db37ea5 Set a property to its default value if the field is defaultable and the referenced object cannot be found in the database. 11 years ago
Sven Slootweg d27086aca7 Only check the defaultable array if it is, in fact, an array. 11 years ago
Sven Slootweg 56b741bbee If we don't define unsafe default values, database insertion will probably break. 11 years ago
Sven Slootweg 7b625f6965 Only throw a NotFoundException during recursive retrieval if the problematic field is not defaultable 11 years ago
Sven Slootweg 641a5fe43e Remove ownership checks - this belongs in application code, not in a framework. 11 years ago
Sven Slootweg 8b437c6a4b Include the field on which retrieval from database failed when throwing a NotFoundException in a recursive retrieval. 11 years ago
Sven Slootweg 42bdba7ce0 Remove old cut_text function 11 years ago
Sven Slootweg 589dbae474 Replace cut_text with own regex-based version 11 years ago
Sven Slootweg 4245c1f206 Add cut_text option 11 years ago
Sven Slootweg b87ee4671b Set default values for blank objects 11 years ago
Sven Slootweg 7c230224f9 Add time_ago function for generating a textual representation of time difference. 11 years ago
Sven Slootweg 62064095ad Oops, I broke something 11 years ago
Sven Slootweg 69c4c67927 Fixed memcache variable name to prevent conflicts 11 years ago
Sven Slootweg 56001c5b95 Add simple RSS parser 11 years ago
Sven Slootweg fe096eac5c Only send out Unicode headers if the current document is HTML, as indicated by a switch 11 years ago
Sven Slootweg f42d47d454 Unicode, damnit\! 11 years ago
Sven Slootweg d749e53352 Deprecate a few legacy functions. 11 years ago
Sven Slootweg e9c46d4182 Add HTML tag and attribute stripping.\nAdd HTML filtering options. 11 years ago
Sven Slootweg e864e912d0 Properly handle the allow_slash parameter for regexes that have one or more end-of-string characters. 11 years ago
Sven Slootweg f4f15d9cd1 Save request path in Router object 11 years ago
Sven Slootweg 35aad80cdc We don't need that there 11 years ago
Sven Slootweg 5842bf2b72 Bugfix to make uParameters properly available when routing a request 11 years ago
Sven Slootweg 44196de152 Bugfix for incorrect handling of boolean values in FetchVariable function 11 years ago
Sven Slootweg d990ffaed4 Add hex/RGB conversion functions 11 years ago
Sven Slootweg 63702fc9db Removed obsolete type 11 years ago
Sven Slootweg 98d7e64771 Give locales a name field that specifies the original defined locale name 11 years ago
Sven Slootweg 2b91a34206 Move templater constants outside the Templater class 11 years ago
Sven Slootweg d36d283b7b Use uVariables instead of sVariables for unfiltered router variables 11 years ago
Sven Slootweg 2d634b14d7 Support configuring of variables for advanced routes 11 years ago
Sven Slootweg c66efa4bae Allow more routing options like authenticators 11 years ago
Sven Slootweg 9b0058d199 Optimize Templater::Localize and add support for new format 11 years ago
Sven Slootweg 597d8d0e56 Clean up Templater code 11 years ago
Sven Slootweg f910045417 Clean up Templater code 11 years ago
Sven Slootweg 70baf0b182 Move tree visualization to debug variable 11 years ago
Sven Slootweg 0e027f73bd Finished variable substitution 11 years ago
Sven Slootweg da9e963602 First steps for variable substitution 11 years ago
Sven Slootweg 93e7510cc5 ForEach/If evaluation done, including data subsets 11 years ago
Sven Slootweg 261ea3b8b4 Add foreach logic 11 years ago
Sven Slootweg 2b575d4f0e Clean up some unneeded parser code 11 years ago
Sven Slootweg d254d77c27 Finish template parsing 11 years ago
Sven Slootweg 1cfd53deb4 Basic template parser 11 years ago
Sven Slootweg 61a435863d Added ignore for non-sample config files 11 years ago
Sven Slootweg 9254b0594b Merged back CPHP updates from CVM and Anontune 11 years ago
Sven Slootweg b40139d102 Removed debugging info 11 years ago
Sven Slootweg 7aee896ebc Added if and foreach statements to Templater 11 years ago
  1. 2
      .gitignore
  2. 263
      base.php
  3. 9
      class.base.php
  4. 566
      class.databaserecord.php
  5. 13
      class.localizer.php
  6. 1331
      class.templater.php
  7. 18
      components/component.errorhandler.php
  8. 319
      components/component.formbuilder.php
  9. 107
      components/component.router.php
  10. 42
      config.sample.php
  11. 33
      include.config.php
  12. 74
      include.csrf.php
  13. 355
      include.datetime.php
  14. 388
      include.debug.php
  15. 59
      include.exceptions.php
  16. 700
      include.forms.php
  17. 99
      include.lib.php
  18. 17
      include.locale.php
  19. 70
      include.memcache.php
  20. 369
      include.misc.php
  21. 156
      include.mysql.php

2
.gitignore

@ -0,0 +1,2 @@
config.php
config.mysql.php

263
base.php

@ -13,7 +13,8 @@
require("include.constants.php");
require("cphp/config.php");
require("include.config.php");
require("include.debug.php");
require("include.dependencies.php");
require("include.exceptions.php");
@ -23,19 +24,271 @@ require("include.misc.php");
require("include.memcache.php");
require("include.mysql.php");
require("include.session.php");
require("include.csrf.php");
require("include.forms.php");
require("include.lib.php");
require("class.templater.php");
require("class.localizer.php");
$locale = new Localizer();
$locale->Load($cphp_locale_name);
require("include.locale.php");
setlocale(LC_ALL, $locale->locale);
if(empty($not_html))
{
header("Content-Type:text/html; charset=UTF-8");
}
require("class.base.php");
require("class.databaserecord.php");
foreach($cphp_components as $component)
foreach($cphp_config->components as $component)
{
require("components/component.{$component}.php");
}
/* lighttpd (and perhaps some other HTTPds) won't pass on GET parameters
* when using the server.error-handler-404 directive that is required to
* use the CPHP router. This patch will try to detect such problems, and
* manually extract the GET data from the request URI. I admit, it's a
* bit of a hack, but there doesn't really seem to be a different way of
* solving this issue. */
/* Detect whether the request URI and the $_GET array disagree on the
* existence of GET parameters. */
if(strpos($_SERVER['REQUEST_URI'], "?") !== false && empty($_GET))
{
/* Separate the protocol/host/path component from the query string. */
list($uri, $query) = explode("?", $_SERVER['REQUEST_URI'], 2);
/* Store the entire query string in the relevant $_SERVER variable -
* lighttpds strange behaviour breaks this variable as well. */
$_SERVER['QUERY_STRING'] = $query;
/* Finally, run the query string through PHPs own internal GET data
* parser, and have it store the result in the $_GET variable. This
* should yield an identical result to a well-functioning HTTPd. */
parse_str($query, $_GET);
}
if(get_magic_quotes_gpc())
{
/* By default, get rid of all quoted variables. Magic quotes are evil. */
foreach($_POST as &$var)
{
$var = stripslashes($var);
}
foreach($_GET as &$var)
{
$var = stripslashes($var);
}
}
if(!empty($cphp_config->autoloader))
{
function cphp_autoload_class($class_name)
{
global $_APP;
$class_name = str_replace("\\", "/", strtolower($class_name));
if(file_exists("classes/{$class_name}.php"))
{
require_once("classes/{$class_name}.php");
}
}
spl_autoload_register('cphp_autoload_class');
}
/* https://stackoverflow.com/a/1159235/1332715 */
set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
if(!(error_reporting() & $errno))
return;
switch($errno) {
case E_WARNING :
case E_USER_WARNING :
case E_STRICT :
case E_NOTICE :
case E_USER_NOTICE :
$type = 'warning';
$fatal = false;
break;
default :
$type = 'fatal error';
$fatal = true;
break;
}
$trace = array_reverse(debug_backtrace());
array_pop($trace);
if(php_sapi_name() == 'cli') {
echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
foreach($trace as $item)
echo ' ' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()' . "\n";
} else {
echo '<p class="error_backtrace">' . "\n";
echo ' Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
echo ' <ol>' . "\n";
foreach($trace as $item)
echo ' <li>' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()</li>' . "\n";
echo ' </ol>' . "\n";
echo '</p>' . "\n";
}
if(ini_get('log_errors')) {
$items = array();
foreach($trace as $item)
$items[] = (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()';
$message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
error_log($message);
}
if($fatal)
exit(1);
});
set_exception_handler(function($e){
/* Intentionally not using the templater here; any inner exceptions
* cause serious debugging issues. Avoiding potential issues by just
* hardcoding the response here, with no code that could raise an
* exception. */
$exception_class = get_class($e);
$exception_message = $e->getMessage();
$exception_file = $e->getFile();
$exception_line = $e->getLine();
$exception_trace = $e->getTraceAsString();
error_log("Uncaught {$exception_class} in {$exception_file}:{$exception_line} ({$exception_message}). Traceback: {$exception_trace}");
switch(strtolower(ini_get('display_errors')))
{
case "1":
case "on":
case "true":
$inner_exceptions = array();
$inner_e = $e;
while(true)
{
$inner_e = $inner_e->getPrevious();
if($inner_e === null)
{
break;
}
else
{
$inner_exceptions[] = array($inner_e->getMessage(), $inner_e->getTraceAsString());
}
}
if(empty($inner_exceptions))
{
$inner_traces = "";
}
else
{
$inner_traces = "<h2>One or more previous exceptions were also recorded.</h2>";
}
foreach($inner_exceptions as $inner_e)
{
$inner_traces .= "
<p>
<span class='message'>{$inner_e[0]}</span>
</p>
<pre>{$inner_e[1]}</pre>
";
}
$error_body = "
<p>
An uncaught <span class='detail'>{$exception_class}</span> was thrown, in <span class='detail'>{$exception_file}</span> on line <span class='detail'>{$exception_line}</span>.
</p>
<p>
<span class='message'>{$exception_message}</span>
</p>
<pre>{$exception_trace}</pre>
{$inner_traces}
<p><strong>Important:</strong> These errors should never be displayed on a production server! Make sure that <em>display_errors</em> is turned off in your PHP configuration, if you want to hide these tracebacks.</p>
";
break;
default:
$error_body = "
<p>
Something went wrong while creating this page, but we're not yet quite sure what it was.
</p>
<p>
If the issue persists, please contact the administrator for this application or website.
</p>
";
break;
}
http_status_code(500);
echo("
<!doctype html>
<html>
<head>
<title>An unexpected error occurred.</title>
<style>
body
{
margin: 24px auto;
padding: 24px 16px;
font-family: sans-serif;
font-size: 18px;
width: 960px;
color: #676767;
}
h1
{
border-bottom: 2px solid black;
color: #444444;
font-size: 26px;
padding-bottom: 6px;
}
h2
{
color: #575757;
border-bottom: 2px solid #444444;
padding-top: 22px;
padding-bottom: 6px;
font-size: 21px;
}
pre
{
overflow: auto;
font-size: 13px;
color: black;
padding: 10px;
border: 1px solid gray;
border-radius: 6px;
background-color: #F8F8F8;
}
.message
{
font-weight: bold;
color: #5B0000;
}
.detail
{
color: black;
}
</style>
</head>
<body>
<h1>An unexpected error occurred.</h1>
{$error_body}
</body>
</html>
");
die();
});

9
class.base.php

@ -19,6 +19,8 @@ class CPHPBaseClass
public function RenderTimeAgo($template, $property)
{
/* DEPRECATED: Please do not use this function if you can avoid it.
* The time_ago function can now be used to accomplish the same. */
global $locale;
$variable_name = "s{$property}";
@ -130,11 +132,18 @@ class CPHPBaseClass
public function RenderTemplateExternal($template, $strings)
{
/* DEPRECATED: Please do not use this function.
* Instead, you can use Templater::AdvancedParse for rendering arbitrary templates
* without instantiating a Templater yourself. */
return $this->DoRenderTemplate($template, $strings);
}
public function DoRenderTemplate($template, $strings)
{
/* DEPRECATED: Please do not use this function.
* Class-specific templater functions have been discontinued. Instead, you can use
* Templater::AdvancedParse for rendering templates without instantiating a Templater
* yourself. */
global $locale;
try

566
class.databaserecord.php

@ -19,54 +19,95 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
public $verify_query = "";
public $table_name = "";
public $query_cache = 60;
public $id_field = "Id";
public $autoloading = true;
public $prototype = array();
public $prototype_render = array();
public $prototype_export = array();
public $uData = array();
public $sIsNewObject = true;
public $sId = 0;
public function __construct($uDataSource, $uCommunityId = 0)
public function __construct($uDataSource = 0, $defaultable = null)
{
$this->ConstructDataset($uDataSource, $uCommunityId);
global $cphp_config;
if(!isset($cphp_config->class_map))
{
die("No class map was specified. Refer to the CPHP manual for instructions.");
}
$this->ConstructDataset($uDataSource);
$this->EventConstructed();
}
public function ConstructDataset($uDataSource, $uCommunityId = 0)
public function __get($name)
{
$bind_datasets = true;
/* TODO: Don't overwrite current value in uVariable when sVariable is requested and uVariable is already set. */
if(is_numeric($uDataSource))
if($name[0] == "s" || $name[0] == "u")
{
if($uDataSource != 0)
$actual_name = substr($name, 1);
$found = false;
foreach($this->prototype as $type => $dataset)
{
if(!empty($this->fill_query))
{
$this->sId = (is_numeric($uDataSource)) ? $uDataSource : 0;
$query = sprintf($this->fill_query, $uDataSource);
if($result = mysql_query_cached($query, $this->query_cache))
{
$uDataSource = $result->data[0];
}
else
{
$classname = get_class($this);
throw new NotFoundException("Could not locate {$classname} {$uDataSource} in database.");
}
}
else
if(isset($dataset[$actual_name]))
{
$classname = get_class($this);
throw new PrototypeException("No fill query defined for {$classname} class.");
$found = true;
$found_type = $type;
$found_field = $dataset[$actual_name];
}
}
else
if($found === false)
{
$bind_datasets = false;
$classname = get_class($this);
throw new PrototypeException("The {$actual_name} variable was not found in the prototype of the {$classname} class.");
}
$this->SetField($found_type, $actual_name, $found_field);
return $this->$name;
}
}
public function RefreshData()
{
$this->PurgeCache();
$this->ConstructDataset($this->sId, 0);
if($this->autoloading === true)
{
$this->PurgeVariables();
}
elseif(is_object($uDataSource))
}
public function PurgeVariables()
{
foreach($this->prototype as $type => $dataset)
{
foreach($dataset as $key => $field)
{
$variable_name_safe = "s" . $key;
$variable_name_unsafe = "u" . $key;
unset($this->$variable_name_safe);
unset($this->$variable_name_unsafe);
}
}
}
public function ConstructDataset($uDataSource, $expiry = -1)
{
global $database;
$bind_datasets = true;
if(is_object($uDataSource))
{
if(isset($uDataSource->data[0]))
{
@ -84,6 +125,39 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
$uDataSource = $uDataSource[0];
}
}
elseif(is_string($uDataSource) || is_numeric($uDataSource))
{
if($uDataSource !== 0)
{
if(!empty($this->fill_query))
{
/* TODO: Figure out a way to store the ID internally without post-processing... */
$this->sId = htmlspecialchars($uDataSource);
$expiry = ($expiry == -1) ? $this->query_cache : $expiry;
/* Use PDO to fetch the object from the database. */
if($result = $database->CachedQuery($this->fill_query, array(":Id" => (string) $uDataSource), $expiry))
{
$uDataSource = $result->data[0];
}
else
{
$classname = get_class($this);
throw new NotFoundException("Could not locate {$classname} {$uDataSource} in database.", 0, null, "");
}
}
else
{
$classname = get_class($this);
throw new PrototypeException("No fill query defined for {$classname} class.");
}
}
else
{
$bind_datasets = false;
$this->FillDefaults();
}
}
else
{
$classname = get_class($this);
@ -92,13 +166,17 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
if($bind_datasets === true)
{
$this->sId = (is_numeric($uDataSource['Id'])) ? $uDataSource['Id'] : 0;
$this->sId = htmlspecialchars($uDataSource[$this->id_field]);
$this->sIsNewObject = false;
$this->uData = $uDataSource;
foreach($this->prototype as $type => $dataset)
if($this->autoloading === false)
{
$this->BindDataset($type, $dataset);
foreach($this->prototype as $type => $dataset)
{
$this->BindDataset($type, $dataset, $defaultable);
}
}
$this->sFound = true;
@ -107,106 +185,167 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
{
$this->sFound = false;
}
}
public function BindDataset($type, $dataset, $defaultable)
{
global $cphp_config;
if(!empty($uCommunityId) && !empty($this->sCommunityId))
if(is_array($dataset))
{
$sCommunityId = (is_numeric($uCommunityId)) ? $uCommunityId : 0;
if($sCommunityId != $this->sCommunity->sId)
foreach($dataset as $variable_name => $column_name)
{
$classname = get_class($this);
throw new OwnershipException("{$classname} {$this->sId} does not belong to Community {$sCommunityId}.");
$this->SetField($type, $variable_name, $column_name);
}
}
else
{
$classname = get_class($this);
throw new Exception("Invalid dataset passed on to {$classname}.BindDataset.");
}
}
public function BindDataset($type, $dataset)
public function SetField($type, $variable_name, $column_name)
{
global $cphp_class_map;
global $cphp_config;
if(is_array($dataset))
if(!isset($this->uData[$column_name]))
{
foreach($dataset as $variable_name => $column_name)
throw new Exception("The column name {$column_name} was not found in the resultset - ensure the prototype corresponds to the table schema.");
}
$original_value = $this->uData[$column_name];
if($original_value === "" && ($type == "timestamp" || $type == "numeric" || $type == "boolean"))
{
$variable_name_safe = "s" . $variable_name;
$this->$variable_name_safe = null;
$variable_name_unsafe = "u" . $variable_name;
$this->$variable_name_unsafe = null;
}
else
{
switch($type)
{
$original_value = $this->uData[$column_name];
switch($type)
{
case "string":
$value = htmlspecialchars(stripslashes($original_value));
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "html":
$value = filter_html(stripslashes($original_value));
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "simplehtml":
$value = filter_html_strict(stripslashes($original_value));
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "nl2br":
$value = nl2br(htmlspecialchars(stripslashes($original_value)), false);
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "numeric":
$value = (is_numeric($original_value)) ? $original_value : 0;
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "timestamp":
$value = unix_from_mysql($original_value);
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "boolean":
$value = (empty($original_value)) ? false : true;
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "user":
$value = new User($original_value);
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "none":
$value = $original_value;
$variable_type = CPHP_VARIABLE_UNSAFE;
break;
default:
$found = false;
foreach($cphp_class_map as $class_type => $class_name)
case "string":
$value = htmlspecialchars(stripslashes($original_value));
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "html":
$value = filter_html(stripslashes($original_value));
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "simplehtml":
$value = filter_html_strict(stripslashes($original_value));
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "nl2br":
$value = nl2br(htmlspecialchars(stripslashes($original_value)), false);
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "numeric":
$value = (is_numeric($original_value)) ? $original_value : 0;
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "timestamp":
$value = unix_from_mysql($original_value);
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "boolean":
$value = (empty($original_value)) ? false : true;
$variable_type = CPHP_VARIABLE_SAFE;
break;
case "none":
$value = $original_value;
$variable_type = CPHP_VARIABLE_UNSAFE;
break;
default:
$found = false;
foreach(get_object_vars($cphp_config->class_map) as $class_type => $class_name)
{
if($type == $class_type)
{
if($type == $class_type)
try
{
$value = new $class_name($original_value);
$variable_type = CPHP_VARIABLE_SAFE;
$found = true;
}
catch (NotFoundException $e)
{
$e->field = $variable_name;
throw $e;
}
$variable_type = CPHP_VARIABLE_SAFE;
$found = true;
}
if($found == false)
{
$classname = get_class($this);
throw new Exception("Cannot determine type of dataset ({$type}) passed on to {$classname}.BindDataset.");
break;
}
}
if($variable_type == CPHP_VARIABLE_SAFE)
{
$variable_name_safe = "s" . $variable_name;
$this->$variable_name_safe = $value;
}
$variable_name_unsafe = "u" . $variable_name;
$this->$variable_name_unsafe = $original_value;
}
if($found == false)
{
$classname = get_class($this);
throw new Exception("Cannot determine type of dataset ({$type}) passed on to {$classname}.BindDataset.");
break;
}
}
if($variable_type == CPHP_VARIABLE_SAFE)
{
$variable_name_safe = "s" . $variable_name;
$this->$variable_name_safe = $value;
}
$variable_name_unsafe = "u" . $variable_name;
$this->$variable_name_unsafe = $original_value;
}
else
}
public function FillDefaults()
{
foreach($this->prototype as $type => $dataset)
{
$classname = get_class($this);
throw new Exception("Invalid dataset passed on to {$classname}.BindDataset.");
switch($type)
{
case "string":
case "simplehtml":
case "html":
case "nl2br":
case "none":
$safe_default_value = "";
$unsafe_default_value = "";
break;
case "numeric":
$safe_default_value = 0;
$unsafe_default_value = "0";
break;
case "boolean":
$safe_default_value = false;
$unsafe_default_value = "0";
break;
case "timestamp":
$safe_default_value = null;
$unsafe_default_value = null;
break;
default:
continue 2;
}
foreach($dataset as $property)
{
$safe_variable_name = "s" . $property;
$this->$safe_variable_name = $safe_default_value;
$unsafe_variable_name = "u" . $property;
$this->$unsafe_variable_name = $unsafe_default_value;
}
}
}
public function DoRenderInternalTemplate()
{
/* DEPRECATED: Please do not use this function.
* Class-specific templater functions have been discontinued. Instead, you can use
* Templater::AdvancedParse for rendering templates without instantiating a Templater
* yourself. */
if(!empty($this->render_template))
{
$strings = array();
@ -224,18 +363,25 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
}
}
public function InsertIntoDatabase()
public function InsertIntoDatabase($force_data = false)
{
global $cphp_config, $database;
if(!empty($this->verify_query))
{
if($this->sId == 0)
if(strpos($this->verify_query, ":Id") === false)
{
throw new DeprecatedException("Support for mysql_* has been removed from CPHP. Please update your queries to be in CachedPDO-style.");
}
if($this->sIsNewObject === true)
{
$insert_mode = CPHP_INSERTMODE_INSERT;
}
else
{
$query = sprintf($this->verify_query, $this->sId);
if($result = mysql_query_cached($query))
/* FIXME: This can probably be optimized... */
if($result = $database->CachedQuery($this->verify_query, array(":Id" => $this->sId), 0))
{
$insert_mode = CPHP_INSERTMODE_UPDATE;
}
@ -245,6 +391,29 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
}
}
if($force_data === true)
{
foreach($this->prototype as $type_key => $type_value)
{
foreach($type_value as $element_key => $element_value)
{
$variable_name_unsafe = "u" . $element_key;
if(!isset($this->$variable_name_unsafe))
{
foreach($this->prototype as $type => $dataset)
{
if(isset($dataset[$element_key]))
{
$column_name = $dataset[$element_key];
$this->$variable_name_unsafe = $this->uData[$column_name];
}
}
}
}
}
}
$element_list = array();
foreach($this->prototype as $type_key => $type_value)
@ -258,6 +427,9 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
case "boolean":
case "timestamp":
case "string":
case "simplehtml":
case "html":
case "nl2br":
$element_list[$element_value] = array(
'key' => $element_key,
'type' => $type_key
@ -270,7 +442,8 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
}
$sKeyList = array();
$sValueList = array();
$sKeyIdentifierList = array();
$uValueList = array();
foreach($element_list as $sKey => $value)
{
@ -282,77 +455,121 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
switch($value['type'])
{
case "none":
$sFinalValue = mysql_real_escape_string($this->$variable_name_unsafe);
$uFinalValue = $this->$variable_name_unsafe;
break;
case "numeric":
$number = (isset($this->$variable_name_unsafe)) ? $this->$variable_name_unsafe : $this->$variable_name_safe;
$sFinalValue = (is_numeric($number)) ? $number : 0;
$uFinalValue = (is_numeric($number)) ? $number : 0;
break;
case "boolean":
$bool = (isset($this->$variable_name_unsafe)) ? $this->$variable_name_unsafe : $this->$variable_name_safe;
$sFinalValue = ($bool) ? "1" : "0";
$uFinalValue = ($bool) ? "1" : "0";
break;
case "timestamp":
$sFinalValue = (isset($this->$variable_name_safe)) ? mysql_from_unix($this->$variable_name_safe) : mysql_from_unix(unix_from_local($this->$variable_name_unsafe));
if(is_numeric($this->$variable_name_unsafe))
{
$uFinalValue = mysql_from_unix($this->$variable_name_unsafe);
}
else
{
if(isset($this->$variable_name_safe))
{
$uFinalValue = mysql_from_unix($this->$variable_name_safe);
}
else
{
$uFinalValue = mysql_from_unix(unix_from_local($this->$variable_name_unsafe));
}
}
break;
case "string":
$sFinalValue = (isset($this->$variable_name_unsafe)) ? mysql_real_escape_string($this->$variable_name_unsafe) : mysql_real_escape_string($this->$variable_name_safe);
case "simplehtml":
case "html":
case "nl2br":
$uFinalValue = (isset($this->$variable_name_unsafe)) ? $this->$variable_name_unsafe : $this->$variable_name_safe;
break;
case "default":
$sFinalValue = mysql_real_escape_string($this->$variable_name_unsafe);
$uFinalValue = $this->$variable_name_unsafe;
break;
}
$sFinalValue = "'{$sFinalValue}'";
$sKey = "`{$sKey}`";
$sIdentifier = ":{$sKey}";
$sKeyList[] = $sKey;
$sValueList[] = $sFinalValue;
$sKeyList[] = "`{$sKey}`";
$sKeyIdentifierList[] = $sIdentifier;
$uValueList[$sIdentifier] = $uFinalValue;
}
else
{
$classname = get_class($this);
throw new Exception("Database insertion failed: prototype property {$value['key']} not found in object of type {$classname}.");
if($this->autoloading === false)
{
$classname = get_class($this);
throw new Exception("Database insertion failed: prototype property {$value['key']} not found in object of type {$classname}.");
}
}
}
if($insert_mode == CPHP_INSERTMODE_INSERT)
{
if(!empty($this->uId))
{
$sIdentifier = ":{$this->id_field}";
$sKeyList[] = "`{$this->id_field}`";
$sKeyIdentifierList[] = $sIdentifier;
$uValueList[$sIdentifier] = $this->uId;
}
$sQueryKeys = implode(", ", $sKeyList);
$sQueryValues = implode(", ", $sValueList);
$query = "INSERT INTO {$this->table_name} ({$sQueryKeys}) VALUES ({$sQueryValues})";
$sQueryKeyIdentifiers = implode(", ", $sKeyIdentifierList);
$query = "INSERT INTO {$this->table_name} ({$sQueryKeys}) VALUES ({$sQueryKeyIdentifiers})";
}
elseif($insert_mode == CPHP_INSERTMODE_UPDATE)
{
$sKeyValueList = array();
$sKeysIdentifiersList = array();
for($i = 0; $i < count($sKeyList); $i++)
{
$sKey = $sKeyList[$i];
$sValue = $sValueList[$i];
$sKeyValueList[] = "{$sKey} = {$sValue}";
$sValue = $sKeyIdentifierList[$i];
$sKeysIdentifiersList[] = "{$sKey} = {$sValue}";
}
$sQueryKeysValues = implode(", ", $sKeyValueList);
$query = "UPDATE {$this->table_name} SET {$sQueryKeysValues} WHERE `Id` = '{$this->sId}'";
$sQueryKeysIdentifiers = implode(", ", $sKeysIdentifiersList);
/* We use :CPHPID here because it's unlikely to be used in the application itself. */
$query = "UPDATE {$this->table_name} SET {$sQueryKeysIdentifiers} WHERE `{$this->id_field}` = :CPHPID";
$uValueList[':CPHPID'] = $this->sId;
}
if($result = mysql_query($query))
try
{
$result = $database->CachedQuery($query, $uValueList, 0);
if($insert_mode == CPHP_INSERTMODE_INSERT)
{
$this->sId = mysql_insert_id();
$this->sId = $database->lastInsertId();
$this->sIsNewObject = false;
}
$this->PurgeCache();
$this->RefreshData();
return $result;
}
else
catch (DatabaseException $e)
{
$classname = get_class($this);
throw new DatabaseException("Database insertion query failed in object of type {$classname}. Error message: " . mysql_error());
$error = $database->errorInfo();
if(empty($error[2]))
{
$errmsg = $e->getMessage();
}
else
{
$errmsg = $error[2];
}
throw new DatabaseException("Database insertion query failed in object of type {$classname}. Error message: " . $errmsg);
}
}
else
@ -364,13 +581,15 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
public function RetrieveChildren($type, $field)
{
if(!isset($cphp_class_map[$type]))
/* Probably won't ever be fully implemented, now that there is CreateFromQuery. */
if(!isset($cphp_config->class_map->$type))
{
$classname = get_class($this);
throw new NotFoundException("Non-existent 'type' argument passed on to {$classname}.RetrieveChildren function.");
}
$parent_type = get_parent_class($cphp_class_map[$type]);
$parent_type = get_parent_class($cphp_config->class_map->$type);
if($parent_type !== "CPHPDatabaseRecordClass")
{
$parent_type = ($parent_type === false) ? "NONE" : $parent_type;
@ -383,9 +602,13 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
public function PurgeCache()
{
$query = sprintf($this->fill_query, $this->sId);
$key = md5($query) . md5($query . "x");
mc_delete($key);
$parameters = array(":Id" => (string) $this->sId);
$query_hash = md5($this->fill_query);
$parameter_hash = md5(serialize($parameters));
$cache_hash = $query_hash . $parameter_hash;
mc_delete($cache_hash);
}
public function RenderTemplate($template = "")
@ -398,6 +621,69 @@ abstract class CPHPDatabaseRecordClass extends CPHPBaseClass
return $this->DoRenderInternalTemplate();
}
public function Export()
{
/* This function is DEPRECATED and should not be used. Please manually build your arrays instead. */
$export_array = array();
foreach($this->prototype_export as $field)
{
$variable_name = "s{$field}";
if(is_object($this->$variable_name))
{
if(!empty($this->$variable_name->sId))
{
$export_array[$field] = $this->$variable_name->Export();
}
else
{
$export_array[$field] = null;
}
}
else
{
$export_array[$field] = $this->$variable_name;
}
}
return $export_array;
}
public static function CreateFromQuery($query, $parameters = array(), $expiry = 0, $first_only = false)
{
global $database;
$result = $database->CachedQuery($query, $parameters, $expiry);
if($result)
{
if($first_only === true)
{
/* TODO: Try to run the query with LIMIT 1 if only the first result is desired. */
return new static($result);
}
elseif(count($result->data) == 1)
{
return array(new static($result));
}
else
{
$result_array = array();
foreach($result->data as $row)
{
$result_array[] = new static($row);
}
return $result_array;
}
}
else
{
throw new NotFoundException("No results for specified query.");
}
}
// Define events
protected function EventConstructed() { }

13
class.localizer.php

@ -22,6 +22,7 @@ class Localizer
public $date_short = "";
public $date_long = "";
public $time = "";
public $name = "";
public function Load($locale)
{
@ -32,8 +33,14 @@ class Localizer
public function LoadInternal($locale)
{
global $cphp_locale_path, $cphp_locale_ext;
$lng_contents = file_get_contents("{$cphp_locale_path}/{$locale}.{$cphp_locale_ext}");
global $cphp_config;
if(!isset($cphp_config->locale->path) || !isset($cphp_config->locale->extension))
{
throw new Exception("The locale path settings are not specified correctly. Refer to the CPHP manual for instructions.");
}
$lng_contents = file_get_contents("{$cphp_config->locale->path}/{$locale}.{$cphp_config->locale->extension}");
if($lng_contents !== false)
{
$lines = explode("\n", $lng_contents);
@ -70,6 +77,8 @@ class Localizer
}
}
}
$this->name = $locale;
}
else
{

1331
class.templater.php

File diff suppressed because it is too large

18
components/component.errorhandler.php

@ -42,31 +42,27 @@ class CPHPErrorHandler
{
global $locale;
$template['error'] = new Templater();
switch($this->sErrorType)
{
case CPHP_ERRORHANDLER_TYPE_ERROR:
$template['error']->Load("errorhandler.error");
$template = "errorhandler.error";
break;
case CPHP_ERRORHANDLER_TYPE_INFO:
$template['error']->Load("errorhandler.info");
$template = "errorhandler.info";
break;
case CPHP_ERRORHANDLER_TYPE_WARNING:
$template['error']->Load("errorhandler.warning");
$template = "errorhandler.warning";
break;
case CPHP_ERRORHANDLER_TYPE_SUCCESS:
$template['error']->Load("errorhandler.success");
$template = "errorhandler.success";
break;
default:
return false;
}
$template['error']->Localize($locale->strings);
$template['error']->Compile(array(
return Templater::AdvancedParse($template, $locale->strings, array(
'title' => $this->sTitle,
'message' => $this->sMessage
));
return $template['error']->Render();
}
}
?>

319
components/component.formbuilder.php

@ -1,319 +0,0 @@
<?php
/*
* CPHP is more free software. It is licensed under the WTFPL, which
* allows you to do pretty much anything with it, without having to
* ask permission. Commercial use is allowed, and no attribution is
* required. We do politely request that you share your modifications
* to benefit other developers, but you are under no enforced
* obligation to do so :)
*
* Please read the accompanying LICENSE document for the full WTFPL
* licensing text.
*/
cphp_dependency_provides("cphp_formbuilder", "1.0");
$cphp_formbuilder_increment = 0;
abstract class CPHPFormBuilderBaseClass
{
public $parameters = array();
public function AddParameter($key, $value)
{
$this->parameters[$key] = $value;
}
public function RenderParameters($parameters)
{
if(empty($parameters))
{
return "";
}
$rendered = array();
foreach($parameters as $key => $value)
{
$value = utf8entities($value);
$rendered[] = "{$key}=\"{$value}\"";
}
return " " . implode(" ", $rendered);
}
public function RenderNote()
{
if(!empty($this->note))
{
return "<div class=\"cphp_fbd_note\">{$this->note}</div>";
}
else
{
return "";
}
}
}
abstract class CPHPFormBuilderContainer extends CPHPFormBuilderBaseClass
{
public $elements = array();
public function AddElement($element)
{
$this->elements[] = $element;
}
}
class CPHPFormBuilder extends CPHPFormBuilderContainer
{
public $method = "";
public $action = "";
public function __construct($method, $target)
{
$this->method = strtolower($method);
$this->action = $target;
}
public function Render()
{
$rendered_elements = "";
foreach($this->elements as $element)
{
$rendered_elements .= $element->Render();
}
$this->AddParameter("method", $this->method);
$this->AddParameter("action", $this->action);
$rendered_parameters = $this->RenderParameters($this->parameters);
return "<form{$rendered_parameters}>{$rendered_elements}</form>";
}
}
class CPHPFormSection extends CPHPFormBuilderContainer
{
public $label = "";
public $fieldset = true;
public $classname = "";
public function __construct($fieldset = true, $label = "")
{
if(!empty($label))
{
$this->label = $label;
}
$this->fieldset = $fieldset;
}
public function Render()
{
if(!empty($this->label))
{
$legend = "<legend>{$this->label}</legend>";
}
else
{
$legend = "";
}
if($this->fieldset === true)
{
$this->classname = trim("{$this->classname} cphp_fbd_fieldset");
}
$rendered_elements = "";
foreach($this->elements as $element)
{
$rendered_elements .= $element->Render();
}
if($this->fieldset === true)
{
$this->AddParameter("class", $this->classname);
$rendered_parameters = $this->RenderParameters($this->parameters);
return "<fieldset{$rendered_parameters}>{$legend}<div class=\"cphp_fbd_form\">{$rendered_elements}</div></fieldset>";
}
else
{
return "<div class=\"cphp_fbd_form\"{$rendered_parameters}>{$rendered_elements}</div>";
}
}
}
abstract class CPHPFormInputElement extends CPHPFormBuilderBaseClass
{
public $id = "";
public $name = "";
public $value = "";
public $label = "";
public function __construct($label, $name, $value = "", $note = "", $id = "")
{
global $cphp_formbuilder_increment;
$this->name = $name;
$this->value = $value;
$this->label = $label;
$this->note = $note;
if(empty($id))
{
$this->id = "cphp_fbd_{$cphp_formbuilder_increment}";
$cphp_formbuilder_increment += 1;
}
else
{
$this->id = $id;
}
}
}
abstract class CPHPFormInput extends CPHPFormInputElement
{
public function Render()
{
$this->AddParameter("id", $this->id);
$this->AddParameter("type", $this->type);
$this->AddParameter("name", $this->name);
$this->AddParameter("value", $this->value);
$rendered_parameters = $this->RenderParameters($this->parameters);
$rendered_note = $this->RenderNote();
return "<div class=\"cphp_fbd_row\"><div class=\"cphp_fbd_label\">{$this->label}{$rendered_note}</div><div class=\"cphp_fbd_field\"><input{$rendered_parameters}></div></div>";
}
}
class CPHPFormTextInput extends CPHPFormInput
{
public $type = "text";
}
class CPHPFormPasswordInput extends CPHPFormInput
{
public $type = "password";
}
class CPHPFormDateInput extends CPHPFormInput
{
public $type = "date";
}
class CPHPFormTimeInput extends CPHPFormInput
{
public $type = "time";
}
class CPHPFormEmailInput extends CPHPFormInput
{
public $type = "email";
}
class CPHPFormUrlInput extends CPHPFormInput
{
public $type = "url";
}
class CPHPFormRangeInput extends CPHPFormInput
{
public $type = "range";
}
class CPHPFormColorInput extends CPHPFormInput
{
public $type = "color";
}
class CPHPFormSearchInput extends CPHPFormInput
{
public $type = "search";
}
class CPHPFormCheckboxGroup extends CPHPFormBuilderContainer
{
public function __construct($label, $note = "")
{
global $cphp_formbuilder_increment;
$this->label = $label;
$this->note = $note;
}
public function Render()
{
$rendered_note = $this->RenderNote();
$rendered_elements = "";
foreach($this->elements as $element)