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;
+ +
+

&docweb.phpt.edit.title;

+ + +

&docweb.phpt.edit.skipif;

+ + +

&docweb.phpt.edit.test;

+ + +

&docweb.phpt.edit.expected;

+ + +

&docweb.phpt.edit.approve;

+ + +
+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;

+ +
+ + +HTML; + +if (!empty($tests)) { + + echo <<

+ +

+ {$limitError}Stats: $ntotal examples, $napproved approved, $nfilled filled, $nimported imported.
+ + + + + + + +HTML; + + + foreach ($tests as $test) { + + echo << + + + + + +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; +}
&docweb.phpt.list.id;&docweb.phpt.list.location;&docweb.phpt.list.title;&docweb.phpt.list.status;
{$test['id']}{$test['location']}{$test['title_limited']}{$test['status']}