--- a/.hgignore Wed Oct 26 16:28:42 2011 +0200
+++ b/.hgignore Wed Oct 26 21:44:35 2011 +0200
@@ -3,3 +3,8 @@
var/abook.txt
.index.php.swp
var/abook.txt~
+class.Address_Book_DB.php~
+class.Address_Book_File.php~
+templates/results.html~
+test.php~
+var/abook.sqlite
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/_vimrc Wed Oct 26 21:44:35 2011 +0200
@@ -0,0 +1,67 @@
+version 6.0
+if &cp | set nocp | endif
+let s:cpo_save=&cpo
+set cpo&vim
+cnoremap <C-F4> c
+inoremap <C-F4> c
+cnoremap <C-Tab> w
+inoremap <C-Tab> w
+cmap <S-Insert> +
+imap <S-Insert>
+xnoremap ggVG
+snoremap gggHG
+onoremap gggHG
+nnoremap gggHG
+vnoremap "+y
+noremap
+vnoremap :update
+nnoremap :update
+onoremap :update
+nmap "+gP
+omap "+gP
+vnoremap "+x
+noremap
+noremap u
+cnoremap :simalt ~
+inoremap :simalt ~
+map Q gq
+nmap gx <Plug>NetrwBrowseX
+nnoremap <silent> <Plug>NetrwBrowseX :call netrw#NetrwBrowseX(expand("<cWORD>"),0)
+onoremap <C-F4> c
+nnoremap <C-F4> c
+vnoremap <C-F4> c
+onoremap <C-Tab> w
+nnoremap <C-Tab> w
+vnoremap <C-Tab> w
+vmap <S-Insert>
+vnoremap <BS> d
+vmap <C-Del> "*d
+vnoremap <S-Del> "+x
+vnoremap <C-Insert> "+y
+nmap <S-Insert> "+gP
+omap <S-Insert> "+gP
+cnoremap gggHG
+inoremap gggHG
+inoremap :update
+inoremap u
+cmap +
+inoremap
+inoremap u
+noremap :simalt ~
+let &cpo=s:cpo_save
+unlet s:cpo_save
+set backspace=indent,eol,start
+set backup
+set diffexpr=MyDiff()
+set guifont=Lucida_Sans_Typewriter:h14:cANSI
+set helplang=de
+set history=50
+set hlsearch
+set incsearch
+set keymodel=startsel,stopsel
+set ruler
+set selection=exclusive
+set selectmode=mouse,key
+set whichwrap=b,s,<,>,[,]
+set window=33
+" vim: set ft=vim :
--- a/addressbook.class.php Wed Oct 26 16:28:42 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-<?
-
-interface Address_Book {
- public function get_entries();
- public function search_entries($pattern);
- public function add_entry($entry);
-}
-
-class Address_Book_Exception extends Exception { }
-
-class Address_Book_File implements Address_Book {
-
- const RS = "\n";
- const FS = "\t";
-
- private $fh;
- private $file;
-
- function __construct($file) {
- @mkdir(dirname($file));
- $this->fh = fopen($file, "a+b");
- flock($this->fh, LOCK_EX);
- $stat = fstat($this->fh);
- if ($stat['size'] == 0) {
- fputs($this->fh, join(self::FS, array("Hans Hanson", "0815", "hans@hanson.de"))
- . self::RS);
- }
- flock($this->fh, LOCK_SH);
- fseek($this->fh, 0, SEEK_SET);
- }
-
- function get_entries() {
- $entries = array();
- fseek($this->fh, 0, SEEK_SET);
- while($line = stream_get_line($this->fh, 0, self::RS)) {
- if ($line === FALSE) break;
- $entries[] = explode(self::FS, $line);
- }
- return $entries;
- }
-
- function add_entry($entry) {
- $fields = array('name', 'tel', 'mail');
-
- $new = array();
- foreach($fields as $key) {
- if (!isset($entry[$key])) return false;
- $new[$key] = trim($entry[$key]);
- $new[$key] = preg_replace('/['.self::RS.self::FS.' ]+/', ' ', $new[$key]);
- if (empty($new[$key])) return false;
- }
-
- flock($this->fh, LOCK_EX);
- fputs($this->fh, join(self::FS, $new) . self::RS);
- flock($this->fh, LOCK_UN);
-
- return true;
- }
-
- function search_entries($pattern) {
- $pattern = trim($pattern);
- if (empty($pattern)) return;
- //$pattern = preg_replace('/\//', '\/', $pattern);
- if (preg_match('/\//', $pattern))
- throw new Address_Book_Exception("Pattern must not contain '/'");
- fseek($this->fh, 0, SEEK_SET);
- $entries = array();
- while ($line = stream_get_line($this->fh, 0, self::RS)) {
- if ($line === FALSE) break;
- if (!preg_match("/$pattern/i", $line)) continue;
- $entry = explode(self::FS, $line);
- $entries[] = array('name' => $entry[0],
- 'tel' => $entry[1],
- 'mail' => $entry[2]);
- }
- return $entries;
- }
-}
-
-?>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/class.Address_Book_DB.php Wed Oct 26 21:44:35 2011 +0200
@@ -0,0 +1,99 @@
+<?
+require_once "interface.Address_Book.php";
+
+class Address_Book_DB implements Address_Book {
+ const INSERT_ENTRY = 'INSERT INTO data (name, tel, mail)
+ VALUES(:name, :tel, :mail)';
+ const SELECT_ENTRY = 'SELECT name AS NAME, tel AS TEL, mail AS MAIL
+ FROM data WHERE name LIKE :name
+ OR tel LIKE :tel
+ OR mail LIKE :mail';
+
+
+ private $dbh;
+
+ public function __construct($dsn, $user = null, $pass = null) {
+ $this->dbh = new PDO($dsn, $user, $pass,
+ array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
+
+ $this->dbh->exec("CREATE TABLE IF NOT EXISTS data
+ (name TEXT, tel TEXT, mail TEXT)");
+
+ $this->dbh->beginTransaction();
+
+ $sth = $this->dbh->prepare("SELECT COUNT(*) AS COUNT FROM data");
+ $sth->execute();
+ $r = $sth->fetch();
+
+ if ($r['COUNT'] == 0)
+ $this->insert(array("Hans Hanson", "0815", "hans@hanson.de"));
+ $this->dbh->commit();
+ }
+
+ private function insert($entry) {
+ static $sth = null;
+
+ if ($sth === null)
+ $sth = $this->dbh->prepare(self::INSERT_ENTRY);
+
+ $sth->execute(array("name" => $entry[0],
+ "tel" => $entry[1],
+ "mail" => $entry[2]));
+ }
+
+ public function get_all_entries() {
+ $entries = array();
+ fseek($this->fh, 0, SEEK_SET);
+ while($line = stream_get_line($this->fh, 0, self::RS)) {
+ if ($line === FALSE) break;
+ $entries[] = explode(self::FS, $line);
+ }
+ return $entries;
+ }
+
+ public function add_entry($entry) {
+ $fields = array('name', 'tel', 'mail');
+ $new = array();
+ foreach($fields as $key) {
+ if (!isset($entry[$key])) return;
+ $new[$key] = $entry[$key];
+ trim($new[$key]);
+ preg_replace('/['.self::RS.self::FS.' ]+/', ' ', $new[$key]);
+ if (empty($new[$key])) return;
+ }
+
+ flock($this->fh, LOCK_EX);
+ fputs($this->fh, join(self::FS, $new) . self::RS);
+ flock($this->fh, LOCK_UN);
+ header("Location: $_SERVER[PHP_SELF]?action=add");
+ exit;
+ }
+
+ public function search_entries($pattern) {
+ static $sth = null;
+
+ if ($sth === null)
+ $sth = $this->dbh->prepare(self::SELECT_ENTRY);
+
+ $pattern = trim($pattern);
+ if (empty($pattern)) return;
+
+ $pattern = trim($pattern, '%');
+ $pattern = "%$pattern%";
+
+ $sth->execute(array("name" => $pattern,
+ "tel" => $pattern,
+ "mail" => $pattern));
+ $entries = array();
+ while ($r = $sth->fetch()) {
+ $entries[] = array('name' => $r['NAME'],
+ 'tel' => $r['TEL'],
+ 'mail' => $r['MAIL']);
+ }
+ return $entries;
+ }
+
+ public function delete_entries($ids) { }
+}
+
+?>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/class.Address_Book_File.php Wed Oct 26 21:44:35 2011 +0200
@@ -0,0 +1,70 @@
+<?
+require_once "interface.Address_Book.php";
+
+class Address_Book_File implements Address_Book {
+ const RS = "\n";
+ const FS = "\t";
+
+ private $fh;
+ public function __construct($file) {
+ @mkdir(dirname($file));
+ $this->fh = fopen($file, "a+b");
+ if (!$this->fh) {
+ throw new Exception("Oooops, Problem mit $file");
+ }
+ flock($this->fh, LOCK_EX);
+ $stat = fstat($this->fh);
+ if ($stat['size'] == 0) {
+ fputs($this->fh, join(self::FS, array("Hans Hanson", "0815", "hans@hanson.de"))
+ . self::RS);
+ }
+ flock($this->fh, LOCK_SH);
+ fseek($this->fh, 0, SEEK_SET);
+ }
+
+ public function get_all_entries() {
+ $entries = array();
+ fseek($this->fh, 0, SEEK_SET);
+ while($line = stream_get_line($this->fh, 0, self::RS)) {
+ if ($line === FALSE) break;
+ $entries[] = explode(self::FS, $line);
+ }
+ return $entries;
+ }
+
+ public function add_entry($entry) {
+ $fields = array('name', 'tel', 'mail');
+ $new = array();
+ foreach($fields as $key) {
+ if (!isset($entry[$key])) return;
+ $new[$key] = trim($entry[$key]);
+ $new[$key] = preg_replace('/['.self::RS.self::FS.' ]+/', ' ', $new[$key]);
+ if (empty($new[$key])) return;
+ }
+
+ flock($this->fh, LOCK_EX);
+ fputs($this->fh, join(self::FS, $new) . self::RS);
+ flock($this->fh, LOCK_UN);
+ }
+
+ public function search_entries($pattern) {
+ $pattern = trim($pattern);
+ if (empty($pattern)) return array();
+ fseek($this->fh, 0, SEEK_SET);
+ $pattern = preg_replace('|/|', '\/', $pattern);
+ $entries = array();
+ while ($line = stream_get_line($this->fh, 0, self::RS)) {
+ if ($line === FALSE) break;
+ if (!preg_match("/$pattern/i", $line)) continue;
+ $entry = explode(self::FS, $line);
+ $entries[] = array('name' => $entry[0],
+ 'tel' => $entry[1],
+ 'mail' => $entry[2]);
+ }
+ return $entries;
+ }
+
+ public function delete_entries($ids) { }
+}
+
+?>
--- a/index.php Wed Oct 26 16:28:42 2011 +0200
+++ b/index.php Wed Oct 26 21:44:35 2011 +0200
@@ -1,75 +1,83 @@
-<?php
-// Template Engine
-require_once 'Twig-1.3.0/lib/Twig/Autoloader.php';
-Twig_Autoloader::register();
-$twig = new Twig_Environment(new Twig_Loader_Filesystem("templates"));
-
-const FILE = "var/abook.txt";
-
-// stop on any error!
-set_error_handler(create_function('$a, $b, $c, $d',
- 'if (error_reporting()) throw new ErrorException($b, 0, $a, $c, $d);'), -1);
-
-if (isset($_REQUEST['action'])) {
- require 'addressbook.class.php';
-
- try {
- $abook = new Address_Book_File(FILE);
-
- switch (@$_REQUEST['action']) {
- // Nach dem Eintragen bleiben wir auf der Eintragsseite,
- // aber wir verhindern Duplikate, die mit RELOAD passieren
- case 'add': if ($abook->add_entry($_REQUEST)) {
- header("Location: $_SERVER[PHP_SELF]?action=add");
- exit(0);
- }
- echo $twig->render("add.html", array());
- exit;
- break;
-
- // Suchen…
- case 'search': $entries = null;
- $error = null;
- try {
- $entries = $abook->search_entries($_REQUEST['pattern']);
- }
- catch (Address_Book_Exception $e) {
- $error = $e->getMessage();
- }
-
- if (@$_REQUEST['format'] == 'table') {
- if (is_numeric($_REQUEST['max'])) {
- $left = count($entries) - $_REQUEST['max'];
- if ($left > 0)
- $entries = array_slice($entries, 0, $_REQUEST['max']);
- else
- $left = NULL;
- }
- echo $twig->render("results.html",
- array('entries' => $entries,
- 'left' => $left, 'error' => $error));
- exit;
- }
- echo $twig->render("search.html",
- array('entries' => $entries, 'error' => $error));
- exit;
- }
- break;
-
- }
- catch (Address_Book_Exception $e) {
- header("Content-Type: text/plain; charset=utf-8");
- print "Address Book Exception: " . $e->getMessage();
- exit;
- }
- catch (Exception $e) {
- header("Content-Type: text/plain; charset=utf-8");
- print "Ohoh\n\n" . $e;
- exit;
- }
-}
-
-echo $twig->render("search.html", array());
-
-exit;
-?>
+<?php
+
+const FILE = "var/abook.txt";
+const DB = "sqlite:var/abook.sqlite";
+const ABOOK = DB;
+
+set_error_handler(create_function(
+ '$errno, $errstr, $errfile, $errline, $errcontext',
+ 'if (!error_reporting()) return;
+ throw new ErrorException($errstr, 0, $errno, $errfile, $errline);'), -1);
+
+spl_autoload_register(create_function(
+ '$class',
+ '$file = "class.$class.php";
+ if (!file_exists($file)) return;
+ require_once $file;'));
+
+require_once 'Twig-1.3.0/lib/Twig/Autoloader.php';
+Twig_Autoloader::register();
+$twig = new Twig_Environment(new Twig_Loader_Filesystem("templates"));
+
+if (isset($_REQUEST['action'])) {
+
+ try {
+ if (preg_match('/^[\w]+\//', ABOOK))
+ $abook = new Address_Book_File(FILE);
+ else
+ $abook = new Address_Book_DB(DB);
+
+ switch (@$_REQUEST['action']) {
+ // Nach dem Eintragen bleiben wir auf der Eintragsseite,
+ // aber wir verhindern Duplikate, die mit RELOAD passieren
+ case 'add': if ($abook->add_entry($_REQUEST)) {
+ header("Location: $_SERVER[PHP_SELF]?action=add");
+ exit(0);
+ }
+ echo $twig->render("add.html", array());
+ exit;
+ break;
+
+ // Suchen…
+ case 'search': $entries = null;
+ $error = null;
+ try {
+ $entries = $abook->search_entries($_REQUEST['pattern']);
+ }
+ catch (Address_Book_Exception $e) {
+ $error = $e->getMessage();
+ }
+
+ if (@$_REQUEST['format'] == 'table') {
+ if (is_numeric($_REQUEST['max'])) {
+ $left = count($entries) - $_REQUEST['max'];
+ if ($left > 0)
+ $entries = array_slice($entries, 0, $_REQUEST['max']);
+ else
+ $left = NULL;
+ }
+ echo $twig->render("results.html",
+ array('entries' => $entries,
+ 'left' => $left, 'error' => $error));
+ exit;
+ }
+ echo $twig->render("search.html",
+ array('entries' => $entries, 'error' => $error));
+ exit;
+ }
+ break;
+
+ }
+ catch (Address_Book_Exception $e) {
+ header("Content-Type: text/plain; charset=utf-8");
+ print "Address Book Exception: " . $e->getMessage();
+ exit;
+ }
+ catch (Exception $e) {
+ header("Content-Type: text/plain; charset=utf-8");
+ print "Ohoh\n\n" . $e;
+ exit;
+ }
+}
+
+echo $twig->render("search.html", array());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/interface.Address_Book.php Wed Oct 26 21:44:35 2011 +0200
@@ -0,0 +1,8 @@
+<?
+interface Address_Book {
+ function add_entry($entry);
+ function search_entries($pattern);
+ function delete_entries($ids);
+ function get_all_entries();
+}
+?>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test.php Wed Oct 26 21:44:35 2011 +0200
@@ -0,0 +1,10 @@
+<?
+$dbh = new PDO("mysql:host=localhost;dbname=abook", "hans", "x",
+ array(
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
+ ));
+
+ $dbh->exec("CREATE TABLE IF NOT EXISTS data
+ (name TEXT, tel TEXT, email TEXT)");
+
+?>