PageRenderTime 37ms CodeModel.GetById 9ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

/db/db.class.php

https://bitbucket.org/Daniel0203/openrat
PHP | 489 lines | 255 code | 95 blank | 139 comment | 10 complexity | 9e2d7918201627b98e3954e2c53987a1 MD5 | raw file
  1<?php
  2//
  3// +----------------------------------------------------------------------+
  4// | PHP version 4.0                                                      |
  5// +----------------------------------------------------------------------+
  6// | Copyright (c) 1997-2001 The PHP Group                                |
  7// +----------------------------------------------------------------------+
  8// | This source file is subject to version 2.02 of the PHP license,      |
  9// | that is bundled with this package in the file LICENSE, and is        |
 10// | available at through the world-wide-web at                           |
 11// | http://www.php.net/license/2_02.txt.                                 |
 12// | If you did not receive a copy of the PHP license and are unable to   |
 13// | obtain it through the world-wide-web, please send a note to          |
 14// | license@php.net so we can mail you a copy immediately.               |
 15// +----------------------------------------------------------------------+
 16// | Authors: Stig Bakken <ssb@fast.no>                                   |
 17// |          Jan Dankert <phpdb@jandankert.de>                           |
 18// +----------------------------------------------------------------------+
 19//
 20
 21// This is the database abstraction layer. This class was inspired by the
 22// PHP-Pear-DB package. Thanks to its developers.
 23
 24/**
 25 * Darstellung einer Datenbank-Verbindung.
 26 * F�r die echten DB-Aufrufe werden die entsprechenden
 27 * Methoden des passenden Clients aufgerufen.
 28 * 
 29 * Diese Klasse stammt urspruenglich aus dem PHP-Pear-DB-Projekt und unterliegt
 30 * daher auch der PHP-licence.
 31 * 
 32 * @author Jan Dankert
 33 * @package openrat.database
 34 */
 35class DB
 36{
 37	/**
 38	 * Datenbank-Id.
 39	 *
 40	 * @var String
 41	 */
 42	var $id;
 43	
 44	/**
 45	 * Konfiguration der Datenbank-Verbindung
 46	 *
 47	 * @var Array
 48	 */
 49	var $conf;
 50	
 51	/**
 52	 * Kennzeichen, ob die Datenbank verf�gbar ist.
 53	 *
 54	 * @var Boolean
 55	 */
 56	var $available;
 57	
 58	/**
 59	 * Enth�lt eine Fehlermeldung (sofern verf�gbar).
 60	 *
 61	 * @var String
 62	 */
 63	var $error;
 64
 65	/**
 66	 * Client.
 67	 * Enth�lt ein Objekt der Klasse db_<type>.
 68	 *
 69	 * @var Object
 70	 */
 71	var $client;
 72	
 73	/**
 74	 * Schalter, ob eine Transaktion begonnen wurde.
 75	 * @var boolean
 76	 */
 77	var $transactionInProgress = false;
 78	
 79
 80	/**
 81	 * Kontruktor.
 82	 * Erwartet die Datenbank-Konfiguration als Parameter.
 83	 *
 84	 * @param Array Konfiguration der Verbindung
 85	 * @return Status 'true' wenn Verbindung erfolgreich aufgebaut.
 86	 */
 87	public function DB( $conf )
 88	{
 89		$this->available = false;
 90		$this->conf      = $conf;
 91		
 92		$this->connect();
 93		
 94		return $this->available;
 95	}
 96	
 97
 98	/**
 99	 * Verbindung zur Datenbank aufbauen.
100	 *
101	 * @return Status
102	 */
103	public function connect()
104	{
105		// Ausfuehren des Systemkommandos vor Verbindungsaufbau
106		if	( !empty($this->conf['cmd']))
107		{
108			$ausgabe = array();
109			$rc      = false;
110
111			Logger::debug("Database command executing: ".$this->conf['cmd']);
112			exec( $this->conf['cmd'],$ausgabe,$rc );
113			
114			foreach( $ausgabe as $zeile )
115				Logger::debug("Database command output: ".$zeile);
116			
117			if	( $rc != 0 )
118			{
119				$this->error     = 'Command failed: '.implode("",$ausgabe);
120				$this->available = false; 
121				return false;
122			}
123		}
124		
125		$type = $this->conf['type'];
126		$classname = 'db_'.$type;
127		
128		if	( ! class_exists($classname) )
129		{
130			$this->error     = 'Database type "'.$type.'" is not available';
131			$this->available = false;
132			return false;
133		}
134		
135		// Client instanziieren
136		$this->client = & new $classname;
137
138		$ok = $this->client->connect( $this->conf );
139		
140		if	( ! $ok )
141		{
142			$this->error     = 'Cannot connect to database: '.$this->client->error;
143			$this->available = false;
144			return false; 
145		}
146
147				
148		// SQL nach Verbindungsaufbau ausfuehren.
149		if	( isset($this->conf['connection_sql']) &&  ! empty($this->conf['connection_sql']) )
150		{
151			$cmd = $this->conf['connection_sql'];
152			$ok = $this->client->query($cmd);
153			
154			if	( ! $ok )
155			{
156				$this->error     = $this->client->error;
157				$this->available = false;
158				return false; 
159			}
160		}
161		
162		$this->available = true;
163		return true;
164	}
165
166
167	/**
168	 * Ausfuehren einer Datenbankanfrage.
169	 *
170	 * @param SQL-Objekt
171	 * @return Object (Result)
172	 */
173	public function query( $query )
174	{
175		if ( !is_object($query) )
176			die('SQL-Query must be an object');
177			
178		// Vorbereitete Datenbankabfrage ("Prepared Statement")
179		if	( isset($this->conf['prepare']) && $this->conf['prepare'] )
180		{
181			$this->client->clear();
182			
183			// Statement an die Datenbank schicken
184			$this->client->prepare( $query->raw,$query->param );
185			
186			// Einzelne Parameter an die Anfrage binden
187			foreach ($query->param as $name=>$unused)
188				$this->client->bind($name,$this->convertCharsetToDatabase($query->data[$name]));
189			
190			// Ausf�hren...
191			$result = $this->client->query($query);
192			
193			if	( $result === FALSE )
194			{
195				$this->error = $this->client->error;
196				
197				Logger::warn('Database error: '.$this->error);
198				Http::serverError('Database Error',$this->error);
199			}
200					
201			return $result;
202		}
203		else
204		{
205			// Es handelt sich um eine nicht-vorbereitete Anfrage. Das gesamte
206			// SQL wird durch die SQL-Klasse erzeugt, dort werden auch die Parameter
207			// in die Abfrage gesetzt.
208			
209			$escape_function = method_exists($this->client,'escape')?$this->client->escape():'addslashes';
210			$flatQuery = $query->getQuery( $escape_function );
211
212			$flatQuery = $this->convertCharsetToDatabase($flatQuery);
213			
214			Logger::trace('DB query on DB '.$this->id."\n".$query->raw);
215	
216			$result = $this->client->query($flatQuery);
217			
218			if	( $result === FALSE )
219			{
220				$this->error = $this->client->error;
221				
222				if	( true )
223				{
224					Logger::warn('Database error: '.$this->error);
225					Http::serverError('Database Error',$this->error);
226				}
227			}
228	
229			if	( isset($this->conf['autocommit']) && @$this->conf['autocommit'])
230				if	( method_exists($this->client,'commit') )
231					$this->client->commit();
232			
233			return $result;
234		}
235	}
236
237
238	/**
239	 * Ermittelt genau 1 Datenbankergebnis aus einer SQL-Anfrage.
240	 * Falls es mehrere Treffer gibt, wird die 1. Spalte aus der 1. Zeile genommen.
241	 *
242	 * @param String $query
243	 * @return String
244	 */
245	public function &getOne( $query )
246	{
247		$none = '';
248		$result = $this->query($query);
249		
250		$row = $this->client->fetchRow( $result,0 );
251		$this->client->freeResult($result);
252
253		if	( ! is_array($row) )
254			return $none;
255			
256		array_walk($row,array($this,'convertCharsetFromDatabase'));
257		$keys = array_keys($row);
258		
259		return $row[ $keys[0] ];
260	}
261
262
263	/**
264	 * Ermittelt eine Zeile aus der Datenbank.
265	 *
266	 * @param String $query
267	 * @return Array
268	 */
269	public function &getRow( $query )
270	{
271		$result = $this->query($query);
272		
273		if	( $result === FALSE )
274		{
275			$this->error = $this->client->error;
276			
277			Logger::warn('Database error: '.$this->error);
278			Http::serverError('Database Error',$this->error);
279		}
280
281		$row = $this->client->fetchRow( $result,0 );
282		$this->client->freeResult($result);
283
284		if	( ! is_array($row) )
285			$row = array();
286
287			//Html::debug($row,"vorher");
288		$row = $this->convertRowWithCharsetFromDatabase($row);
289			//Html::debug($row,"nachher");
290			
291		return $row;
292	}
293
294
295	/**
296	 * Ermittelt eine (die 1.) Spalte aus dem Datenbankergebnis.
297	 *
298	 * @param String $query
299	 * @return Array
300	 */
301	public function &getCol( $query )
302	{
303		$result = $this->query($query);
304
305		$i = 0;
306		$col = array();
307		while( $row = $this->client->fetchRow( $result,$i++ ) )
308		{
309			if	( empty($row) )
310				break;
311				
312			array_walk($row,array($this,'convertCharsetFromDatabase'));
313			$keys = array_keys($row);
314			$col[] = $row[ $keys[0] ];
315		}
316			
317		$this->client->freeResult($result);
318		
319		return $col;
320	}
321
322
323	/**
324	 * Ermittelt ein assoziatives Array aus der Datenbank.
325	 *
326	 * @param String $query
327	 * @param Boolean $force_array
328	 * @return Array
329	 */
330	public function &getAssoc( $query, $force_array = false )
331	{
332		$results = array();
333		$result = $this->query($query);
334
335		$i = 0;
336		
337		while( $row = $this->client->fetchRow( $result,$i++ ) )
338		{
339			if	( empty($row) )
340				break;
341
342			array_walk($row,array($this,'convertCharsetFromDatabase'));
343				
344			if	( count($row) > 2 || $force_array )
345			{
346				// FIXME: Wird offenbar nie ausgeführt.
347				$row = $res->fetchRow($i);
348
349				$keys = array_keys($row);
350				$key1 = $keys[0];
351
352				unset( $row[$key1] );
353				$results[ $row[$key1] ] = $row;
354			}
355			else
356			{
357				$keys = array_keys($row);
358				$key1 = $keys[0];
359				$key2 = $keys[1];
360
361				$results[ $row[$key1] ] = $row[$key2];
362			}
363		}
364
365		$this->client->freeResult( $result );
366
367		return $results;
368	}
369
370
371	/**
372	 * Ermittelt alle Datenbankergebniszeilen.
373	 *
374	 * @param String $query
375	 * @return Array
376	 */
377	public function &getAll( $query )
378	{
379		$result = $this->query( $query );
380
381		$results = array();
382		$i = 0;
383
384		while( $row = $this->client->fetchRow( $result,$i++ ) )
385		{
386			array_walk($row,array($this,'convertCharsetFromDatabase'));
387			$results[] = $row;
388		}
389
390		$this->client->freeResult( $result );
391		
392		return $results;
393	}
394	
395	
396	/**
397	 * Startet eine Transaktion.
398	 */
399	public function start()
400	{
401		if	( @$this->conf['transaction'])
402			if	( method_exists($this->client,'start') )
403			{
404				$this->transactionInProgress = true;
405				$this->client->start();
406			}
407	}
408	
409	
410	/**
411	 * Beendet und best�tigt eine Transaktion.
412	 */
413	public function commit()
414	{
415		if	( @$this->conf['transaction'])
416			if	( method_exists($this->client,'commit') )
417				if	( $this->transactionInProgress )
418				{
419					$this->client->commit();
420					$this->transactionInProgress = false;
421				}
422	}
423	
424	/**
425	 * Setzt eine Transaktion zur�ck.
426	 */
427	public function rollback()
428	{
429		if	( @$this->conf['transaction'])
430			if	( method_exists($this->client,'rollback') )
431				if	( $this->transactionInProgress )
432				{
433					$this->client->rollback();
434					$this->transactionInProgress = false;
435				}
436	}
437	
438	
439	private function convertCharsetToDatabase($text)
440	{
441		//Logger::debug('from '.$text);
442		$dbCharset = @$this->conf['charset'];
443		if	( !empty($dbCharset) && $dbCharset != 'UTF-8' )
444		{
445		//	Logger::debug('Converting from UTF-8 to '.$dbCharset);
446			if	( !function_exists('iconv') )
447				Logger::warn('iconv not available - database charset unchanged. Please '.
448				             'enable iconv on your system or transform your database content to UTF-8.');
449			else
450				$text = iconv('UTF-8',$dbCharset.'//TRANSLIT',$text);
451		}
452		//Logger::debug('to   '.$text);
453		return $text;
454		
455	}
456	
457	
458	private function convertCharsetFromDatabase($text)
459	{
460		//Logger::debug('from '.$text);
461		$dbCharset = @$this->conf['charset'];
462		if	( !empty($dbCharset) && $dbCharset != 'UTF-8' )
463		{
464			//Logger::debug('Converting to UTF-8 from '.$dbCharset);
465			if	( !function_exists('iconv') )
466				Logger::warn('iconv not available - database charset unchanged. Please '.
467				             'enable iconv on your system or transform your database content to UTF-8.');
468			else
469				$text = iconv($dbCharset,'UTF-8//TRANSLIT',$text);
470		}
471		//Logger::debug('to   '.$text);
472		return $text;
473		
474	}
475	
476	
477	private function convertRowWithCharsetFromDatabase($row)
478	{
479		foreach( $row as $key=>$value)
480		{
481			$row[$key] = $this->convertCharsetFromDatabase($row[$key]);
482		}
483		return $row;
484	}
485	
486}
487
488
489?>