Index: include/lib_auth.inc.php
===================================================================
RCS file: /repository/docweb/include/lib_auth.inc.php,v
retrieving revision 1.13
diff -u -r1.13 lib_auth.inc.php
--- include/lib_auth.inc.php 5 Feb 2006 11:17:37 -0000 1.13
+++ include/lib_auth.inc.php 3 Oct 2006 21:06:21 -0000
@@ -36,6 +36,7 @@
'sean',
'vincent',
'mazzanet',
+ 'colder',
);
$user = $password = false;
Index: include/lib_general.inc.php
===================================================================
RCS file: /repository/docweb/include/lib_general.inc.php,v
retrieving revision 1.50
diff -u -r1.50 lib_general.inc.php
--- include/lib_general.inc.php 11 Aug 2005 15:25:37 -0000 1.50
+++ include/lib_general.inc.php 3 Oct 2006 21:06:21 -0000
@@ -209,11 +209,12 @@
switch(SITE) {
case 'php':
- $links['orphan-notes'] = BASE_URL . '/orphan_notes.php';
- $links['notes-stats'] = BASE_URL . '/notes_stats.php';
- $links['undoc-functions'] = BASE_URL . '/undoc_functions.php';
+ $links['orphan-notes'] = BASE_URL . '/orphan_notes.php';
+ $links['notes-stats'] = BASE_URL . '/notes_stats.php';
+ $links['undoc-functions'] = BASE_URL . '/undoc_functions.php';
$links['missing-examples'] = BASE_URL . '/missing_examples.php';
-
+ $links['phpt-generator'] = BASE_URL . '/phpt_generator.php';
+
case 'pear':
case 'smarty':
}
Index: include/lib_phpt_generator.inc.php
===================================================================
RCS file: include/lib_phpt_generator.inc.php
diff -N include/lib_phpt_generator.inc.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ include/lib_phpt_generator.inc.php 3 Oct 2006 21:06:22 -0000
@@ -0,0 +1,426 @@
+ |
++----------------------------------------------------------------------+
+$Id:$
+*/
+/**
+ * Parameters
+ */
+define('PHPT_EOL', "\n");
+define('PHPT_SQLITE_FILE', SQLITE_DIR . 'tests.sqlite');
+define('PHPT_DOC_PATH', CVS_DIR.'/phpdoc-all/en/');
+
+define('PHPT_LIMIT_RESULTS', 200);
+
+define('PHPT_EXAMPLE_REGEX', '#\s*(.+)\s*\s*\s*(.+)#isU');
+define('PHPT_OUTPUT_REGEX', '#&example\.outputs;\s*\s*\s*#isU');
+
+define('PHPT_FLAG_IMPORTED', 1);
+define('PHPT_FLAG_FILLED', 2);
+define('PHPT_FLAG_APPROVED', 4);
+define('PHPT_FLAG_IMPLEMENTED', 8);
+
+define('PHPT_FORMAT_SKIPIF', "--TEST--".PHPT_EOL.
+ "%s (generated)".PHPT_EOL.
+ "--SKIPIF--".PHPT_EOL.
+ "%s".PHPT_EOL.
+ "--FILE--".PHPT_EOL.
+ "%s".PHPT_EOL.
+ "--EXPECT--".PHPT_EOL.
+ "%s");
+
+define('PHPT_FORMAT', "--TEST--".PHPT_EOL.
+ "%s (generated)".PHPT_EOL.
+ "--FILE--".PHPT_EOL.
+ "%s".PHPT_EOL.
+ "--EXPECT--".PHPT_EOL.
+ "%s");
+
+
+// disable magic_quotes_gpc
+
+function phpt_clean_gpc (&$item, $key) {
+ $item = stripslashes($item);
+}
+
+
+/**
+ * Opens a new SQLite connection for URLs
+ *
+ * @return resource SQLite connection
+ */
+function phpt_sqlite_open()
+{
+ return @sqlite_open(PHPT_SQLITE_FILE, 0666);
+}
+
+
+/**
+ * Extrapolate informations from the sql result
+ *
+ * @return resource SQLite connection
+ */
+function phpt_extrapolate($row)
+{
+
+ $return = array('id' => (int) $row['id'],
+ 'title' => $row['title'],
+ 'location' => '',
+ 'class' => '',
+ 'status' => '',
+ 'expected' => '',
+ 'test' => '',
+ 'skipif' => '',
+ 'approve_checkbox' => '',
+ 'cvs_link' => 'http://cvs.php.net/viewvc.cgi/phpdoc/en/'.$row['location'].'?view=markup',
+ 'test_lines' => 4,
+ 'expected_lines' => 4,
+ 'skipif_lines' => 1,
+ );
+
+ // clean up location
+ $path_pieces = explode('/', $row['location']);
+ $return['location'] = implode('/', array_slice($path_pieces, -3));
+
+ // generate the status and the status class
+ if (($row['flags'] & PHPT_FLAG_IMPLEMENTED) === PHPT_FLAG_IMPLEMENTED) {
+ $return['status'] = '&docweb.phpt.implemented;';
+ $return['class'] = 'phpt_implemented';
+ } else if (($row['flags'] & PHPT_FLAG_APPROVED) === PHPT_FLAG_APPROVED) {
+ $return['status'] = '&docweb.phpt.approved;';
+ $return['class'] = 'phpt_approved';
+ } else if (($row['flags'] & PHPT_FLAG_FILLED) === PHPT_FLAG_FILLED) {
+ $return['status'] = '&docweb.phpt.filled;';
+ $return['class'] = 'phpt_filled';
+ } else {
+ $return['status'] = '&docweb.phpt.imported;';
+ $return['class'] = 'phpt_none';
+ }
+
+
+ if (!empty($row['expected'])) {
+ if(($num = substr_count($row['expected'], "\n")) > $return['expected_lines']) {
+ if($num > 30) {
+ $num = 30;
+ }
+
+ $return['expected_lines'] = $num;
+
+ }
+ $return['expected'] = htmlentities($row['expected']);
+ }
+
+ if (!empty($row['test'])) {
+ if(($num = substr_count($row['test'], "\n")) > $return['test_lines']) {
+ if($num > 30) {
+ $num = 30;
+ }
+ $return['test_lines'] = $num;
+ }
+ $return['test'] = htmlentities($row['test']);
+ }
+
+ if (!empty($row['skipif'])) {
+ if(($num = substr_count($row['skipif'], "\n")) > $return['skipif_lines']) {
+ if($num > 30) {
+ $num = 30;
+ }
+ $return['skipif_lines'] = $num;
+ }
+ $return['skipif'] = htmlentities($row['skipif']);
+ }
+ // approve checkbox
+
+ if (($row['flags'] & PHPT_FLAG_APPROVED) === PHPT_FLAG_APPROVED) {
+ $return['approve_checkbox'] = ' checked';
+ }
+
+ // careful with large titles
+ $return['title_limited'] = trim($return['title']);
+
+ if (strlen($return['title_limited']) > 40) {
+ $return['title_limited'] = substr($return['title_limited'], 0, 37).'...';
+ }
+
+ $return['title'] = trim(htmlentities($return['title']));
+ $return['title_limited'] = htmlentities($return['title_limited']);
+
+ return $return;
+
+}
+
+
+/**
+ * Import examples from doc sources.
+ *
+ * @return int, number of imported examples
+ */
+function phpt_import_from_source($sqlite)
+{
+
+ // Begin the listing
+ $userdata = array('examples_added' => 0,
+ 'sqlite' => $sqlite);
+
+
+ $path = '';
+
+ phpt_list_files(PHPT_DOC_PATH, $path, $userdata);
+
+ return $userdata['examples_added'];
+
+}
+
+/**
+ * List files recursivly and scan them
+ *
+ * @return bool
+ */
+function phpt_list_files($prefix, $path, &$userdata) {
+
+ if (is_dir($prefix.$path) && is_resource($handle = @opendir($prefix.$path))) {
+
+ while ($name = readdir($handle)) {
+ if (strpos($name, ".xml") !== false) {
+ phpt_scan_file($prefix, $path.$name, $userdata);
+ } else if(is_dir($prefix.$path.$name) && $name !== 'CVS' && $name !== '.' && $name !== '..') {
+ phpt_list_files($prefix, $path.$name.DIRECTORY_SEPARATOR, $userdata);
+ }
+
+ }
+
+ closedir($handle);
+ return true;
+
+ } else {
+ return false;
+ }
+
+}
+
+/**
+ * Scan files for examples, and insert them
+ *
+ * @return null
+ */
+function phpt_scan_file($prefix, $path, &$userdata) {
+
+ if (!is_file($prefix.$path)) {
+ return false;
+ }
+
+ $content = file_get_contents($prefix.$path);
+
+ if ($number = preg_match_all(PHPT_EXAMPLE_REGEX, $content, $matches)) {
+ // found at least an example
+
+ foreach ($matches[2] as $key => $example) {
+
+ $expected = '';
+ $flags = 1;
+
+ /* Parse the extra content */
+ $extra = $matches[3][$key];
+
+ if (preg_match(PHPT_OUTPUT_REGEX, $extra, $match)) {
+ $expected = $match[1];
+ $flags |= PHPT_FLAG_FILLED;
+ }
+
+
+ $title = preg_replace('#([\w_-]+)#', '\1()', $matches[1][$key]);
+
+ //$example = preg_replace('/print_r(\s+)\(/', 'var_dump\1(', $example);
+
+ // let's create the entry
+
+ $sql_query = "INSERT INTO tests (
+ title,
+ location,
+ test,
+ expected,
+ import_date,
+ flags
+ )
+ VALUES (
+ '".sqlite_escape_string($title)."',
+ '".sqlite_escape_string($path)."',
+ '".sqlite_escape_string(phpt_clean_ws($example))."',
+ '".sqlite_escape_String(phpt_clean_ws($expected))."',
+ datetime('now'),
+ $flags
+ )";
+ // @ here to avoid "column test is not unique".
+ if (!@sqlite_exec($userdata['sqlite'], $sql_query)) {
+ $number--;
+ }
+
+ }
+
+ $userdata['examples_added'] += $number;
+ }
+
+}
+
+/**
+ * Generate a list of examples
+ *
+ * @return null
+ */
+function phpt_generate_list($sqlite, $ids)
+{
+ $ids = array_map('intval', $ids);
+
+ // select data
+
+ $sql_query = 'SELECT id,
+ title,
+ location,
+ test,
+ skipif,
+ expected,
+ edit_date,
+ import_date,
+ flags
+ FROM tests
+ WHERE id IN ('.implode(',', $ids).')';
+
+ $results = sqlite_query($sqlite, $sql_query);
+
+
+ if (count($ids) === 1) {
+ phpt_download(sqlite_fetch_array($results, SQLITE_ASSOC));
+ } else {
+
+ $archivePath = '/tmp/phpt_'.md5(implode('-', $ids)).'.tgz';
+
+ header('Content-Type: application/gzip');
+ header('Content-Disposition: attachment; filename='.basename($archivePath));
+
+
+
+ $myArchive = new Archive_Tar($archivePath, 'gz');
+
+ while ($row = sqlite_fetch_array($results, SQLITE_ASSOC)) {
+ $myArchive->addString('test'.$row['id'].'.phpt', phpt_generate($row));
+ }
+
+ readfile($archivePath);
+ unlink($archivePath);
+
+ }
+}
+
+/**
+ * Delete a list of tests
+ *
+ * @return null
+ */
+function phpt_delete_list($sqlite, $ids)
+{
+ $ids = array_map('intval', $ids);
+
+ $sql_query = 'DELETE FROM tests
+ WHERE id IN ('.implode(',', $ids).')';
+
+ return var_dump(sqlite_exec($sqlite, $sql_query));
+
+}
+
+/**
+ * Generate one example
+ *
+ * @return null
+ */
+function phpt_generate($infos)
+{
+
+ if (empty($infos['skipif'])) {
+
+ return sprintf(PHPT_FORMAT, $infos['title'],
+ $infos['test'],
+ $infos['expected']);
+
+ } else {
+
+ return sprintf(PHPT_FORMAT_SKIPIF, $infos['title'],
+ $infos['skipif'],
+ $infos['test'],
+ $infos['expected']);
+ }
+}
+
+
+/**
+ * Generate one example and make it available to download
+ *
+ * @return null
+ */
+function phpt_download($infos)
+{
+ if (headers_sent()) {
+ return false;
+ }
+
+ $path_pieces = explode('/', $infos['location']);
+ $name = implode('_', array_slice($path_pieces, -3));
+
+ $name = substr($name, 0, -4).'.phpt';
+
+ header('Content-Type: text/plain');
+ header('Content-Disposition: attachment; filename="'.$name.'"');
+
+ echo phpt_generate($infos);
+}
+
+
+/**
+ * Commit changes
+ *
+ * @return true/false
+ */
+function phpt_commit_changes($sqlite, $input)
+{
+ $title = !empty($input['title']) ? sqlite_escape_string($input['title']) : '';
+ $test = !empty($input['test']) ? sqlite_escape_string(phpt_clean_ws($input['test'])) : '';
+ $skipif = !empty($input['skipif']) ? sqlite_escape_string(phpt_clean_ws($input['skipif'])) : '';
+ $expected = !empty($input['expected']) ? sqlite_escape_string(phpt_clean_ws($input['expected'])) : '';
+ $flags = isset($input['approve']) ? PHPT_FLAG_APPROVED : 0;
+ if (!empty($expected)) {
+ $flags |= PHPT_FLAG_FILLED;
+ }
+
+ $sql_query = "UPDATE tests SET edit_date = datetime('now'),
+ title = '$title',
+ test = '$test',
+ skipif = '$skipif',
+ expected = '$expected',
+ flags = flags | $flags
+ WHERE id = ".intval($input['editId']);
+ //echo $sql_query;
+ return @sqlite_exec($sqlite, $sql_query);
+}
+
+/**
+ * clean linefeeds and extra spaces
+ */
+function phpt_clean_ws($string)
+{
+ $string = trim($string);
+ return str_replace(array("\r\n", "\r", "\n"), PHPT_EOL, $string);
+}
+
Index: scripts/setup_tests_database.php
===================================================================
RCS file: scripts/setup_tests_database.php
diff -N scripts/setup_tests_database.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ scripts/setup_tests_database.php 3 Oct 2006 21:06:23 -0000
@@ -0,0 +1,31 @@
+#!/usr/local/bin/php
+ |
++----------------------------------------------------------------------+
+$Id:$
+*/
+
+$path = '../sqlite/tests.sqlite';
+
+$idx = sqlite_open($path, 0666);
+
+if (!$idx) {
+ die('Could not open '.$path);
+}
+
+sqlite_query($idx, file_get_contents("../sql/tests.sql"));
+sqlite_close($idx);
Index: sql/tests.sql
===================================================================
RCS file: sql/tests.sql
diff -N sql/tests.sql
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sql/tests.sql 3 Oct 2006 21:06:23 -0000
@@ -0,0 +1,20 @@
+/*
+ * Tables for the RFC system
+ * Original PEPr sql can be found at pearweb/sql/pepr.sql
+ *
+ * This is for a SQLite database, only edit if you
+ * know what SQLite doesn't support
+ */
+;
+
+CREATE TABLE tests (
+ id INTEGER PRIMARY KEY,
+ title varchar(150) NOT NULL default '',
+ location varchar(80) NOT NULL default '',
+ test text NOT NULL UNIQUE,
+ skipif, text NOT NULL default '',
+ expected text NOT NULL default '',
+ edit_date timestamp(14) NOT NULL default '0',
+ import_date timestamp(14) NOT NULL default '0',
+ flags INTEGER NOT NULL default 1
+)
Index: templates/all/www/phpt_edit.tpl.php
===================================================================
RCS file: templates/all/www/phpt_edit.tpl.php
diff -N templates/all/www/phpt_edit.tpl.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ templates/all/www/phpt_edit.tpl.php 3 Oct 2006 21:06:23 -0000
@@ -0,0 +1,44 @@
+Error:
+$error;
+
&docweb.phpt.return;
+HTML;
+
+ return;
+}
+
+if ($edited === false) {
+ echo '
&docweb.phpt.edit.error;
';
+} else if ($edited === true) {
+ echo '&docweb.phpt.edit.ok;
';
+}
+
+echo <<&docweb.phpt.edit;
+
+&docweb.phpt.return;
+&docweb.phpt.generate;
+
+
+HTML;
+
+?>
Index: templates/all/www/phpt_list.tpl.php
===================================================================
RCS file: templates/all/www/phpt_list.tpl.php
diff -N templates/all/www/phpt_list.tpl.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ templates/all/www/phpt_list.tpl.php 3 Oct 2006 21:06:23 -0000
@@ -0,0 +1,59 @@
+&docweb.phpt.limitreached;
';
+} else {
+ $limitError = '';
+}
+
+echo <<&docweb.phpt.list;
+
+&docweb.phpt.import;
+
+
+
+
+ {$limitError}Stats: $ntotal examples, $napproved approved, $nfilled filled, $nimported imported.
+
+
+ | &docweb.phpt.list.id; |
+ &docweb.phpt.list.location; |
+ &docweb.phpt.list.title; |
+ &docweb.phpt.list.status; |
+
+HTML;
+
+
+ foreach ($tests as $test) {
+
+ echo <<
+ {$test['id']} |
+ {$test['location']} |
+ {$test['title_limited']} |
+ {$test['status']} |
+
+HTML;
+
+ }
+
+echo <<
+
+
+HTML;
+
+}
+?>
+
Index: www/phpt_generator.php
===================================================================
RCS file: www/phpt_generator.php
diff -N www/phpt_generator.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ www/phpt_generator.php 3 Oct 2006 21:06:23 -0000
@@ -0,0 +1,229 @@
+ |
++----------------------------------------------------------------------+
+$Id:$
+*/
+
+require_once '../include/init.inc.php';
+require_once '../include/lib_phpt_generator.inc.php';
+require_once '../include/lib_auth.inc.php';
+require_once 'Archive/Tar.php';
+
+// clean magic_quotes_gpc
+
+if (get_magic_quotes_gpc()) {
+ array_walk_recursive($_GET, 'phpt_clean_gpc');
+ array_walk_recursive($_POST, 'phpt_clean_gpc');
+ array_walk_recursive($_REQUEST, 'phpt_clean_gpc');
+ array_walk_recursive($_COOKIE, 'phpt_clean_gpc');
+}
+
+
+if (!$sqlite = phpt_sqlite_open()) {
+ echo site_header('docweb.common.header.phptgen');
+ echo 'Unable to open examples database
';
+ echo site_footer();
+ exit();
+}
+
+
+/**
+ * Generate tests
+ */
+if (!empty($_REQUEST['ids']) && isset($_REQUEST['generate'])) {
+ phpt_generate_list($sqlite, array_keys($_REQUEST['ids']));
+ exit;
+}
+
+
+
+/**
+ * Generate one test
+ */
+if (!empty($_REQUEST['generateId'])) {
+
+ $sql_query = 'SELECT id,
+ title,
+ location,
+ test,
+ skipif,
+ expected,
+ edit_date,
+ import_date,
+ flags
+ FROM tests
+ WHERE id = '.(int)$_REQUEST['generateId'];
+
+ $results = sqlite_query($sqlite, $sql_query);
+
+ phpt_download(sqlite_fetch_array($results, SQLITE_ASSOC));
+ exit;
+}
+
+
+/**
+ * check rights when admin required.
+ */
+if ((!empty($_REQUEST['ids']) && isset($_REQUEST['delete']))
+ || isset($_REQUEST['import'])
+ || (!empty($_REQUEST['editId']) && isset($_REQUEST['commit']))) {
+
+ auth();
+ if (!is_admin()) {
+ die('you are not an admin!');
+ }
+}
+
+echo site_header('docweb.common.header.phptgen');
+
+
+
+/**
+ * Remove tests
+ */
+if (!empty($_REQUEST['ids']) && isset($_REQUEST['delete'])) {
+ phpt_delete_list($sqlite, array_keys($_REQUEST['ids']));
+}
+
+
+/**
+ * Import tests
+ */
+if (isset($_REQUEST['import'])) {
+ // this operation requires authentication as
+ // it can waste a lot of server resources
+
+ $num = phpt_import_from_source($sqlite);
+ echo "Imported $num examples
";
+}
+
+/**
+ * Handle edition
+ */
+if (!empty($_REQUEST['editId'])) {
+
+ $test_id = (int)$_REQUEST['editId'];
+ $edited = null;
+ $error = '';
+ $testData = array();
+ $q = !empty($_REQUEST['q']) ? rawurlencode($_REQUEST['q']) : '';
+
+ if (isset($_REQUEST['commit'])) {
+ $edited = phpt_commit_changes($sqlite, $_REQUEST);
+ }
+
+ $sql_query = 'SELECT id,
+ title,
+ location,
+ test,
+ skipif,
+ expected,
+ edit_date,
+ import_date,
+ flags
+ FROM tests
+ WHERE id = '.$test_id;
+
+ $results = sqlite_query($sqlite, $sql_query);
+
+
+ $row = sqlite_fetch_array($results, SQLITE_ASSOC);
+
+ if (empty($row)) {
+ $error = '&docweb.phpt.editidnotfound;';
+ } else {
+ $testData = phpt_extrapolate($row);
+ }
+
+
+ echo DocWeb_Template::get(
+ 'phpt_edit.tpl.php',
+ array(
+ 'test' => $testData,
+ 'error' => $error,
+ 'edited' => $edited,
+ 'q' => $q,
+ )
+ );
+ echo site_footer();
+ exit;
+
+}
+/**
+ * Display listing
+ */
+$testsData = array();
+
+$imported = 0;
+$filled = 0;
+$approved = 0;
+$total = 0;
+$q = '';
+
+if (!empty($_REQUEST['q'])) {
+
+ $q = trim($_REQUEST['q']);
+ $q_sql = str_replace('\%', '%', sqlite_escape_string($q));
+ $sql_query = 'SELECT id,
+ title,
+ location,
+ test,
+ expected,
+ edit_date,
+ import_date,
+ flags
+ FROM tests
+ WHERE location LIKE \'%'.$q_sql.'%\'
+ ORDER BY flags DESC, location, id
+ LIMIT '.PHPT_LIMIT_RESULTS;
+
+ $results = sqlite_query($sqlite, $sql_query);
+
+
+ while ($row = sqlite_fetch_array($results, SQLITE_ASSOC)) {
+ $testsData[$row['id']] = phpt_extrapolate($row);
+ if (($row['flags'] & PHPT_FLAG_APPROVED) === PHPT_FLAG_APPROVED) {
+ $approved ++;
+ }
+ if (($row['flags'] & PHPT_FLAG_FILLED) === PHPT_FLAG_FILLED) {
+ $filled ++;
+ }
+ if ($row['flags'] === PHPT_FLAG_IMPORTED) {
+ $imported ++;
+ }
+
+ $total++;
+ }
+}
+echo DocWeb_Template::get(
+ 'phpt_list.tpl.php',
+ array(
+ 'tests' => $testsData,
+ 'search' => htmlentities($q),
+ 'search_enc' => rawurlencode($q),
+ 'nimported' => $imported,
+ 'nfilled' => $filled,
+ 'napproved' => $approved,
+ 'ntotal' => $total
+
+ )
+);
+
+echo site_footer();
+
+
+?>
Index: www/style/common.css
===================================================================
RCS file: /repository/docweb/www/style/common.css,v
retrieving revision 1.2
diff -u -r1.2 common.css
--- www/style/common.css 21 Jan 2005 18:19:12 -0000 1.2
+++ www/style/common.css 3 Oct 2006 21:06:23 -0000
@@ -229,3 +229,32 @@
/* howto's nav footer */
div.NAVFOOTER { clear: both; }
+
+/* phpt classes */
+tr.phpt_approved td {
+ background-color: #D9FFCC;
+}
+tr.phpt_implemented td {
+ background-color: #CCD9FF;
+}
+tr.phpt_filled td {
+ background-color: #FFF2CC;
+}
+tr.phpt_none td {
+ background-color: #f5f5f5;
+}
+form.phpt input, form.phpt textarea {
+ display: block;
+ margin-bottom: 20px;
+}
+
+form.phpt input[type="submit"]{
+ margin-bottom: 0px;
+ margin-right: 5px;
+ display: inline;
+}
+
+form.phpt td input{
+ display: inline;
+ margin-bottom: 0px;
+}