From tuxsoul en gmail.com Thu Feb 2 14:27:56 2006 From: tuxsoul en gmail.com (Mario Oyorzabal Salgado) Date: Tue Aug 15 11:27:11 2006 Subject: [Ofrenda-svn] r24 - in trunk/ofrenda-galaxy: . html/incluidos/magpierss html/incluidos/magpierss/extlib Message-ID: <20060202212756.A265A1B6598@kolax.provo.novell.com> Author: tuxsoul Date: 2006-02-02 14:27:55 -0700 (Thu, 02 Feb 2006) New Revision: 24 Modified: trunk/ofrenda-galaxy/CHANGELOG trunk/ofrenda-galaxy/html/incluidos/magpierss/CHANGES trunk/ofrenda-galaxy/html/incluidos/magpierss/ChangeLog trunk/ofrenda-galaxy/html/incluidos/magpierss/extlib/Snoopy.class.inc trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_cache.inc trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_fetch.inc trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_parse.inc Log: Galaxy: Actualizacion de Magpierss a la version 0.72 Modified: trunk/ofrenda-galaxy/CHANGELOG =================================================================== --- trunk/ofrenda-galaxy/CHANGELOG 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/CHANGELOG 2006-02-02 21:27:55 UTC (rev 24) @@ -6,17 +6,23 @@ -------------------------------------------------------------------------------- ******************************************************************************** +Versión 0.1.2 Beta - 2006-02-02 +******************************************************************************** +- Actualización de la librería de Magpierss de la versión 0.7 a la 0.72. + Para resolver un bug's. + + +******************************************************************************** Versión 0.1 Beta - 2005-11-16 ******************************************************************************** +- Primera versión de Ofrenda. +- Administración via web. + - usuarios (feed's). + - administradores. +- Imagenes de usuarios usando Gravata. + +- Actualización mediante cron. -** Primera versión de Ofrenda. - * Administración via web. - - usuarios (feed's). - - administradores. - * Imagenes de usuarios usando Gravata. - http://www.gravatar.com - * Actualización mediante cron. - -------------------------------------------------------------------------------- Ofrenda @ 2004. Mario Oyorzabal Salgado Modified: trunk/ofrenda-galaxy/html/incluidos/magpierss/CHANGES =================================================================== --- trunk/ofrenda-galaxy/html/incluidos/magpierss/CHANGES 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/html/incluidos/magpierss/CHANGES 2006-02-02 21:27:55 UTC (rev 24) @@ -1,3 +1,7 @@ +Version 0.72 +----------- + - fix security exploit: http://www.sec-consult.com/216.html + Version 0.7 ----------- - support for input and output charset encoding Modified: trunk/ofrenda-galaxy/html/incluidos/magpierss/ChangeLog =================================================================== --- trunk/ofrenda-galaxy/html/incluidos/magpierss/ChangeLog 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/html/incluidos/magpierss/ChangeLog 2006-02-02 21:27:55 UTC (rev 24) @@ -1,70 +1,129 @@ -2004-11-21 22:45 kellan +2005-10-28 14:11 kellan + * extlib/Snoopy.class.inc: a better solution + +2005-10-28 11:51 kellan + + * extlib/Snoopy.class.inc: fix arbtriary code execution + vulnerability when using curl+ssl + + http://www.sec-consult.com/216.html + +2005-03-08 10:46 kellan + + * rss_parse.inc: fix bug w/ atom and date normalization + +2005-02-09 14:59 kellan + + * rss_fetch.inc: fix stale cache bug + +2005-01-28 02:27 kellan + + * rss_parse.inc: support php w/o array_change_case + +2005-01-23 20:02 kellan + + * rss_fetch.inc: fix cache bug introduced by charset encoding + +2005-01-12 09:14 kellan + + * rss_cache.inc, rss_fetch.inc: more sanity checks for when things + go wrong + +2004-12-12 13:44 kellan + + * INSTALL, rss_cache.inc, rss_utils.inc: detab + +2004-11-23 20:15 kellan + + * rss_parse.inc: fix calling iconv instead of mb_convert_encoding + +2004-11-22 02:11 kellan + + * CHANGES, ChangeLog, rss_parse.inc, scripts/magpie_debug.php: last + bit of tidying + +2004-11-22 01:45 kellan + * rss_fetch.inc: detab, bump version -2004-11-21 20:52 kellan +2004-11-22 01:43 kellan + * rss_parse.inc: was filtering too much + +2004-11-22 00:03 kellan + * rss_fetch.inc, rss_parse.inc: cache on $url . $output_encoding otherwise we can get munged output + +2004-11-21 23:52 kellan + + * rss_parse.inc: add WARNING + +2004-11-21 23:45 kellan + * rss_parse.inc: don't set ERROR on notice or warning (rss_fetch dies on parse errors) + +2004-11-21 23:44 kellan + * rss_fetch.inc: add encoding defines (fix timeout error reporting) -2004-11-21 17:21 kellan +2004-11-21 20:21 kellan * rss_parse.inc: incorporate steve's patch -2004-11-21 16:26 kellan +2004-11-21 19:26 kellan * rss_parse.inc: remove old debugging functions, totally arbitrarily. might break stuff. can't really explain why i'm doing this. -2004-10-28 12:52 kellan +2004-10-28 15:52 kellan * rss_parse.inc: fixed '=' instead of '==' -2004-10-25 21:48 kellan +2004-10-26 00:48 kellan * rss_parse.inc: chance epoch to timestamp to conform w/ php naming conventions -2004-06-15 09:00 kellan +2004-06-15 12:00 kellan * rss_parse.inc: [no log message] -2004-04-26 11:16 kellan +2004-04-26 14:16 kellan * rss_fetch.inc: bump version -2004-04-26 09:36 kellan +2004-04-26 12:36 kellan * rss_parse.inc: fix field doubling -2004-04-24 14:47 kellan +2004-04-24 17:47 kellan * CHANGES, ChangeLog: updated -2004-04-24 14:35 kellan +2004-04-24 17:35 kellan * rss_fetch.inc: bumped version -2004-04-24 13:52 kellan +2004-04-24 16:52 kellan * rss_parse.inc: support arbitrary atom content constructs some refactoring -2004-04-24 13:15 kellan +2004-04-24 16:15 kellan * rss_parse.inc: support summary content contstruct. add normalize function -2004-03-27 13:29 kellan +2004-03-27 16:29 kellan * extlib/Snoopy.class.inc: accept self-signed certs -2004-03-27 09:53 kellan +2004-03-27 12:53 kellan * extlib/Snoopy.class.inc: fixed SSL support * set status * set error on bad curl @@ -72,123 +131,123 @@ (also ripped out big chunks of dead weight (submit_form) which were getting in my way -2004-01-24 23:25 kellan +2004-01-25 02:25 kellan * rss_parse.inc: make RSS 1.0's rdf:about available -2004-01-24 23:07 kellan +2004-01-25 02:07 kellan * rss_parse.inc: clean up text, and line formats. add support item rdf:about -2004-01-24 20:40 kellan +2004-01-24 23:40 kellan * CHANGES, ChangeLog: update changes -2004-01-24 20:37 kellan +2004-01-24 23:37 kellan * rss_fetch.inc: updated version -2004-01-24 20:35 kellan +2004-01-24 23:35 kellan * rss_parse.inc: whitespace -2004-01-24 20:23 kellan +2004-01-24 23:23 kellan * extlib/Snoopy.class.inc: support badly formatted http headers -2004-01-24 20:20 kellan +2004-01-24 23:20 kellan * rss_parse.inc: added alpha atom parsing support -2003-06-25 19:34 kellan +2003-06-25 22:34 kellan * extlib/Snoopy.class.inc: fixed fread 4.3.2 compatibility problems -2003-06-13 08:31 kellan +2003-06-13 11:31 kellan * rss_fetch.inc: reset cache on 304 -2003-06-12 18:37 kellan +2003-06-12 21:37 kellan * rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: bumped up version numbers -2003-06-12 18:32 kellan +2003-06-12 21:32 kellan * htdocs/index.html: updated news -2003-06-12 18:27 kellan +2003-06-12 21:27 kellan * NEWS: a manual blog :) -2003-06-12 18:22 kellan +2003-06-12 21:22 kellan * htdocs/index.html: fully qualified img -2003-06-12 18:20 kellan +2003-06-12 21:20 kellan * htdocs/index.html: clean up. added badge. -2003-06-12 18:04 kellan +2003-06-12 21:04 kellan * rss_utils.inc: clean up regex -2003-06-12 18:02 kellan +2003-06-12 21:02 kellan * rss_cache.inc: suppress some warnings -2003-05-30 17:44 kellan +2003-05-30 20:44 kellan * extlib/Snoopy.class.inc: more comments, cleaned up notice -2003-05-30 12:14 kellan +2003-05-30 15:14 kellan * extlib/Snoopy.class.inc: don't advertise gzip support if the user hasn't built php with gzinflate support -2003-05-12 19:32 kellan +2003-05-12 22:32 kellan * ChangeLog: changes -2003-05-12 19:11 kellan +2003-05-12 22:11 kellan * htdocs/index.html: announce 0.5 -2003-05-12 18:42 kellan +2003-05-12 21:42 kellan * htdocs/index.html: change -2003-05-12 18:39 kellan +2003-05-12 21:39 kellan * rss_fetch.inc: use gzip -2003-05-12 18:37 kellan +2003-05-12 21:37 kellan * extlib/Snoopy.class.inc: added support gzip encoded content negoiation -2003-05-12 18:32 kellan +2003-05-12 21:32 kellan * rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: fixed typoes -2003-04-26 18:44 kellan +2003-04-26 21:44 kellan * rss_parse.inc: fix minor typo -2003-04-18 05:19 kellan +2003-04-18 08:19 kellan * htdocs/cookbook.html: updated cookbook to show more code for limiting items -2003-03-03 13:02 kellan +2003-03-03 16:02 kellan * rss_parse.inc, scripts/magpie_slashbox.php: committed (or adpated) patch from Nicola (www.technick.com) to quell 'Undefined Indexes' notices -2003-03-03 12:59 kellan +2003-03-03 15:59 kellan * rss_fetch.inc: commited patch from nicola (www.technick.com) to quell 'undefined indexes' notices. @@ -196,61 +255,61 @@ * Magpie now automatically includes its version in the user-agent, & whether cacheing is turned on. -2003-02-11 22:22 kellan +2003-02-12 01:22 kellan * CHANGES, ChangeLog: ChangeLog now auto-generated by cvs2cl -2003-02-11 21:21 kellan +2003-02-12 00:21 kellan * rss_fetch.inc: better errors, hopefully stomped on pesky notices -2003-02-11 21:19 kellan +2003-02-12 00:19 kellan * rss_parse.inc: check to see is xml is supported, if not die also throw better xml errors -2003-02-11 21:18 kellan +2003-02-12 00:18 kellan * rss_cache.inc: hopefully cleared up some notices that were being thrown into the log fixed a debug statement that was being called as an error -2003-02-11 21:15 kellan +2003-02-12 00:15 kellan * scripts/: magpie_simple.php, magpie_slashbox.php: moved magpie_simple to magpie_slashbox, and replaced it with a simpler demo. -2003-02-11 21:02 kellan +2003-02-12 00:02 kellan * INSTALL, README, TROUBLESHOOTING: Improved documentation. Better install instructions. TROUBLESHOOTING cover common installation and usage problems -2003-01-22 11:40 kellan +2003-01-22 14:40 kellan * htdocs/cookbook.html: added cookbook.html -2003-01-21 20:47 kellan +2003-01-21 23:47 kellan * cookbook: a magpie cookbook -2003-01-20 07:09 kellan +2003-01-20 10:09 kellan * ChangeLog: updated -2003-01-20 06:23 kellan +2003-01-20 09:23 kellan * scripts/simple_smarty.php: minor clean up -2003-01-20 06:15 kellan +2003-01-20 09:15 kellan * scripts/README: added smarty url -2003-01-20 06:14 kellan +2003-01-20 09:14 kellan * magpie_simple.php, htdocs/index.html, scripts/README, scripts/magpie_debug.php, scripts/magpie_simple.php, @@ -265,7 +324,7 @@ smarty_plugin/modifier.rss_date_parse.php - support file for the smarty demo templates/simple.smary - template for the smarty demo -2003-01-20 06:11 kellan +2003-01-20 09:11 kellan * rss_fetch.inc, rss_parse.inc: changes to error handling to give script authors more access to magpie's errors. @@ -273,24 +332,24 @@ added method magpie_error() to retrieve global MAGPIE_ERROR variable for when fetch_rss() returns false -2002-10-26 16:02 kellan +2002-10-26 19:02 kellan * htdocs/index.html: putting the website under source control -2002-10-26 15:43 kellan +2002-10-26 18:43 kellan * AUTHORS, ChangeLog, INSTALL, README: some documentation to make it all look official :) -2002-10-25 20:04 kellan +2002-10-25 23:04 kellan * magpie_simple.php: quxx -2002-10-25 20:04 kellan +2002-10-25 23:04 kellan * rss_parse.inc: added support for textinput and image -2002-10-25 16:23 kellan +2002-10-25 19:23 kellan * magpie_simple.php, rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: switched to using Snoopy for fetching remote RSS @@ -298,18 +357,18 @@ added support for conditional gets -2002-10-25 16:22 kellan +2002-10-25 19:22 kellan * rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: Change comment style to slavishly imitate the phpinsider style found in Smarty and Snoopy :) -2002-10-25 16:18 kellan +2002-10-25 19:18 kellan * extlib/Snoopy.class.inc: added Snoopy in order to support conditional gets -2002-10-23 20:19 kellan +2002-10-23 23:19 kellan * magpie_simple.php, rss_cache.inc, rss_fetch.inc, rss_parse.inc: MAJOR CLEANUP! @@ -334,12 +393,12 @@ * rss_parse properly handles xml parse errors. used to sail along blithely unaware. -2002-09-11 08:11 kellan +2002-09-11 11:11 kellan * rss_cache.inc, rss_parse.inc, magpie_simple.php, rss_fetch.inc, rss_utils.inc: Initial revision -2002-09-11 08:11 kellan +2002-09-11 11:11 kellan * rss_cache.inc, rss_parse.inc, magpie_simple.php, rss_fetch.inc, rss_utils.inc: initial import Modified: trunk/ofrenda-galaxy/html/incluidos/magpierss/extlib/Snoopy.class.inc =================================================================== --- trunk/ofrenda-galaxy/html/incluidos/magpierss/extlib/Snoopy.class.inc 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/html/incluidos/magpierss/extlib/Snoopy.class.inc 2006-02-02 21:27:55 UTC (rev 24) @@ -639,9 +639,10 @@ if(!empty($this->user) || !empty($this->pass)) $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass); - for($curr_header = 0; $curr_header < count($headers); $curr_header++) + for($curr_header = 0; $curr_header < count($headers); $curr_header++) { $cmdline_params .= " -H \"".$headers[$curr_header]."\""; - + } + if(!empty($body)) $cmdline_params .= " -d \"$body\""; @@ -651,8 +652,8 @@ $headerfile = uniqid(time()); # accept self-signed certs - $cmdline_params .= " -k"; - exec($this->curl_path." -D \"/tmp/$headerfile\"".$cmdline_params." ".$URI,$results,$return); + $cmdline_params .= " -k"; + exec($this->curl_path." -D \"/tmp/$headerfile\"".escapeshellcmd($cmdline_params)." ".escapeshellcmd($URI),$results,$return); if($return) { Modified: trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_cache.inc =================================================================== --- trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_cache.inc 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_cache.inc 2006-02-02 21:27:55 UTC (rev 24) @@ -93,10 +93,14 @@ return 0; } - $data = fread( $fp, filesize($cache_file) ); - $rss = $this->unserialize( $data ); + if ($filesize = filesize($cache_file) ) { + $data = fread( $fp, filesize($cache_file) ); + $rss = $this->unserialize( $data ); - return $rss; + return $rss; + } + + return 0; } /*=======================================================================*\ @@ -130,6 +134,18 @@ } } + function cache_age( $cache_key ) { + $filename = $this->file_name( $url ); + if ( file_exists( $filename ) ) { + $mtime = filemtime( $filename ); + $age = time() - $mtime; + return $age; + } + else { + return -1; + } + } + /*=======================================================================*\ Function: serialize \*=======================================================================*/ Modified: trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_fetch.inc =================================================================== --- trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_fetch.inc 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_fetch.inc 2006-02-02 21:27:55 UTC (rev 24) @@ -81,7 +81,7 @@ version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off) \*=======================================================================*/ -define('MAGPIE_VERSION', '0.7'); +define('MAGPIE_VERSION', '0.72'); $MAGPIE_ERROR = ""; @@ -134,7 +134,7 @@ // return cache HIT, MISS, or STALE $cache_status = $cache->check_cache( $cache_key); } - + // if object cached, and cache is fresh, return cached obj if ( $cache_status == 'HIT' ) { $rss = $cache->get( $cache_key ); @@ -142,8 +142,8 @@ // should be cache age $rss->from_cache = 1; if ( MAGPIE_DEBUG > 1) { - debug("MagpieRSS: Cache HIT", E_USER_NOTICE); - } + debug("MagpieRSS: Cache HIT", E_USER_NOTICE); + } return $rss; } } @@ -162,7 +162,7 @@ $resp = _fetch_remote_file( $url, $request_headers ); if (isset($resp) and $resp) { - if ($resp->status == '304' ) { + if ($resp->status == '304' ) { // we have the most current copy if ( MAGPIE_DEBUG > 1) { debug("Got 304 for $url"); Modified: trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_parse.inc =================================================================== --- trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_parse.inc 2006-01-29 23:43:50 UTC (rev 23) +++ trunk/ofrenda-galaxy/html/incluidos/magpierss/rss_parse.inc 2006-02-02 21:27:55 UTC (rev 24) @@ -60,7 +60,6 @@ var $incontent = false; // if in Atom field var $intextinput = false; var $inimage = false; - var $current_field = ''; var $current_namespace = false; @@ -259,7 +258,6 @@ function feed_cdata ($p, $text) { - if ($this->feed_type == ATOM and $this->incontent) { $this->append_content( $text ); @@ -391,7 +389,7 @@ $atom_date = (isset($item['issued']) ) ? $item['issued'] : $item['modified']; if ( $atom_date ) { - $epoch = @parse_w3cdtf($item['modified']); + $epoch = @parse_w3cdtf($atom_date); if ($epoch and $epoch > 0) { $item['date_timestamp'] = $epoch; } @@ -560,7 +558,7 @@ function error ($errormsg, $lvl=E_USER_WARNING) { // append PHP's error message if track_errors enabled - if ( $php_errormsg ) { + if ( isset($php_errormsg) ) { $errormsg .= " ($php_errormsg)"; } if ( MAGPIE_DEBUG ) { @@ -585,5 +583,23 @@ return "$k=\"$v\""; } +// patch to support medieval versions of PHP4.1.x, +// courtesy, Ryan Currie, ryan@digibliss.com +if (!function_exists('array_change_key_case')) { + define("CASE_UPPER",1); + define("CASE_LOWER",0); + + + function array_change_key_case($array,$case=CASE_LOWER) { + if ($case=CASE_LOWER) $cmd=strtolower; + elseif ($case=CASE_UPPER) $cmd=strtoupper; + foreach($array as $key=>$value) { + $output[$cmd($key)]=$value; + } + return $output; + } + +} + ?> From tuxsoul en gmail.com Mon Feb 13 17:44:05 2006 From: tuxsoul en gmail.com (Mario Oyorzabal Salgado) Date: Tue Aug 15 11:27:12 2006 Subject: [Ofrenda-svn] r25 - in tags/ofrenda-rpc_ping: . codigo codigo/xml docs Message-ID: <20060214004405.BDB281B659A@kolax.provo.novell.com> Author: tuxsoul Date: 2006-02-13 17:44:04 -0700 (Mon, 13 Feb 2006) New Revision: 25 Added: tags/ofrenda-rpc_ping/codigo/ tags/ofrenda-rpc_ping/codigo/config.php tags/ofrenda-rpc_ping/codigo/core.php tags/ofrenda-rpc_ping/codigo/index.html tags/ofrenda-rpc_ping/codigo/ping.php tags/ofrenda-rpc_ping/codigo/servidores.php tags/ofrenda-rpc_ping/codigo/xml/ tags/ofrenda-rpc_ping/codigo/xml/index.html tags/ofrenda-rpc_ping/codigo/xml/msg_xml_data.xml tags/ofrenda-rpc_ping/codigo/xml/msg_xml_header.xml tags/ofrenda-rpc_ping/docs/ tags/ofrenda-rpc_ping/docs/README tags/ofrenda-rpc_ping/docs/lista-servidores.txt Removed: tags/ofrenda-rpc_ping/codigo/db.php tags/ofrenda-rpc_ping/codigo/msg_xml_data.inc tags/ofrenda-rpc_ping/codigo/msg_xml_header.inc tags/ofrenda-rpc_ping/codigo/mysql.php tags/ofrenda-rpc_ping/codigo/ping.php tags/ofrenda-rpc_ping/docs/ofrenda-data.sql tags/ofrenda-rpc_ping/docs/ofrenda-lista_servidores.txt tags/ofrenda-rpc_ping/docs/ofrenda-rpc_ping.sql tags/ofrenda-rpc_ping/ping/ tags/ofrenda-rpc_ping/sql/ Modified: tags/ofrenda-rpc_ping/CHANGELOG tags/ofrenda-rpc_ping/INSTALL tags/ofrenda-rpc_ping/README Log: frenda-Core: Rpc-Ping reescrito version 0.1.1b Modified: tags/ofrenda-rpc_ping/CHANGELOG =================================================================== --- tags/ofrenda-rpc_ping/CHANGELOG 2006-02-02 21:27:55 UTC (rev 24) +++ tags/ofrenda-rpc_ping/CHANGELOG 2006-02-14 00:44:04 UTC (rev 25) @@ -1,11 +1,19 @@ REGISTRO DE CAMBIOS -------------------------------------------------------------------------------- -Ofrenda @ 2004. +Ofrenda @ 2004 - 2006. Mario Oyorzabal Salgado http://www.ofrenda.com.mx -------------------------------------------------------------------------------- ******************************************************************************** +Versión 0.1.1b: 13-Febrero-2006 +******************************************************************************** +- Quitado el soporte de MySQL. +- La lista de servidores se maneja ahora mediante el archivo "servidores.php" +- La configuración mediante el archivo "config.php" +- Se ha reescrito el código usando orientación a objetos. + +******************************************************************************** Versión 0.1b: 28-Enero-2006 ******************************************************************************** - Tiene una lista de 39 servidores para enviar ping. @@ -13,7 +21,7 @@ - Se puede conectar a MySQL. -------------------------------------------------------------------------------- -Ofrenda @ 2004. +Ofrenda @ 2004 - 2006. Mario Oyorzabal Salgado http://www.ofrenda.com.mx -------------------------------------------------------------------------------- Modified: tags/ofrenda-rpc_ping/INSTALL =================================================================== --- tags/ofrenda-rpc_ping/INSTALL 2006-02-02 21:27:55 UTC (rev 24) +++ tags/ofrenda-rpc_ping/INSTALL 2006-02-14 00:44:04 UTC (rev 25) @@ -1,6 +1,6 @@ INSTALACIÓN -------------------------------------------------------------------------------- -Ofrenda @ 2004. +Ofrenda @ 2004 - 2006. Mario Oyorzabal Salgado http://www.ofrenda.com.mx -------------------------------------------------------------------------------- @@ -32,7 +32,7 @@ webmasters de estos servidores bloquen o dejen de dar este servicio gratuito. -------------------------------------------------------------------------------- -Ofrenda @ 2004. +Ofrenda @ 2004 - 2006. Mario Oyorzabal Salgado http://www.ofrenda.com.mx -------------------------------------------------------------------------------- Modified: tags/ofrenda-rpc_ping/README =================================================================== --- tags/ofrenda-rpc_ping/README 2006-02-02 21:27:55 UTC (rev 24) +++ tags/ofrenda-rpc_ping/README 2006-02-14 00:44:04 UTC (rev 25) @@ -1,6 +1,6 @@ LEEME -------------------------------------------------------------------------------- -Ofrenda @ 2004. +Ofrenda @ 2004 - 2006. Mario Oyorzabal Salgado http://www.ofrenda.com.mx -------------------------------------------------------------------------------- @@ -33,7 +33,7 @@ ofrenda-galaxy y posiblemente ofrenda-shop. -------------------------------------------------------------------------------- -Ofrenda @ 2004. +Ofrenda @ 2004 - 2006. Mario Oyorzabal Salgado http://www.ofrenda.com.mx -------------------------------------------------------------------------------- Copied: tags/ofrenda-rpc_ping/codigo (from rev 20, tags/ofrenda-rpc_ping/ping) Copied: tags/ofrenda-rpc_ping/codigo/config.php (from rev 22, tags/ofrenda-rpc_ping/ping/db.php) =================================================================== --- tags/ofrenda-rpc_ping/ping/db.php 2006-01-29 23:10:35 UTC (rev 22) +++ tags/ofrenda-rpc_ping/codigo/config.php 2006-02-14 00:44:04 UTC (rev 25) @@ -0,0 +1,36 @@ + */ +/* http://www.ofrenda.com.mx */ +/******************************************************************************/ + +class OfrendaConfig +{ + function OfrendaConfig ( $name, $url ) + { + // establece modo debug para ver mas informacion del proceso + define ( DEBUG, false ); + + // url y nombre de la pagina + $ofrenda['site']['name'] = $name; + $ofrenda['site']['url'] = $url; + + // lista de servidores + $ofrenda['servers']['file'] = 'servidores.php'; + + // configuracion de informacion xml + $ofrenda['xml']['path'] = 'xml'; + $ofrenda['xml']['header'] = 'msg_xml_header.xml'; + $ofrenda['xml']['data'] = 'msg_xml_data.xml'; + + // informacion rpc + $ofrenda['rpc']['agente'] = 'Ofrenda XML-RPC ' . OFRENDA_VERSION; + $ofrenda['rpc']['cliente'] = 'Ofrenda XML-RPC Client ' . OFRENDA_VERSION; + + return $ofrenda; + } +}; + +?> Added: tags/ofrenda-rpc_ping/codigo/core.php =================================================================== --- tags/ofrenda-rpc_ping/ping/core.php 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/core.php 2006-02-14 00:44:04 UTC (rev 25) @@ -0,0 +1,128 @@ + */ +/* http://www.ofrenda.com.mx */ +/******************************************************************************/ + +// se establece la version del codigo +define ( 'OFRENDA_VERSION', '0.1.1b' ); + +// se define la ruta de ejecucion +define ( 'OFRENDA_PATH', dirname ( __FILE__ ) . '/' ); + +// archivo de configuracion +include ( OFRENDA_PATH . 'config.php' ); + +class OfrendaPing extends OfrendaConfig +{ + var $ofrenda; + + function OfrendaPing ( $name, $url ) + { + // FIXME: Falta un parseo a $name y $url para validarlos + // de lo contrario terminar la ejecucion mediante un exit(); + $ofrenda = OfrendaConfig::OfrendaConfig ( $name, $url ); + + // se carga el archivo lista de servidores + require ( OFRENDA_PATH . $ofrenda['servers']['file'] ); + + $this->ofrenda = $ofrenda; + } + + function Ping () + { + $data = $this->CargaMensajeXML ( $this->ofrenda['xml']['data'] ); + $data = $this->LlenarDatosXML ( $data ); + + $header = $this->CargaMensajeXML ( $this->ofrenda['xml']['header'] ); + $header = $this->LlenarHeaderXML ( $header, strlen ( $data ) ); + + echo " Ofrenda RPC-PING version: " . OFRENDA_VERSION; + echo " \n Blog " . $this->ofrenda['site']['name'] . " : " . $this->ofrenda['site']['url'] . "\n"; + $this->SendPing ( $header, $data ); + } + + function CargaMensajeXML ( $file ) + { + $xml['path'] = OFRENDA_PATH . $this->ofrenda['xml']['path'] . '/'; + + // mensaje xml + if ( file_exists ( $xml['path'] . $file ) ) + { + $xml['file'] = fopen ( $xml['path'] . $file, "r" ); + $xml['data'] = fread ( $xml['file'], filesize ( $xml['path'] . $file ) ); + // es un detalle poner "\n" entre comillas ya que no tiene el mismo + // efecto que solo poniendolo en apostrofes, de lo contrario imprime \n + $xml['data'] .= "\n"; + fclose ( $xml['file'] ); + return $xml['data']; + } + else + { + echo " No existe el archivo: " . $file . "\n"; + echo " Ruta: " . $xml['path'] . "\n"; + exit(1); + } + } + + function LlenarHeaderXML ( $data, $size ) + { + $size = (int) $size; + $size = (string) $size; + + // se reemplaza etiqueta de agente del header xml + $data = eregi_replace ( "{AGENTE}", $this->ofrenda['rpc']['agente'], $data ); + // se reemplaza etiqueta de host:cliente del header xml + $data = eregi_replace ( "{HOST_CLIENTE}", $this->ofrenda['rpc']['cliente'], $data ); + // se reemplaza etiqueta de longitud del mensaje + $data = eregi_replace ( "{LONGITUD}", $size, $data ); + + return $data; + } + + function LlenarDatosXML ( $data ) + { + // se reemplazan los datos que faltan de los archivo xml + $data = eregi_replace ( "{BLOG_NOMBRE}", $this->ofrenda['site']['name'], $data ); + $data = eregi_replace ( "{BLOG_URL}", $this->ofrenda['site']['url'], $data ); + + return $data; + } + + function SendPing ( $header, $data ) + { + foreach ( $this->ofrenda['servers']['list'] as $server ) + { + // se reemplaza etiquete de host:servidor del header xml + $temp = eregi_replace ( "{HOST_SERVIDOR}", $server, $header); + + // para saber que se envia + if ( DEBUG ) + echo $temp . $data . "\n"; + else + { + echo " \n Servidor: " . $server . " Estatus : "; + + // se manda el ping + $host = parse_url ( $server ); + $ping = @fsockopen ( $host['host'], 80, $errno, $errstr, 15 ); + + if ( !$ping ) + echo $errno . "\n" . $errstr; + else + { + fputs ( $ping, $temp . $data ); + fclose ( $ping ); + } + + echo " DONE "; + } + } + + echo "\n"; + } +}; + +?> Deleted: tags/ofrenda-rpc_ping/codigo/db.php =================================================================== --- tags/ofrenda-rpc_ping/ping/db.php 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/db.php 2006-02-14 00:44:04 UTC (rev 25) @@ -1,20 +0,0 @@ - - * http://www.ofrenda.com.mx - */ - - $ofrenda['db']['host'] = 'localhost'; // direccion de la bd - $ofrenda['db']['name'] = 'ofrenda_ping'; // nombre de la bd - $ofrenda['db']['user'] = 'root'; // usuario de la bd - $ofrenda['db']['pass'] = 'root'; // password de acceso a la bd - - // url del blog - $ofrenda['blog']['nombre'] = 'Ofrenda'; - $ofrenda['blog']['url'] = 'http://www.ofrenda.com.mx'; - - // tabla de sitios - $ofrenda['db']['ping'] = 'rpc_ping_url'; - -?> Added: tags/ofrenda-rpc_ping/codigo/index.html =================================================================== Deleted: tags/ofrenda-rpc_ping/codigo/msg_xml_data.inc =================================================================== --- tags/ofrenda-rpc_ping/ping/msg_xml_data.inc 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/msg_xml_data.inc 2006-02-14 00:44:04 UTC (rev 25) @@ -1,8 +0,0 @@ - - - weblogUpdates.ping - - {BLOG_NOMBRE} - {BLOG_URL} - - Deleted: tags/ofrenda-rpc_ping/codigo/msg_xml_header.inc =================================================================== --- tags/ofrenda-rpc_ping/ping/msg_xml_header.inc 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/msg_xml_header.inc 2006-02-14 00:44:04 UTC (rev 25) @@ -1,5 +0,0 @@ -POST {HOST_SERVIDOR} HTTP/1.0 -User-Agent: {AGENTE} -Host: {HOST_CLIENTE} -Content-Type: text/xml -Content-Length: {LONGITUD} Deleted: tags/ofrenda-rpc_ping/codigo/mysql.php =================================================================== --- tags/ofrenda-rpc_ping/ping/mysql.php 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/mysql.php 2006-02-14 00:44:04 UTC (rev 25) @@ -1,36 +0,0 @@ - - * http://www.ofrenda.com.mx - */ - - // conecta a la base de datos - function db_conectar ( &$link ) - { - $link = mysql_connect( $GLOBALS['ofrenda']['db']['host'], - $GLOBALS['ofrenda']['db']['user'], - $GLOBALS['ofrenda']['db']['pass'] - ) - or die ( " \n No puedo conectarme: " . mysql_error () . "\n"); - - if( $link ){ - mysql_select_db ( $GLOBALS['ofrenda']['db']['name'], $link ); - return 1; - } - else - return 0; - } - - // realiza una consulta en la base de datos - function db_consultar ( $sql, &$link) - { - if( db_conectar( $link ) ) - { - $sql = mysql_escape_string ( $sql ); - $resultado = mysql_query ( $sql, $link ); - return $resultado; - } - } - -?> Deleted: tags/ofrenda-rpc_ping/codigo/ping.php =================================================================== --- tags/ofrenda-rpc_ping/ping/ping.php 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/ping.php 2006-02-14 00:44:04 UTC (rev 25) @@ -1,108 +0,0 @@ - - * http://www.ofrenda.com.mx - */ - - // incluye la informacion de configuracion - // para el acceso a la base de datos - include 'db.php'; - - // funciones para acceso a la bd - include 'mysql.php'; - - // archivos xml - $name_xml_header = 'msg_xml_header.inc'; - $name_xml_data = 'msg_xml_data.inc'; - - // variables xml - $agente = 'Ofrenda XML-RPC 0.1'; - $host_cliente = 'Ofrenda XML-RPC Client'; - - if( strlen( $ofrenda['blog'] ) > 0 ) - { - // consulta de la db si existen sitios para hacer ping - $sql = 'select * from ' . $ofrenda['db']['ping']; - $ping['resultado'] = db_consultar ( $sql, $ping['link'] ); - $ping['num'] = mysql_num_rows ( $ping['resultado'] ); - - if( $ping['num'] > 0 ) - { - // encabezado xml - if ( file_exists ( $name_xml_header ) ) - { - $file_xml_header = fopen( $name_xml_header, "r" ); - $xml_header_source = fread ( $file_xml_header, filesize ( $name_xml_header ) ); - fclose ( $file_xml_header ); - } - else - { - echo " No existe el archivo: " . $name_xml_header; - exit(1); - } - - // datos xml - if ( file_exists ( $name_xml_data ) ) - { - $file_xml_data = fopen ( $name_xml_data, "r" ); - $xml_data_source = fread ( $file_xml_data, filesize ( $name_xml_data ) ); - fclose ( $file_xml_data ); - } - else - { - echo " No existe el archivo: " . $name_xml_data; - exit(1); - } - - // se reemplazan etiqueta de agente del header xml - $xml_header_source = eregi_replace ( "{AGENTE}", $agente, $xml_header_source ); - // reemplaza el host del cliente en el encabezado xml - $xml_header_source = eregi_replace ( "{HOST_CLIENTE}", $host_cliente, $xml_header_source ); - - $xml_header_source = $xml_header_source . "\n"; - $xml_data_source = $xml_data_source . "\n"; - - echo " \n\n Blog " . $ofrenda['blog']['nombre'] . " : " . $ofrenda['blog']['url'] . "\n"; - - while( $ping_data = mysql_fetch_assoc ( $ping['resultado'] ) ) - { - echo " \n " . $ping_data['url']; - - $xml_header_temp = $xml_header_source; - $xml_data_temp = $xml_data_source; - - // se reemplazan los datos que faltan de los archivo xml - $xml_header_temp = eregi_replace ( "{HOST_SERVIDOR}", $ping_data['url'], $xml_header_temp ); - $xml_data_temp = eregi_replace ( "{BLOG_NOMBRE}", $ofrenda['blog']['nombre'], $xml_data_temp); - $xml_data_temp = eregi_replace ( "{BLOG_URL}", $ofrenda['blog']['url'], $xml_data_temp); - - $xml_data_size = (string) strlen ( $xml_data_temp ); - $xml_header_temp = eregi_replace ( "{LONGITUD}", $xml_data_size, $xml_header_temp ); - - $server = parse_url ( $ping_data['url'] ); - - // para saber que se envia - // echo $xml_header_temp . $xml_data_temp; - - // se manda el ping - $make_ping = @fsockopen ( $server['host'], 80, $errno, $errstr, 15 ); - - if ( !$make_ping ) - echo $errno . '\n' . $errstr; - else - fputs($make_ping, $xml_header_temp . $xml_data_temp); - - fclose ( $make_ping ); - echo " DONE "; - } - } - else - echo " \n No hay url hacian donde hacer el ping "; - } - else - echo " \n No se ha definido información del blog. "; - - echo "\n\n"; - -?> Added: tags/ofrenda-rpc_ping/codigo/ping.php =================================================================== --- tags/ofrenda-rpc_ping/ping/ping.php 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/ping.php 2006-02-14 00:44:04 UTC (rev 25) @@ -0,0 +1,17 @@ + */ +/* http://www.ofrenda.com.mx */ +/******************************************************************************/ + +include ( 'core.php' ); + +$name = 'Ofrenda'; +$url = 'http://www.ofrenda.com.mx'; + +$ofrenda = new OfrendaPing ( $name, $url ); +$ofrenda->Ping (); + +?> Added: tags/ofrenda-rpc_ping/codigo/servidores.php =================================================================== --- tags/ofrenda-rpc_ping/ping/servidores.php 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/codigo/servidores.php 2006-02-14 00:44:04 UTC (rev 25) @@ -0,0 +1,51 @@ + */ +/* http://www.ofrenda.com.mx */ +/******************************************************************************/ + +$ofrenda['servers']['list'] = array ( + 'http://api.feedster.com/ping', + 'http://api.my.yahoo.com/RPC2', + 'http://api.my.yahoo.com/rss/ping', + 'http://bblog.com/ping.php', + 'http://www.bitacoras.net/actualizado/', + 'http://blogmatcher.com/u.php', + 'http://bulkfeeds.net/rpc', + 'http://coreblog.org/ping/', + 'http://mod-pubsub.org/kn_apps/blogchatt', + 'http://ping.bitacoras.com', + 'http://ping.blo.gs/', + 'http://ping.feedburner.com', + 'http://ping.rootblog.com/rpc.php', + 'http://ping.syndic8.com/xmlrpc.php', + 'http://rcs.datashed.net/RPC2', + 'http://rpc.blogrolling.com/pinger/', + 'http://rpc.pingomatic.com/', + 'http://rpc.technorati.com/rpc/ping', + 'http://rpc.weblogs.com/RPC2', + 'http://thingamablog.sourceforge.net/ping.php', + 'http://topicexchange.com/RPC2', + 'http://topicexchange.com/t/gofio/', + 'http://www.a2b.cc/setloc/bp.a2b', + 'http://www.bitacoles.net/ping.php', + 'http://www.bitadir.com/ping.php', + 'http://www.blogdigger.com/RPC2', + 'http://www.blogpeople.net/servlet/weblogUpdates', + 'http://www.blogshares.com/rpc.php', + 'http://www.blogsmexico.com/ping', + 'http://www.blogsnow.com/ping', + 'http://www.blogstreet.com/xrbin/xmlrpc.cgi', + 'http://www.lasermemory.com/lsrpc/', + 'http://www.mod-pubsub.org/kn_apps/blogchatter/ping.php', + 'http://www.newsisfree.com/xmlrpctest.php', + 'http://www.popdex.com/addsite.php', + 'http://www.snipsnap.org/RPC2', + 'http://www.weblogues.com/RPC/', + 'http://xping.pubsub.com/ping/', + 'http://www.xmlrpc.com/weblogsCom' + ); + +?> Added: tags/ofrenda-rpc_ping/codigo/xml/index.html =================================================================== Copied: tags/ofrenda-rpc_ping/codigo/xml/msg_xml_data.xml (from rev 22, tags/ofrenda-rpc_ping/ping/msg_xml_data.xml) Copied: tags/ofrenda-rpc_ping/codigo/xml/msg_xml_header.xml (from rev 22, tags/ofrenda-rpc_ping/ping/msg_xml_header.xml) Copied: tags/ofrenda-rpc_ping/docs (from rev 20, tags/ofrenda-rpc_ping/sql) Added: tags/ofrenda-rpc_ping/docs/README =================================================================== --- tags/ofrenda-rpc_ping/sql/README 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/docs/README 2006-02-14 00:44:04 UTC (rev 25) @@ -0,0 +1,15 @@ +LEEME +-------------------------------------------------------------------------------- +Ofrenda @ 2004 - 2006. +Mario Oyorzabal Salgado +http://www.ofrenda.com.mx +-------------------------------------------------------------------------------- + +Esta carpeta contiene solamente una lista a los servidores a los cuales se envia +una notificación de actualización. + +-------------------------------------------------------------------------------- +Ofrenda @ 2004 - 2006. +Mario Oyorzabal Salgado +http://www.ofrenda.com.mx +-------------------------------------------------------------------------------- Added: tags/ofrenda-rpc_ping/docs/lista-servidores.txt =================================================================== --- tags/ofrenda-rpc_ping/sql/lista-servidores.txt 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/docs/lista-servidores.txt 2006-02-14 00:44:04 UTC (rev 25) @@ -0,0 +1,64 @@ +LISTA DE SERVIDORES +-------------------------------------------------------------------------------- +Ofrenda @ 2004 - 2006. +Mario Oyorzabal Salgado +http://www.ofrenda.com.mx +-------------------------------------------------------------------------------- + +Esta es la lista actual con la que contamos, esta lista tiene direcciones web +hacia servidores que ofrecen el servicio de dar a conocer tu blog cuando este +se ha actualizado, a la vez estos servidores aceptan el ping, que envia +ofrenda, sin problemas. + +- http://api.feedster.com/ping +- http://api.my.yahoo.com/RPC2 +- http://api.my.yahoo.com/rss/ping +- http://bblog.com/ping.php +- http://www.bitacoras.net/actualizado/ +- http://blogmatcher.com/u.php +- http://bulkfeeds.net/rpc +- http://coreblog.org/ping/ +- http://mod-pubsub.org/kn_apps/blogchatt +- http://ping.bitacoras.com +- http://ping.blo.gs/ +- http://ping.feedburner.com +- http://ping.rootblog.com/rpc.php +- http://ping.syndic8.com/xmlrpc.php +- http://rcs.datashed.net/RPC2 +- http://rpc.blogrolling.com/pinger/ +- http://rpc.pingomatic.com/ +- http://rpc.technorati.com/rpc/ping +- http://rpc.weblogs.com/RPC2 +- http://thingamablog.sourceforge.net/ping.php +- http://topicexchange.com/RPC2 +- http://topicexchange.com/t/gofio/ +- http://www.a2b.cc/setloc/bp.a2b +- http://www.bitacoles.net/ping.php +- http://www.bitadir.com/ping.php +- http://www.blogdigger.com/RPC2 +- http://www.blogpeople.net/servlet/weblogUpdates +- http://www.blogshares.com/rpc.php +- http://www.blogsmexico.com/ping +- http://www.blogsnow.com/ping +- http://www.blogstreet.com/xrbin/xmlrpc.cgi +- http://www.lasermemory.com/lsrpc/ +- http://www.mod-pubsub.org/kn_apps/blogchatter/ping.php +- http://www.newsisfree.com/xmlrpctest.php +- http://www.popdex.com/addsite.php +- http://www.snipsnap.org/RPC2 +- http://www.weblogues.com/RPC/ +- http://xping.pubsub.com/ping/ +- http://www.xmlrpc.com/weblogsCom + +Algunos servidores no aceptan blogs en español o fuera de su idioma por lo cual +sería interesante poder hacer que ofrenda tenga clasificada estas direcciones +para así a moldarse a la configuración, región, e idioma de tu blog o tienda. + +También nos puedes informar si algún servidor ya no funciona o ha sido +actualizado para mantener esta lista al día. + +-------------------------------------------------------------------------------- +Ofrenda @ 2004 - 2006. +Mario Oyorzabal Salgado +http://www.ofrenda.com.mx +-------------------------------------------------------------------------------- Deleted: tags/ofrenda-rpc_ping/docs/ofrenda-data.sql =================================================================== --- tags/ofrenda-rpc_ping/sql/ofrenda-data.sql 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/docs/ofrenda-data.sql 2006-02-14 00:44:04 UTC (rev 25) @@ -1,45 +0,0 @@ --- MySQL dump 10.9 --- --- Host: localhost Database: ofrenda_ping --- ------------------------------------------------------ --- Server version 4.1.14-Debian_6-log - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `rpc_ping_url` --- - -DROP TABLE IF EXISTS `rpc_ping_url`; -CREATE TABLE `rpc_ping_url` ( - `id` int(100) NOT NULL auto_increment, - `url` text, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Dumping data for table `rpc_ping_url` --- - - -/*!40000 ALTER TABLE `rpc_ping_url` DISABLE KEYS */; -LOCK TABLES `rpc_ping_url` WRITE; -INSERT INTO `rpc_ping_url` VALUES (126,'http://api.feedster.com/ping'),(127,'http://api.my.yahoo.com/RPC2'),(128,'http://api.my.yahoo.com/rss/ping'),(129,'http://bblog.com/ping.php'),(130,'http://www.bitacoras.net/actualizado/'),(131,'http://blogmatcher.com/u.php'),(132,'http://bulkfeeds.net/rpc'),(133,'http://coreblog.org/ping/'),(134,'http://mod-pubsub.org/kn_apps/blogchatt'),(135,'http://ping.bitacoras.com'),(136,'http://ping.blo.gs/'),(137,'http://ping.feedburner.com'),(138,'http://ping.rootblog.com/rpc.php'),(139,'http://ping.syndic8.com/xmlrpc.php'),(140,'http://rcs.datashed.net/RPC2'),(141,'http://rpc.blogrolling.com/pinger/'),(142,'http://rpc.pingomatic.com/'),(143,'http://rpc.technorati.com/rpc/ping'),(144,'http://rpc.weblogs.com/RPC2'),(145,'http://thingamablog.sourceforge.net/ping.php'),(146,'http://topicexchange.com/RPC2'),(147,'http://topicexchange.com/t/gofio/'),(148,'http://www.a2b.cc/setloc/bp.a2b'),(149,'http://www.bitacoles.net/ping.php'),(150,'http://www.b itadir.com/ping.php'),(151,'http://www.blogdigger.com/RPC2'),(152,'http://www.blogpeople.net/servlet/weblogUpdates'),(153,'http://www.blogshares.com/rpc.php'),(154,'http://www.blogsmexico.com/ping'),(155,'http://www.blogsnow.com/ping'),(156,'http://www.blogstreet.com/xrbin/xmlrpc.cgi'),(157,'http://www.lasermemory.com/lsrpc/'),(158,'http://www.mod-pubsub.org/kn_apps/blogchatter/ping.php'),(159,'http://www.newsisfree.com/xmlrpctest.php'),(160,'http://www.popdex.com/addsite.php'),(161,'http://www.snipsnap.org/RPC2'),(162,'http://www.weblogues.com/RPC/'),(163,'http://xping.pubsub.com/ping/'),(164,'http://www.xmlrpc.com/weblogsCom'); -UNLOCK TABLES; -/*!40000 ALTER TABLE `rpc_ping_url` ENABLE KEYS */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - Deleted: tags/ofrenda-rpc_ping/docs/ofrenda-lista_servidores.txt =================================================================== --- tags/ofrenda-rpc_ping/sql/ofrenda-lista_servidores.txt 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/docs/ofrenda-lista_servidores.txt 2006-02-14 00:44:04 UTC (rev 25) @@ -1,62 +0,0 @@ -Lista de servidores. --------------------------------------------------------------------------------- -Ofrenda @ 2004. -Mario Oyorzabal Salgado -http://www.ofrenda.com.mx --------------------------------------------------------------------------------- -Esta es la lista actual con la que contamos, esta lista tiene direcciones web -hacia servidores que ofrecen el servicio de dar a conocer tu blog cuando este -se ha actualizado, a la vez estos servidores aceptan el ping, que envia -ofrenda, sin problemas. - -- http://api.feedster.com/ping -- http://api.my.yahoo.com/RPC2 -- http://api.my.yahoo.com/rss/ping -- http://bblog.com/ping.php -- http://www.bitacoras.net/actualizado/ -- http://blogmatcher.com/u.php -- http://bulkfeeds.net/rpc -- http://coreblog.org/ping/ -- http://mod-pubsub.org/kn_apps/blogchatt -- http://ping.bitacoras.com -- http://ping.blo.gs/ -- http://ping.feedburner.com -- http://ping.rootblog.com/rpc.php -- http://ping.syndic8.com/xmlrpc.php -- http://rcs.datashed.net/RPC2 -- http://rpc.blogrolling.com/pinger/ -- http://rpc.pingomatic.com/ -- http://rpc.technorati.com/rpc/ping -- http://rpc.weblogs.com/RPC2 -- http://thingamablog.sourceforge.net/ping.php -- http://topicexchange.com/RPC2 -- http://topicexchange.com/t/gofio/ -- http://www.a2b.cc/setloc/bp.a2b -- http://www.bitacoles.net/ping.php -- http://www.bitadir.com/ping.php -- http://www.blogdigger.com/RPC2 -- http://www.blogpeople.net/servlet/weblogUpdates -- http://www.blogshares.com/rpc.php -- http://www.blogsmexico.com/ping -- http://www.blogsnow.com/ping -- http://www.blogstreet.com/xrbin/xmlrpc.cgi -- http://www.lasermemory.com/lsrpc/ -- http://www.mod-pubsub.org/kn_apps/blogchatter/ping.php -- http://www.newsisfree.com/xmlrpctest.php -- http://www.popdex.com/addsite.php -- http://www.snipsnap.org/RPC2 -- http://www.weblogues.com/RPC/ -- http://xping.pubsub.com/ping/ -- http://www.xmlrpc.com/weblogsCom - -Algunos servidores no aceptan blogs en español o fuera de su idioma por lo cual -sería interesante poder hacer que ofrenda tenga clasificada estas direcciones -para así a moldarse a la configuración, región, e idioma de tu blog o tienda. - -También nos puedes informar si algún servidor ya no funciona o ha sido -actualizado para mantener esta lista al día. - --------------------------------------------------------------------------------- -Ofrenda @ 2004. -Mario Oyorzabal Salgado -http://www.ofrenda.com.mx Deleted: tags/ofrenda-rpc_ping/docs/ofrenda-rpc_ping.sql =================================================================== --- tags/ofrenda-rpc_ping/sql/ofrenda-rpc_ping.sql 2006-01-28 22:57:18 UTC (rev 20) +++ tags/ofrenda-rpc_ping/docs/ofrenda-rpc_ping.sql 2006-02-14 00:44:04 UTC (rev 25) @@ -1,10 +0,0 @@ -# Tabla necesaria para ofrenda-rpc_ping. -# En esta se contiene solamente la url de los servidores -# a los cuales se le hace un ping. - -create table rpc_ping_url -( - id int(100) auto_increment, - url varchar(256), - primary key (id) -); From tuxsoul en gmail.com Mon Feb 13 23:23:56 2006 From: tuxsoul en gmail.com (Mario Oyorzabal Salgado) Date: Tue Aug 15 11:27:12 2006 Subject: [Ofrenda-svn] r28 - tags/ofrenda-rpc_ping/codigo Message-ID: <20060214062356.289C41B65A3@kolax.provo.novell.com> Author: tuxsoul Date: 2006-02-13 23:23:55 -0700 (Mon, 13 Feb 2006) New Revision: 28 Modified: tags/ofrenda-rpc_ping/codigo/config.php tags/ofrenda-rpc_ping/codigo/core.php Log: Ofrenda-Core: Rpc-ping detalles Modified: tags/ofrenda-rpc_ping/codigo/config.php =================================================================== --- tags/ofrenda-rpc_ping/codigo/config.php 2006-02-14 06:22:27 UTC (rev 27) +++ tags/ofrenda-rpc_ping/codigo/config.php 2006-02-14 06:23:55 UTC (rev 28) @@ -31,6 +31,6 @@ return $ofrenda; } -}; +} ?> Modified: tags/ofrenda-rpc_ping/codigo/core.php =================================================================== --- tags/ofrenda-rpc_ping/codigo/core.php 2006-02-14 06:22:27 UTC (rev 27) +++ tags/ofrenda-rpc_ping/codigo/core.php 2006-02-14 06:23:55 UTC (rev 28) @@ -123,6 +123,6 @@ echo "\n"; } -}; +} ?> From tuxsoul en gmail.com Mon Feb 13 23:21:24 2006 From: tuxsoul en gmail.com (Mario Oyorzabal Salgado) Date: Tue Aug 15 11:27:17 2006 Subject: [Ofrenda-svn] r26 - in trunk/ofrenda-blog: . html html/librerias html/librerias/magpierss html/librerias/magpierss/extlib html/librerias/mdb2 html/librerias/mdb2/MDB2 html/librerias/mdb2/MDB2/Driver html/librerias/mdb2/MDB2/Driver/Datatype html/librerias/mdb2/MDB2/Driver/Function html/librerias/mdb2/MDB2/Driver/Manager html/librerias/mdb2/MDB2/Driver/Reverse html/librerias/phpmailer html/librerias/phpmailer/language html/librerias/smarty html/librerias/smarty/libs html/librerias/smarty/libs/internals html/librerias/smarty/libs/plugins html/librerias/smarty/misc Message-ID: <20060214062124.464FA1B65A0@kolax.provo.novell.com> Author: tuxsoul Date: 2006-02-13 23:20:45 -0700 (Mon, 13 Feb 2006) New Revision: 26 Added: trunk/ofrenda-blog/html/ trunk/ofrenda-blog/html/librerias/ trunk/ofrenda-blog/html/librerias/README trunk/ofrenda-blog/html/librerias/index.html trunk/ofrenda-blog/html/librerias/magpierss/ trunk/ofrenda-blog/html/librerias/magpierss/AUTHORS trunk/ofrenda-blog/html/librerias/magpierss/CHANGES trunk/ofrenda-blog/html/librerias/magpierss/ChangeLog trunk/ofrenda-blog/html/librerias/magpierss/INSTALL trunk/ofrenda-blog/html/librerias/magpierss/NEWS trunk/ofrenda-blog/html/librerias/magpierss/README trunk/ofrenda-blog/html/librerias/magpierss/TROUBLESHOOTING trunk/ofrenda-blog/html/librerias/magpierss/cookbook trunk/ofrenda-blog/html/librerias/magpierss/extlib/ trunk/ofrenda-blog/html/librerias/magpierss/extlib/Snoopy.class.inc trunk/ofrenda-blog/html/librerias/magpierss/extlib/index.html trunk/ofrenda-blog/html/librerias/magpierss/index.html trunk/ofrenda-blog/html/librerias/magpierss/rss_cache.inc trunk/ofrenda-blog/html/librerias/magpierss/rss_fetch.inc trunk/ofrenda-blog/html/librerias/magpierss/rss_parse.inc trunk/ofrenda-blog/html/librerias/magpierss/rss_utils.inc trunk/ofrenda-blog/html/librerias/mdb2/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Date.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/Common.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/index.html trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/Common.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/index.html trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/Common.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/index.html trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/Common.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/index.html trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/index.html trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Extended.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Iterator.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/LOB.php trunk/ofrenda-blog/html/librerias/mdb2/MDB2/index.html trunk/ofrenda-blog/html/librerias/mdb2/index.html trunk/ofrenda-blog/html/librerias/phpmailer/ trunk/ofrenda-blog/html/librerias/phpmailer/ChangeLog.txt trunk/ofrenda-blog/html/librerias/phpmailer/LICENSE trunk/ofrenda-blog/html/librerias/phpmailer/README trunk/ofrenda-blog/html/librerias/phpmailer/class.phpmailer.php trunk/ofrenda-blog/html/librerias/phpmailer/class.smtp.php trunk/ofrenda-blog/html/librerias/phpmailer/index.html trunk/ofrenda-blog/html/librerias/phpmailer/language/ trunk/ofrenda-blog/html/librerias/phpmailer/language/index.html trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-br.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-ca.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-cz.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-de.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-dk.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-en.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-es.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-fi.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-fo.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-fr.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-hu.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-it.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-ja.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-nl.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-no.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-pl.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-ro.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-ru.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-se.php trunk/ofrenda-blog/html/librerias/phpmailer/language/phpmailer.lang-tr.php trunk/ofrenda-blog/html/librerias/smarty/ trunk/ofrenda-blog/html/librerias/smarty/BUGS trunk/ofrenda-blog/html/librerias/smarty/COPYING.lib trunk/ofrenda-blog/html/librerias/smarty/ChangeLog trunk/ofrenda-blog/html/librerias/smarty/FAQ trunk/ofrenda-blog/html/librerias/smarty/INSTALL trunk/ofrenda-blog/html/librerias/smarty/NEWS trunk/ofrenda-blog/html/librerias/smarty/QUICK_START trunk/ofrenda-blog/html/librerias/smarty/README trunk/ofrenda-blog/html/librerias/smarty/RELEASE_NOTES trunk/ofrenda-blog/html/librerias/smarty/TODO trunk/ofrenda-blog/html/librerias/smarty/index.html trunk/ofrenda-blog/html/librerias/smarty/libs/ trunk/ofrenda-blog/html/librerias/smarty/libs/Config_File.class.php trunk/ofrenda-blog/html/librerias/smarty/libs/Smarty.class.php trunk/ofrenda-blog/html/librerias/smarty/libs/Smarty_Compiler.class.php trunk/ofrenda-blog/html/librerias/smarty/libs/debug.tpl trunk/ofrenda-blog/html/librerias/smarty/libs/index.html trunk/ofrenda-blog/html/librerias/smarty/libs/internals/ trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.assemble_plugin_filepath.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.assign_smarty_interface.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.create_dir_structure.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.display_debug_console.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.get_include_path.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.get_microtime.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.get_php_resource.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.is_secure.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.is_trusted.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.load_plugins.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.load_resource_plugin.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.process_cached_inserts.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.process_compiled_include.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.read_cache_file.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.rm_auto.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.rmdir.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.run_insert_handler.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.smarty_include_php.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.write_cache_file.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.write_compiled_include.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.write_compiled_resource.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/core.write_file.php trunk/ofrenda-blog/html/librerias/smarty/libs/internals/index.html trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/ trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/block.textformat.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/compiler.assign.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.assign_debug_info.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.config_load.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.counter.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.cycle.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.debug.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.eval.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.fetch.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_checkboxes.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_image.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_options.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_radios.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_select_date.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_select_time.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.html_table.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.mailto.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.math.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.popup.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/function.popup_init.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/index.html trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.capitalize.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.cat.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.count_characters.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.count_paragraphs.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.count_sentences.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.count_words.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.date_format.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.debug_print_var.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.default.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.escape.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.indent.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.lower.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.nl2br.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.regex_replace.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.replace.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.spacify.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.string_format.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.strip.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.strip_tags.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.truncate.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.upper.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/modifier.wordwrap.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/outputfilter.trimwhitespace.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/shared.escape_special_chars.php trunk/ofrenda-blog/html/librerias/smarty/libs/plugins/shared.make_timestamp.php trunk/ofrenda-blog/html/librerias/smarty/misc/ trunk/ofrenda-blog/html/librerias/smarty/misc/index.html trunk/ofrenda-blog/html/librerias/smarty/misc/smarty_icon.README trunk/ofrenda-blog/html/librerias/smarty/misc/smarty_icon.gif Log: Ofrenda-blog: Librerias. Added: trunk/ofrenda-blog/html/librerias/README =================================================================== --- trunk/ofrenda-blog/html/librerias/README 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/README 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,49 @@ +LEEME +-------------------------------------------------------------------------------- +Ofrenda @ 2004 - 2006 +Mario Oyorzabal Salgado +http://www.ofrenda.com.mx +-------------------------------------------------------------------------------- + +Esta carpeta contiene proyectos incluidos con los que trabaja Ofrenda, +utilizandolos como librerías para aumentar y facilitar sus caracteristicas. + +******************************************************************************** +2006 - 02 - 03 +******************************************************************************** +- Phpmailer + versión: 1.73 + http://phpmailer.sourceforge.net/ +- MDB2 + versión: 2.0.0 + http://pear.php.net/package/MDB2 +- Smarty + versión: 2.6.12 + http://smarty.php.net/ + +******************************************************************************** +2006 - 02 - 03 +******************************************************************************** +- MargpieRSS -> versión: 0.72 + http://magpierss.sourceforge.net/ + + * Snoopy + versión: 1.2.3 + http://snoopy.sourcegorge.net/ + +******************************************************************************** +2005 - 12 - 01 +******************************************************************************** +- MargpieRSS + vesión: 0.71.1 + http://magpierss.sourceforge.net/ + + * Snoopy + versión: 1.0 + http://snoopy.sourcegorge.net/ + +-------------------------------------------------------------------------------- +Ofrenda @ 2004 - 2006 +Mario Oyorzabal Salgado +http://www.ofrenda.com.mx +-------------------------------------------------------------------------------- Property changes on: trunk/ofrenda-blog/html/librerias/README ___________________________________________________________________ Name: svn:executable + * Added: trunk/ofrenda-blog/html/librerias/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/magpierss/AUTHORS =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/AUTHORS 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/AUTHORS 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1 @@ +kellan Added: trunk/ofrenda-blog/html/librerias/magpierss/CHANGES =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/CHANGES 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/CHANGES 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,41 @@ +Version 0.72 +----------- + - fix security exploit: http://www.sec-consult.com/216.html + +Version 0.7 +----------- + - support for input and output charset encoding + based on the work in FoF, uses iconv or mbstring if available + - + +Version 0.6 +----------- + - basic support for Atom syndication format + including support for Atom content constructs + - fixed support for private feeds (HTTP Auth and SSL) + (thanks to silverorange.com for providing test feeds) + - support for some broken webservers + +Version 0.52 +----------- + - support GZIP content negoiation + - PHP 4.3.2 support + +Version 0.4 +----------- + - improved error handling, better access for script authors + - included example scripts of working with MagpieRSS + - new Smarty plugin for RSS date parsing + +Version 0.3 +----------- + - added support for conditional gets (Last-Modified, ETag) + - now use Snoopy to handle fetching RSS files + +Version 0.2 +----------- + - MAJOR CLEAN UP + - removed kludgy $options array in favour of constants + - phased out returning arrays + - added better error handling + - re-worked comments Added: trunk/ofrenda-blog/html/librerias/magpierss/ChangeLog =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/ChangeLog 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/ChangeLog 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,405 @@ +2005-10-28 14:11 kellan + + * extlib/Snoopy.class.inc: a better solution + +2005-10-28 11:51 kellan + + * extlib/Snoopy.class.inc: fix arbtriary code execution + vulnerability when using curl+ssl + + http://www.sec-consult.com/216.html + +2005-03-08 10:46 kellan + + * rss_parse.inc: fix bug w/ atom and date normalization + +2005-02-09 14:59 kellan + + * rss_fetch.inc: fix stale cache bug + +2005-01-28 02:27 kellan + + * rss_parse.inc: support php w/o array_change_case + +2005-01-23 20:02 kellan + + * rss_fetch.inc: fix cache bug introduced by charset encoding + +2005-01-12 09:14 kellan + + * rss_cache.inc, rss_fetch.inc: more sanity checks for when things + go wrong + +2004-12-12 13:44 kellan + + * INSTALL, rss_cache.inc, rss_utils.inc: detab + +2004-11-23 20:15 kellan + + * rss_parse.inc: fix calling iconv instead of mb_convert_encoding + +2004-11-22 02:11 kellan + + * CHANGES, ChangeLog, rss_parse.inc, scripts/magpie_debug.php: last + bit of tidying + +2004-11-22 01:45 kellan + + * rss_fetch.inc: detab, bump version + +2004-11-22 01:43 kellan + + * rss_parse.inc: was filtering too much + +2004-11-22 00:03 kellan + + * rss_fetch.inc, rss_parse.inc: cache on $url . $output_encoding + otherwise we can get munged output + +2004-11-21 23:52 kellan + + * rss_parse.inc: add WARNING + +2004-11-21 23:45 kellan + + * rss_parse.inc: don't set ERROR on notice or warning (rss_fetch + dies on parse errors) + +2004-11-21 23:44 kellan + + * rss_fetch.inc: add encoding defines (fix timeout error reporting) + +2004-11-21 20:21 kellan + + * rss_parse.inc: incorporate steve's patch + +2004-11-21 19:26 kellan + + * rss_parse.inc: remove old debugging functions, totally + arbitrarily. might break stuff. can't really explain why i'm + doing this. + +2004-10-28 15:52 kellan + + * rss_parse.inc: fixed '=' instead of '==' + +2004-10-26 00:48 kellan + + * rss_parse.inc: chance epoch to timestamp to conform w/ php naming + conventions + +2004-06-15 12:00 kellan + + * rss_parse.inc: [no log message] + +2004-04-26 14:16 kellan + + * rss_fetch.inc: bump version + +2004-04-26 12:36 kellan + + * rss_parse.inc: fix field doubling + +2004-04-24 17:47 kellan + + * CHANGES, ChangeLog: updated + +2004-04-24 17:35 kellan + + * rss_fetch.inc: bumped version + +2004-04-24 16:52 kellan + + * rss_parse.inc: support arbitrary atom content constructs + + some refactoring + +2004-04-24 16:15 kellan + + * rss_parse.inc: support summary content contstruct. add normalize + function + +2004-03-27 16:29 kellan + + * extlib/Snoopy.class.inc: accept self-signed certs + +2004-03-27 12:53 kellan + + * extlib/Snoopy.class.inc: fixed SSL support * set status * set + error on bad curl + + (also ripped out big chunks of dead weight (submit_form) which + were getting in my way + +2004-01-25 02:25 kellan + + * rss_parse.inc: make RSS 1.0's rdf:about available + +2004-01-25 02:07 kellan + + * rss_parse.inc: clean up text, and line formats. add support item + rdf:about + +2004-01-24 23:40 kellan + + * CHANGES, ChangeLog: update changes + +2004-01-24 23:37 kellan + + * rss_fetch.inc: updated version + +2004-01-24 23:35 kellan + + * rss_parse.inc: whitespace + +2004-01-24 23:23 kellan + + * extlib/Snoopy.class.inc: support badly formatted http headers + +2004-01-24 23:20 kellan + + * rss_parse.inc: added alpha atom parsing support + +2003-06-25 22:34 kellan + + * extlib/Snoopy.class.inc: fixed fread 4.3.2 compatibility problems + +2003-06-13 11:31 kellan + + * rss_fetch.inc: reset cache on 304 + +2003-06-12 21:37 kellan + + * rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: + bumped up version numbers + +2003-06-12 21:32 kellan + + * htdocs/index.html: updated news + +2003-06-12 21:27 kellan + + * NEWS: a manual blog :) + +2003-06-12 21:22 kellan + + * htdocs/index.html: fully qualified img + +2003-06-12 21:20 kellan + + * htdocs/index.html: clean up. added badge. + +2003-06-12 21:04 kellan + + * rss_utils.inc: clean up regex + +2003-06-12 21:02 kellan + + * rss_cache.inc: suppress some warnings + +2003-05-30 20:44 kellan + + * extlib/Snoopy.class.inc: more comments, cleaned up notice + +2003-05-30 15:14 kellan + + * extlib/Snoopy.class.inc: don't advertise gzip support if the user + hasn't built php with gzinflate support + +2003-05-12 22:32 kellan + + * ChangeLog: changes + +2003-05-12 22:11 kellan + + * htdocs/index.html: announce 0.5 + +2003-05-12 21:42 kellan + + * htdocs/index.html: change + +2003-05-12 21:39 kellan + + * rss_fetch.inc: use gzip + +2003-05-12 21:37 kellan + + * extlib/Snoopy.class.inc: added support gzip encoded content + negoiation + +2003-05-12 21:32 kellan + + * rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: fixed + typoes + +2003-04-26 21:44 kellan + + * rss_parse.inc: fix minor typo + +2003-04-18 08:19 kellan + + * htdocs/cookbook.html: updated cookbook to show more code for + limiting items + +2003-03-03 16:02 kellan + + * rss_parse.inc, scripts/magpie_slashbox.php: committed (or + adpated) patch from Nicola (www.technick.com) to quell 'Undefined + Indexes' notices + +2003-03-03 15:59 kellan + + * rss_fetch.inc: commited patch from nicola (www.technick.com) to + quell 'undefined indexes' notices. + + * Magpie now automatically includes its version in the + user-agent, & whether cacheing is turned on. + +2003-02-12 01:22 kellan + + * CHANGES, ChangeLog: ChangeLog now auto-generated by cvs2cl + +2003-02-12 00:21 kellan + + * rss_fetch.inc: better errors, hopefully stomped on pesky notices + +2003-02-12 00:19 kellan + + * rss_parse.inc: check to see is xml is supported, if not die + + also throw better xml errors + +2003-02-12 00:18 kellan + + * rss_cache.inc: hopefully cleared up some notices that were being + thrown into the log + + fixed a debug statement that was being called as an error + +2003-02-12 00:15 kellan + + * scripts/: magpie_simple.php, magpie_slashbox.php: moved + magpie_simple to magpie_slashbox, and replaced it with a simpler + demo. + +2003-02-12 00:02 kellan + + * INSTALL, README, TROUBLESHOOTING: Improved documentation. Better + install instructions. + + TROUBLESHOOTING cover common installation and usage problems + +2003-01-22 14:40 kellan + + * htdocs/cookbook.html: added cookbook.html + +2003-01-21 23:47 kellan + + * cookbook: a magpie cookbook + +2003-01-20 10:09 kellan + + * ChangeLog: updated + +2003-01-20 09:23 kellan + + * scripts/simple_smarty.php: minor clean up + +2003-01-20 09:15 kellan + + * scripts/README: added smarty url + +2003-01-20 09:14 kellan + + * magpie_simple.php, htdocs/index.html, scripts/README, + scripts/magpie_debug.php, scripts/magpie_simple.php, + scripts/simple_smarty.php, + scripts/smarty_plugin/modifier.rss_date_parse.php, + scripts/templates/simple.smarty: Added scripts directory for + examples on how to use MagpieRSS + + magpie_simple - is a simple example magpie_debug - spew all the + information from a parsed RSS feed simple_smary - example of + using magpie with Smarty template system + smarty_plugin/modifier.rss_date_parse.php - support file for the + smarty demo templates/simple.smary - template for the smarty demo + +2003-01-20 09:11 kellan + + * rss_fetch.inc, rss_parse.inc: changes to error handling to give + script authors more access to magpie's errors. + + added method magpie_error() to retrieve global MAGPIE_ERROR + variable for when fetch_rss() returns false + +2002-10-26 19:02 kellan + + * htdocs/index.html: putting the website under source control + +2002-10-26 18:43 kellan + + * AUTHORS, ChangeLog, INSTALL, README: some documentation to make + it all look official :) + +2002-10-25 23:04 kellan + + * magpie_simple.php: quxx + +2002-10-25 23:04 kellan + + * rss_parse.inc: added support for textinput and image + +2002-10-25 19:23 kellan + + * magpie_simple.php, rss_cache.inc, rss_fetch.inc, rss_parse.inc, + rss_utils.inc: switched to using Snoopy for fetching remote RSS + files. + + added support for conditional gets + +2002-10-25 19:22 kellan + + * rss_cache.inc, rss_fetch.inc, rss_parse.inc, rss_utils.inc: + Change comment style to slavishly imitate the phpinsider style + found in Smarty and Snoopy :) + +2002-10-25 19:18 kellan + + * extlib/Snoopy.class.inc: added Snoopy in order to support + conditional gets + +2002-10-23 23:19 kellan + + * magpie_simple.php, rss_cache.inc, rss_fetch.inc, rss_parse.inc: + MAJOR CLEANUP! + + * rss_fetch got rid of the options array, replaced it with a more + PHP-like solution of using defines. constants are setup, with + defaults, in the function init() + + got rid of the idiom of passing back an array, its was awkward to + deal with in PHP, and unusual (and consquently confusing to + people). now i return true/false values, and try to setup error + string where appropiate (rss_cache has the most complete example + of this) + + change the logic for interacting with the cache + + * rss_cache major re-working of how error are handled. tried to + make the code more resillient. the cache is now much more aware + of MAX_AGE, where before this was being driven out of rss_fetch + (which was silly) + + * rss_parse properly handles xml parse errors. used to sail + along blithely unaware. + +2002-09-11 11:11 kellan + + * rss_cache.inc, rss_parse.inc, magpie_simple.php, rss_fetch.inc, + rss_utils.inc: Initial revision + +2002-09-11 11:11 kellan + + * rss_cache.inc, rss_parse.inc, magpie_simple.php, rss_fetch.inc, + rss_utils.inc: initial import + Added: trunk/ofrenda-blog/html/librerias/magpierss/INSTALL =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/INSTALL 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/INSTALL 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,143 @@ +REQUIREMENTS + + MapieRSS requires a recent PHP 4+ (developed with 4.2.0) + with xml (expat) support. + + Optionally: + * PHP5 with libxml2 support. + * cURL for SSL support + * iconv (preferred) or mb_string for expanded character set support + +QUICK START + + Magpie consists of 4 files (rss_fetch.inc, rss_parser.inc, rss_cache.inc, + and rss_utils.inc), and the directory extlib (which contains a modified + version of the Snoopy HTTP client) + + Copy these 5 resources to a directory named 'magpierss' in the same + directory as your PHP script. + + At the top of your script add the following line: + + require_once('magpierss/rss_fetch.inc'); + + Now you can use the fetch_rss() method: + + $rss = fetch_rss($url); + + Done. That's it. See README for more details on using MagpieRSS. + +NEXT STEPS + + Important: you'll probably want to get the cache directory working in + order to speed up your application, and not abuse the webserver you're + downloading the RSS from. + + Optionally you can install MagpieRSS in your PHP include path in order to + make it available server wide. + + Lastly you might want to look through the constants in rss_fetch.inc see if + there is anything you want to override (the defaults are pretty good) + + For more info, or if you have trouble, see TROUBLESHOOTING + +SETTING UP CACHING + + Magpie has built-in transparent caching. With caching Magpie will only + fetch and parse RSS feeds when there is new content. Without this feature + your pages will be slow, and the sites serving the RSS feed will be annoyed + with you. + +** Simple and Automatic ** + + By default Magpie will try to create a cache directory named 'cache' in the + same directory as your PHP script. + +** Creating a Local Cache Directory ** + + Often this will fail, because your webserver doesn't have sufficient + permissions to create the directory. + + Exact instructions for how to do this will vary from install to install and + platform to platform. The steps are: + + 1. Make a directory named 'cache' + 2. Give the web server write access to that directory. + + An example of how to do this on Debian would be: + + 1. mkdir /path/to/script/cache + 2. chgrp www-data /path/to/script/cache + 3. chmod 775 /path/to/script/cache + + On other Unixes you'll need to change 'www-data' to what ever user Apache + runs as. (on MacOS X the user would be 'www') + +** Cache in /tmp ** + + Sometimes you won't be able to create a local cache directory. Some reasons + might be: + + 1. No shell account + 2. Insufficient permissions to change ownership of a directory + 3. Webserver runs as 'nobody' + + In these situations using a cache directory in /tmp can often be a good + option. + + The drawback is /tmp is public, so anyone on the box can read the cache + files. Usually RSS feeds are public information, so you'll have to decide + how much of an issue that is. + + To use /tmp as your cache directory you need to add the following line to + your script: + + define('MAGPIE_CACHE_DIR', '/tmp/magpie_cache'); + +** Global Cache ** + + If you have several applications using Magpie, you can create a single + shared cache directory, either using the /tmp cache, or somewhere else on + the system. + + The upside is that you'll distribute fetching and parsing feeds across + several applications. + +INSTALLING MAGPIE SERVER WIDE + + Rather then following the Quickstart instructions which requires you to have + a copy of Magpie per application, alternately you can place it in some + shared location. + +** Adding Magpie to Your Include Path ** + + Copy the 5 resources (rss_fetch.inc, rss_parser.inc, rss_cache.inc, + rss_utils.inc, and extlib) to a directory named 'magpierss' in your include + path. Now any PHP file on your system can use Magpie with: + + require_once('magpierss/rss_fetch.inc'); + + Different installs have different include paths, and you'll have to figure + out what your include_path is. + + From shell you can try: + + php -i | grep 'include_path' + + Alternatley you can create a phpinfo.php file with contains: + + + + Debian's default is: + + /usr/share/php + + (though more idealogically pure location would be /usr/local/share/php) + + Apple's default include path is: + + /usr/lib/php + + While the Entropy PHP build seems to use: + + /usr/local/php/lib/php \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/magpierss/NEWS =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/NEWS 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/NEWS 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,53 @@ +MagpieRSS News + +MAGPIERSS 0.51 RELEASED + * important bugfix! + * fix "silent failure" when PHP doesn't have zlib + +FEED ON FEEDS USES MAGPIE + * web-based RSS aggregator built with Magpie + * easy to install, easy to use. + http://minutillo.com/steve/feedonfeeds/ + +MAGPIERSS 0.5 RELEASED + * supports transparent HTTP gzip content negotiation for reduced bandwidth usage + * quashed some undefined index notices + +MAGPIERSS 0.46 RELEASED + * minor release, more error handling clean up + * documentation fixes, simpler example + * new trouble shooting guide for installation and usage problems + http://magpierss.sourceforge.net/TROUBLESHOOTING + +MAGPIE NEWS AS RSS + * releases, bug fixes, releated stories in RSS + +MAGPIERSS COOKBOOK: SIMPLE PHP RSS HOW TOS + * answers some of the most frequently asked Magpie questions + * feedback, suggestions, requests, recipes welcome + http://magpierss.sourceforge.net/cookbook.html + +MAGPIERSS 0.4 RELEASED! + * improved error handling, more flexibility for script authors, backwards compatible + * new and better examples! including using MagpieRSS and Smarty + * new Smarty plugin for RSS date parsing + http://smarty.php.net + +INFINITE PENGUIN NOW SUPPORTS MAGPIE 0.3 + * simple, sophisticated RSS viewer + * includes auto-generated javascript ticker from RSS feed + http://www.infinitepenguins.net/rss/ + +TRAUMWIND RELEASES REX BACKEND FOR MAGPIERSS + * drop in support using regex based XML parser + * parses improperly formed XML that chokes expat + http://traumwind.de/blog/magpie/magpie_alike.php + +MAGPIERSS 0.3 RELEASED! + * Support added for HTTP Conditional GETs. + http://fishbowl.pastiche.org/archives/001132.html + +MAGPIERSS 0.2! + * Major clean up of the code. Easier to use. + * Simpler install on shared hosts. + * Better documentation and comments. Added: trunk/ofrenda-blog/html/librerias/magpierss/README =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/README 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/README 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,48 @@ +NAME + + MagpieRSS - a simple RSS integration tool + +SYNOPSIS + + require_once(rss_fetch.inc); + $url = $_GET['url']; + $rss = fetch_rss( $url ); + + echo "Channel Title: " . $rss->channel['title'] . "

"; + echo "

    "; + foreach ($rss->items as $item) { + $href = $item['link']; + $title = $item['title']; + echo "
  • $title
  • "; + } + echo "
"; + +DESCRIPTION + + MapieRSS is an XML-based RSS parser in PHP. It attempts to be "PHP-like", + and simple to use. + + Some features include: + + * supports RSS 0.9 - 1.0, with limited RSS 2.0 support + * supports namespaces, and modules, including mod_content and mod_event + * open minded [1] + * simple, functional interface, to object oriented backend parser + * automatic caching of parsed RSS objects makes its easy to integrate + * supports conditional GET with Last-Modified, and ETag + * uses constants for easy override of default behaviour + * heavily commented + + +1. By open minded I mean Magpie will accept any tag it finds in good faith that + it was supposed to be here. For strict validation, look elsewhere. + + +GETTING STARTED + + + +COPYRIGHT: + Copyright(c) 2002 kellan@protest.net. All rights reserved. + This software is released under the GNU General Public License. + Please read the disclaimer at the top of the Snoopy.class.inc file. Added: trunk/ofrenda-blog/html/librerias/magpierss/TROUBLESHOOTING =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/TROUBLESHOOTING 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/TROUBLESHOOTING 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,152 @@ +TROUBLESHOOTING + + +Trouble Installing MagpieRSS: + +1. Fatal error: Failed opening required '/path/to/script/rss_fetch.inc' + (include_path='.:/usr/local/lib/php:/usr/local/lib/php/pear') + +2. Cache couldn't make dir './cache'. + +3. Fatal error: Failed to load PHP's XML Extension. + http://www.php.net/manual/en/ref.xml.php + +Trouble Using MagpieRSS + +4. Warning: MagpieRSS: Failed to fetch example.com/index.rdf. + (HTTP Error: Invalid protocol "") + +5. Warning: MagpieRSS: Failed to parse RSS file. + (not well-formed (invalid token) at line 19, column 98) + +6. Warning: MagpieRSS: Failed to fetch http://localhost/rss/features.1-0.rss. + (HTTP Response: HTTP/1.1 404 Not Found) + +If you would rather provide a custom error, see the COOKBOOK +(http://magpierss.sf.net/cookbook.html) recipe 2. + +************************************************************************* +1. Fatal error: Failed opening required '/path/to/script/rss_fetch.inc' + (include_path='.:/usr/local/lib/php:/usr/local/lib/php/pear') + + This could mean that: + + a) PHP can't find the MagpieRSS files. + b) PHP found them the MagpieRSS files, but can't read them. + + a. Telling PHP where to look for MagpieRSS file. + + This might mean your PHP program can't find the MagpieRSS libraries. + Magpie relies on 4 include files, rss_fetch.inc, rss_parse.inc, + rss_cache.inc, rss_util.inc, and for normal use you'll need all 4 (see the + cookbook for exceptions). + + This can be fixed by making sure the MagpieRSS files are in your include + path. + + If you can edit your include path (for example your on a shared host) then + you need to replace: + + require_once('rss_fetch.inc'); + + -with- + + define('MAGPIE_DIR', '/path/to/magpierss/'); + require_once(MAGPIE_DIR.'rss_fetch.inc'); + + b. PHP can't read the MagpieRSS files + + All PHP libraries need to be readable by your webserver. + + On Unix you can accomplish this with: + + chmod 755 rss_fetch.inc rss_parse.inc rss_cache.inc rss_util.inc + +************************************************************************* +2. Cache couldn't make dir './cache'. + + MagpieRSS caches the results of fetched and parsed RSS to reduce the load on + both your server, and the remote server providing the RSS. It does this by + writing files to a cache directory. + + This error means the webserver doesn't have write access to the current + directory. + + a. Make a webserver writeable cache directory + + Find the webserver's group. (on my system it is 'www') + + mkdir ./cache + chgrp www directory_name + chmod g+w directory_name + + (this is the best, and desired solution) + + b. Tell MagpieRSS to create the cache directory somewhere the webserver can + write to. + + define('MAGPIE_CACHE_DIR', '/tmp/magpierss'); + + (this is not a great solution, and might have security considerations) + + c. Turn off cacheing. + + Magpie can work fine with cacheing, but it will be slower, and you might + become a nuiance to the RSS provider, but it is an option. + + define('MAGPIE_CACHE_ON', 0); + + d. And lastly, do NOT + + chmod 777 ./cache + + Any of the above solutions are better then this. + + NOTE: If none of this works for you, let me know. I've got root, and a + custom compiled Apache on almost any box I ever touch, so I can be a little + out of touch with reality. But I won't know that if I don't feedback. + +************************************************************************* 3. +3. Fatal error: Failed to load PHP's XML Extension. + http://www.php.net/manual/en/ref.xml.php + + -or- + + Fatal error: Failed to create an instance of PHP's XML parser. + http://www.php.net/manual/en/ref.xml.php + + Make sure your PHP was built with --with-xml + + This has been turned on by default for several versions of PHP, but it might + be turned off in your build. + + See php.net for details on building and configuring PHP. + + +************************************************************************* +4. Warning: MagpieRSS: Failed to fetch index.rdf. + (HTTP Error: Invalid protocol "") + + You need to put http:// in front of your the URL to your RSS feed + +************************************************************************* +5. Warning: MagpieRSS: Failed to parse RSS file. + (not well-formed (invalid token) at line 19, column 98) + + There is a problem with the RSS feed you are trying to read. + MagpieRSS is an XML parser, and therefore can't parse RSS feed with invalid + characters. Some RSS parser are based on regular expressions, and can + parse invalid RSS but they have their own problems. + + You could try contacting the author of the RSS feed, and pointing them to + the online RSS validator at: + + http://feeds.archive.org/validator/ + +************************************************************************* +6. Warning: MagpieRSS: Failed to fetch http://example.com/index.rdf + (HTTP Response: HTTP/1.1 404 Not Found) + + Its a 404! The RSS file ain't there. + + Added: trunk/ofrenda-blog/html/librerias/magpierss/cookbook =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/cookbook 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/cookbook 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,125 @@ +MAGPIERSS RECIPES: Cooking with Corbies + + "Four and twenty blackbirds baked in a pie." + +1. LIMIT THE NUMBER OF HEADLINES(AKA ITEMS) RETURNED. + +PROBLEM: + +You want to display the 10 (or 3) most recent headlines, but the RSS feed +contains 15. + +SOLUTION: + +$num_items = 10; +$rss = fetch_rss($url); + +$items = array_slice($rss->items, 0, $num_items); + +DISCUSSION: + +Rather then trying to limit the number of items Magpie parses, a much simpler, +and more flexible approach is to take a "slice" of the array of items. And +array_slice() is smart enough to do the right thing if the feed has less items +then $num_items. + +See: http://www.php.net/array_slice + + +2. DISPLAY A CUSTOM ERROR MESSAGE IF SOMETHING GOES WRONG + +PROBLEM: + +You don't want Magpie's error messages showing up if something goes wrong. + +SOLUTION: + +# Magpie throws USER_WARNINGS only +# so you can cloak these, by only showing ERRORs +error_reporting(E_ERROR); + +# check the return value of fetch_rss() + +$rss = fetch_rss($url); + +if ( $rss ) { +...display rss feed... +} +else { + echo "An error occured! " . + "Consider donating more $$$ for restoration of services." . + "
Error Message: " . magpie_error(); +} + +DISCUSSION: + +MagpieRSS triggers a warning in a number of circumstances. The 2 most common +circumstances are: if the specified RSS file isn't properly formed (usually +because it includes illegal HTML), or if Magpie can't download the remote RSS +file, and there is no cached version. + +If you don't want your users to see these warnings change your error_reporting +settings to only display ERRORs. Another option is to turn off display_error, +so that WARNINGs, and NOTICEs still go to the error_log but not to the webpages. + +You can do this with: + +ini_set('display_errors', 0); + +See: http://www.php.net/error_reporting, + http://www.php.net/ini_set, + http://www.php.net/manual/en/ref.errorfunc.php + +3. GENERATE A NEW RSS FEED + +PROBLEM: + +Create an RSS feed for other people to use. + +SOLUTION: + +Use Useful Inc's RSSWriter (http://usefulinc.com/rss/rsswriter/) + +DISCUSSION: + +An example of turning a Magpie parsed RSS object back into an RSS file is forth +coming. In the meantime RSSWriter has great documentation. + +4. DISPLAY HEADLINES MORE RECENT THEN X DATE + +PROBLEM: + +You only want to display headlines that were published on, or after a certain +date. + + +SOLUTION: + +require 'rss_utils.inc'; + +# get all headlines published today +$today = getdate(); + +# today, 12AM +$date = mktime(0,0,0,$today['mon'], $today['mday'], $today['year']); + +$rss = fetch_rss($url); + +foreach ( $rss->items as $item ) { + $published = parse_w3cdtf($item['dc']['date']); + if ( $published >= $date ) { + echo "Title: " . $item['title']; + echo "Published: " . date("h:i:s A", $published); + echo "

"; + } +} + +DISCUSSION: + +This recipe only works for RSS 1.0 feeds that include the field. +(which is very good RSS style) + +parse_w3cdtf is defined in rss_utils.inc, and parses RSS style dates into Unix +epoch seconds. + +See: http://www.php.net/manual/en/ref.datetime.php Added: trunk/ofrenda-blog/html/librerias/magpierss/extlib/Snoopy.class.inc =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/extlib/Snoopy.class.inc 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/extlib/Snoopy.class.inc 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,1257 @@ + +Copyright (c): 1999-2000 ispi, all rights reserved +Version: 1.01 + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +You may contact the author of Snoopy by e-mail at: +monte@ispi.net + +Or, write to: +Monte Ohrt +CTO, ispi +237 S. 70th suite 220 +Lincoln, NE 68510 + +The latest version of Snoopy can be obtained from: +http://snoopy.sourceforge.net/ + +*************************************************/ + +class Snoopy +{ + /**** Public variables ****/ + + /* user definable vars */ + + var $host = "www.php.net"; // host name we are connecting to + var $port = 80; // port we are connecting to + var $proxy_host = ""; // proxy host to use + var $proxy_port = ""; // proxy port to use + var $proxy_user = ""; // proxy user to use + var $proxy_pass = ""; // proxy password to use + + var $agent = "Snoopy v1.2.3"; // agent we masquerade as + var $referer = ""; // referer info to pass + var $cookies = array(); // array of cookies to pass + // $cookies["username"]="joe"; + var $rawheaders = array(); // array of raw headers to send + // $rawheaders["Content-type"]="text/html"; + + var $maxredirs = 5; // http redirection depth maximum. 0 = disallow + var $lastredirectaddr = ""; // contains address of last redirected address + var $offsiteok = true; // allows redirection off-site + var $maxframes = 0; // frame content depth maximum. 0 = disallow + var $expandlinks = true; // expand links to fully qualified URLs. + // this only applies to fetchlinks() + // submitlinks(), and submittext() + var $passcookies = true; // pass set cookies back through redirects + // NOTE: this currently does not respect + // dates, domains or paths. + + var $user = ""; // user for http authentication + var $pass = ""; // password for http authentication + + // http accept types + var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + + var $results = ""; // where the content is put + + var $error = ""; // error messages sent here + var $response_code = ""; // response code returned from server + var $headers = array(); // headers returned from server sent here + var $maxlength = 500000; // max return data length (body) + var $read_timeout = 0; // timeout on read operations, in seconds + // supported only since PHP 4 Beta 4 + // set to 0 to disallow timeouts + var $timed_out = false; // if a read operation timed out + var $status = 0; // http request status + + var $temp_dir = "/tmp"; // temporary directory that the webserver + // has permission to write to. + // under Windows, this should be C:\temp + + var $curl_path = "/usr/local/bin/curl"; + // Snoopy will use cURL for fetching + // SSL content if a full system path to + // the cURL binary is supplied here. + // set to false if you do not have + // cURL installed. See http://curl.haxx.se + // for details on installing cURL. + // Snoopy does *not* use the cURL + // library functions built into php, + // as these functions are not stable + // as of this Snoopy release. + + /**** Private variables ****/ + + var $_maxlinelen = 4096; // max line length (headers) + + var $_httpmethod = "GET"; // default http request method + var $_httpversion = "HTTP/1.0"; // default http request version + var $_submit_method = "POST"; // default submit method + var $_submit_type = "application/x-www-form-urlencoded"; // default submit type + var $_mime_boundary = ""; // MIME boundary for multipart/form-data submit type + var $_redirectaddr = false; // will be set if page fetched is a redirect + var $_redirectdepth = 0; // increments on an http redirect + var $_frameurls = array(); // frame src urls + var $_framedepth = 0; // increments on frame depth + + var $_isproxy = false; // set if using a proxy server + var $_fp_timeout = 30; // timeout for socket connection + +/*======================================================================*\ + Function: fetch + Purpose: fetch the contents of a web page + (and possibly other protocols in the + future like ftp, nntp, gopher, etc.) + Input: $URI the location of the page to fetch + Output: $this->results the output text from the fetch +\*======================================================================*/ + + function fetch($URI) + { + + //preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS); + $URI_PARTS = parse_url($URI); + if (!empty($URI_PARTS["user"])) + $this->user = $URI_PARTS["user"]; + if (!empty($URI_PARTS["pass"])) + $this->pass = $URI_PARTS["pass"]; + if (empty($URI_PARTS["query"])) + $URI_PARTS["query"] = ''; + if (empty($URI_PARTS["path"])) + $URI_PARTS["path"] = ''; + + switch(strtolower($URI_PARTS["scheme"])) + { + case "http": + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_connect($fp)) + { + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httprequest($URI,$fp,$URI,$this->_httpmethod); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httprequest($path, $fp, $URI, $this->_httpmethod); + } + + $this->_disconnect($fp); + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + $this->fetch($this->_redirectaddr); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + } + else + { + return false; + } + return true; + break; + case "https": + if(!$this->curl_path) + return false; + if(function_exists("is_executable")) + if (!is_executable($this->curl_path)) + return false; + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httpsrequest($URI,$URI,$this->_httpmethod); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httpsrequest($path, $URI, $this->_httpmethod); + } + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + $this->fetch($this->_redirectaddr); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + return true; + break; + default: + // not a valid protocol + $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + return false; + break; + } + return true; + } + +/*======================================================================*\ + Function: submit + Purpose: submit an http form + Input: $URI the location to post the data + $formvars the formvars to use. + format: $formvars["var"] = "val"; + $formfiles an array of files to submit + format: $formfiles["var"] = "/dir/filename.ext"; + Output: $this->results the text output from the post +\*======================================================================*/ + + function submit($URI, $formvars="", $formfiles="") + { + unset($postdata); + + $postdata = $this->_prepare_post_body($formvars, $formfiles); + + $URI_PARTS = parse_url($URI); + if (!empty($URI_PARTS["user"])) + $this->user = $URI_PARTS["user"]; + if (!empty($URI_PARTS["pass"])) + $this->pass = $URI_PARTS["pass"]; + if (empty($URI_PARTS["query"])) + $URI_PARTS["query"] = ''; + if (empty($URI_PARTS["path"])) + $URI_PARTS["path"] = ''; + + switch(strtolower($URI_PARTS["scheme"])) + { + case "http": + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_connect($fp)) + { + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httprequest($URI,$fp,$URI,$this->_submit_method,$this->_submit_type,$postdata); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + + $this->_disconnect($fp); + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) + $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); + + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + if( strpos( $this->_redirectaddr, "?" ) > 0 ) + $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get + else + $this->submit($this->_redirectaddr,$formvars, $formfiles); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + + } + else + { + return false; + } + return true; + break; + case "https": + if(!$this->curl_path) + return false; + if(function_exists("is_executable")) + if (!is_executable($this->curl_path)) + return false; + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httpsrequest($URI, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httpsrequest($path, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) + $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); + + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + if( strpos( $this->_redirectaddr, "?" ) > 0 ) + $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get + else + $this->submit($this->_redirectaddr,$formvars, $formfiles); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + return true; + break; + + default: + // not a valid protocol + $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + return false; + break; + } + return true; + } + +/*======================================================================*\ + Function: fetchlinks + Purpose: fetch the links from a web page + Input: $URI where you are fetching from + Output: $this->results an array of the URLs +\*======================================================================*/ + + function fetchlinks($URI) + { + if ($this->fetch($URI)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_striplinks($this->results[$x]); + } + else + $this->results = $this->_striplinks($this->results); + + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results, $URI); + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: fetchform + Purpose: fetch the form elements from a web page + Input: $URI where you are fetching from + Output: $this->results the resulting html form +\*======================================================================*/ + + function fetchform($URI) + { + + if ($this->fetch($URI)) + { + + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_stripform($this->results[$x]); + } + else + $this->results = $this->_stripform($this->results); + + return true; + } + else + return false; + } + + +/*======================================================================*\ + Function: fetchtext + Purpose: fetch the text from a web page, stripping the links + Input: $URI where you are fetching from + Output: $this->results the text from the web page +\*======================================================================*/ + + function fetchtext($URI) + { + if($this->fetch($URI)) + { + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_striptext($this->results[$x]); + } + else + $this->results = $this->_striptext($this->results); + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: submitlinks + Purpose: grab links from a form submission + Input: $URI where you are submitting from + Output: $this->results an array of the links from the post +\*======================================================================*/ + + function submitlinks($URI, $formvars="", $formfiles="") + { + if($this->submit($URI,$formvars, $formfiles)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + { + $this->results[$x] = $this->_striplinks($this->results[$x]); + if($this->expandlinks) + $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); + } + } + else + { + $this->results = $this->_striplinks($this->results); + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results,$URI); + } + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: submittext + Purpose: grab text from a form submission + Input: $URI where you are submitting from + Output: $this->results the text from the web page +\*======================================================================*/ + + function submittext($URI, $formvars = "", $formfiles = "") + { + if($this->submit($URI,$formvars, $formfiles)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + { + $this->results[$x] = $this->_striptext($this->results[$x]); + if($this->expandlinks) + $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); + } + } + else + { + $this->results = $this->_striptext($this->results); + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results,$URI); + } + return true; + } + else + return false; + } + + + +/*======================================================================*\ + Function: set_submit_multipart + Purpose: Set the form submission content type to + multipart/form-data +\*======================================================================*/ + function set_submit_multipart() + { + $this->_submit_type = "multipart/form-data"; + } + + +/*======================================================================*\ + Function: set_submit_normal + Purpose: Set the form submission content type to + application/x-www-form-urlencoded +\*======================================================================*/ + function set_submit_normal() + { + $this->_submit_type = "application/x-www-form-urlencoded"; + } + + + + +/*======================================================================*\ + Private functions +\*======================================================================*/ + + +/*======================================================================*\ + Function: _striplinks + Purpose: strip the hyperlinks from an html document + Input: $document document to strip. + Output: $match an array of the links +\*======================================================================*/ + + function _striplinks($document) + { + preg_match_all("'<\s*a\s.*?href\s*=\s* # find ]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space + 'isx",$document,$links); + + + // catenate the non-empty matches from the conditional subpattern + + while(list($key,$val) = each($links[2])) + { + if(!empty($val)) + $match[] = $val; + } + + while(list($key,$val) = each($links[3])) + { + if(!empty($val)) + $match[] = $val; + } + + // return the links + return $match; + } + +/*======================================================================*\ + Function: _stripform + Purpose: strip the form elements from an html document + Input: $document document to strip. + Output: $match an array of the links +\*======================================================================*/ + + function _stripform($document) + { + preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements); + + // catenate the matches + $match = implode("\r\n",$elements[0]); + + // return the links + return $match; + } + + + +/*======================================================================*\ + Function: _striptext + Purpose: strip the text from an html document + Input: $document document to strip. + Output: $text the resulting text +\*======================================================================*/ + + function _striptext($document) + { + + // I didn't use preg eval (//e) since that is only available in PHP 4.0. + // so, list your entities one by one here. I included some of the + // more common ones. + + $search = array("']*?>.*?'si", // strip out javascript + "'<[\/\!]*?[^<>]*?>'si", // strip out html tags + "'([\r\n])[\s]+'", // strip out white space + "'&(quot|#34|#034|#x22);'i", // replace html entities + "'&(amp|#38|#038|#x26);'i", // added hexadecimal values + "'&(lt|#60|#060|#x3c);'i", + "'&(gt|#62|#062|#x3e);'i", + "'&(nbsp|#160|#xa0);'i", + "'&(iexcl|#161);'i", + "'&(cent|#162);'i", + "'&(pound|#163);'i", + "'&(copy|#169);'i", + "'&(reg|#174);'i", + "'&(deg|#176);'i", + "'&(#39|#039|#x27);'", + "'&(euro|#8364);'i", // europe + "'&a(uml|UML);'", // german + "'&o(uml|UML);'", + "'&u(uml|UML);'", + "'&A(uml|UML);'", + "'&O(uml|UML);'", + "'&U(uml|UML);'", + "'ß'i", + ); + $replace = array( "", + "", + "\\1", + "\"", + "&", + "<", + ">", + " ", + chr(161), + chr(162), + chr(163), + chr(169), + chr(174), + chr(176), + chr(39), + chr(128), + "ä", + "ö", + "ü", + "Ä", + "Ö", + "Ü", + "ß", + ); + + $text = preg_replace($search,$replace,$document); + + return $text; + } + +/*======================================================================*\ + Function: _expandlinks + Purpose: expand each link into a fully qualified URL + Input: $links the links to qualify + $URI the full URI to get the base from + Output: $expandedLinks the expanded links +\*======================================================================*/ + + function _expandlinks($links,$URI) + { + + preg_match("/^[^\?]+/",$URI,$match); + + $match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]); + $match = preg_replace("|/$|","",$match); + $match_part = parse_url($match); + $match_root = + $match_part["scheme"]."://".$match_part["host"]; + + $search = array( "|^http://".preg_quote($this->host)."|i", + "|^(\/)|i", + "|^(?!http://)(?!mailto:)|i", + "|/\./|", + "|/[^\/]+/\.\./|" + ); + + $replace = array( "", + $match_root."/", + $match."/", + "/", + "/" + ); + + $expandedLinks = preg_replace($search,$replace,$links); + + return $expandedLinks; + } + +/*======================================================================*\ + Function: _httprequest + Purpose: go get the http data from the server + Input: $url the url to fetch + $fp the current open file pointer + $URI the full URI + $body body contents to send if any (POST) + Output: +\*======================================================================*/ + + function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="") + { + $cookie_headers = ''; + if($this->passcookies && $this->_redirectaddr) + $this->setcookies(); + + $URI_PARTS = parse_url($URI); + if(empty($url)) + $url = "/"; + $headers = $http_method." ".$url." ".$this->_httpversion."\r\n"; + if(!empty($this->agent)) + $headers .= "User-Agent: ".$this->agent."\r\n"; + if(!empty($this->host) && !isset($this->rawheaders['Host'])) { + $headers .= "Host: ".$this->host; + if(!empty($this->port)) + $headers .= ":".$this->port; + $headers .= "\r\n"; + } + if(!empty($this->accept)) + $headers .= "Accept: ".$this->accept."\r\n"; + if(!empty($this->referer)) + $headers .= "Referer: ".$this->referer."\r\n"; + if(!empty($this->cookies)) + { + if(!is_array($this->cookies)) + $this->cookies = (array)$this->cookies; + + reset($this->cookies); + if ( count($this->cookies) > 0 ) { + $cookie_headers .= 'Cookie: '; + foreach ( $this->cookies as $cookieKey => $cookieVal ) { + $cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; "; + } + $headers .= substr($cookie_headers,0,-2) . "\r\n"; + } + } + if(!empty($this->rawheaders)) + { + if(!is_array($this->rawheaders)) + $this->rawheaders = (array)$this->rawheaders; + while(list($headerKey,$headerVal) = each($this->rawheaders)) + $headers .= $headerKey.": ".$headerVal."\r\n"; + } + if(!empty($content_type)) { + $headers .= "Content-type: $content_type"; + if ($content_type == "multipart/form-data") + $headers .= "; boundary=".$this->_mime_boundary; + $headers .= "\r\n"; + } + if(!empty($body)) + $headers .= "Content-length: ".strlen($body)."\r\n"; + if(!empty($this->user) || !empty($this->pass)) + $headers .= "Authorization: Basic ".base64_encode($this->user.":".$this->pass)."\r\n"; + + //add proxy auth headers + if(!empty($this->proxy_user)) + $headers .= 'Proxy-Authorization: ' . 'Basic ' . base64_encode($this->proxy_user . ':' . $this->proxy_pass)."\r\n"; + + + $headers .= "\r\n"; + + // set the read timeout if needed + if ($this->read_timeout > 0) + socket_set_timeout($fp, $this->read_timeout); + $this->timed_out = false; + + fwrite($fp,$headers.$body,strlen($headers.$body)); + + $this->_redirectaddr = false; + unset($this->headers); + + while($currentHeader = fgets($fp,$this->_maxlinelen)) + { + if ($this->read_timeout > 0 && $this->_check_timeout($fp)) + { + $this->status=-100; + return false; + } + + if($currentHeader == "\r\n") + break; + + // if a header begins with Location: or URI:, set the redirect + if(preg_match("/^(Location:|URI:)/i",$currentHeader)) + { + // get URL portion of the redirect + preg_match("/^(Location:|URI:)[ ]+(.*)/i",chop($currentHeader),$matches); + // look for :// in the Location header to see if hostname is included + if(!preg_match("|\:\/\/|",$matches[2])) + { + // no host in the path, so prepend + $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; + // eliminate double slash + if(!preg_match("|^/|",$matches[2])) + $this->_redirectaddr .= "/".$matches[2]; + else + $this->_redirectaddr .= $matches[2]; + } + else + $this->_redirectaddr = $matches[2]; + } + + if(preg_match("|^HTTP/|",$currentHeader)) + { + if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status)) + { + $this->status= $status[1]; + } + $this->response_code = $currentHeader; + } + + $this->headers[] = $currentHeader; + } + + $results = ''; + do { + $_data = fread($fp, $this->maxlength); + if (strlen($_data) == 0) { + break; + } + $results .= $_data; + } while(true); + + if ($this->read_timeout > 0 && $this->_check_timeout($fp)) + { + $this->status=-100; + return false; + } + + // check if there is a a redirect meta tag + + if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) + + { + $this->_redirectaddr = $this->_expandlinks($match[1],$URI); + } + + // have we hit our frame depth and is there frame src to fetch? + if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) + { + $this->results[] = $results; + for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); + } + // have we already fetched framed content? + elseif(is_array($this->results)) + $this->results[] = $results; + // no framed content + else + $this->results = $results; + + return true; + } + +/*======================================================================*\ + Function: _httpsrequest + Purpose: go get the https data from the server using curl + Input: $url the url to fetch + $URI the full URI + $body body contents to send if any (POST) + Output: +\*======================================================================*/ + + function _httpsrequest($url,$URI,$http_method,$content_type="",$body="") + { + if($this->passcookies && $this->_redirectaddr) + $this->setcookies(); + + $headers = array(); + + $URI_PARTS = parse_url($URI); + if(empty($url)) + $url = "/"; + // GET ... header not needed for curl + //$headers[] = $http_method." ".$url." ".$this->_httpversion; + if(!empty($this->agent)) + $headers[] = "User-Agent: ".$this->agent; + if(!empty($this->host)) + if(!empty($this->port)) + $headers[] = "Host: ".$this->host.":".$this->port; + else + $headers[] = "Host: ".$this->host; + if(!empty($this->accept)) + $headers[] = "Accept: ".$this->accept; + if(!empty($this->referer)) + $headers[] = "Referer: ".$this->referer; + if(!empty($this->cookies)) + { + if(!is_array($this->cookies)) + $this->cookies = (array)$this->cookies; + + reset($this->cookies); + if ( count($this->cookies) > 0 ) { + $cookie_str = 'Cookie: '; + foreach ( $this->cookies as $cookieKey => $cookieVal ) { + $cookie_str .= $cookieKey."=".urlencode($cookieVal)."; "; + } + $headers[] = substr($cookie_str,0,-2); + } + } + if(!empty($this->rawheaders)) + { + if(!is_array($this->rawheaders)) + $this->rawheaders = (array)$this->rawheaders; + while(list($headerKey,$headerVal) = each($this->rawheaders)) + $headers[] = $headerKey.": ".$headerVal; + } + if(!empty($content_type)) { + if ($content_type == "multipart/form-data") + $headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary; + else + $headers[] = "Content-type: $content_type"; + } + if(!empty($body)) + $headers[] = "Content-length: ".strlen($body); + if(!empty($this->user) || !empty($this->pass)) + $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass); + + for($curr_header = 0; $curr_header < count($headers); $curr_header++) { + $safer_header = strtr( $headers[$curr_header], "\"", " " ); + $cmdline_params .= " -H \"".$safer_header."\""; + } + + if(!empty($body)) + $cmdline_params .= " -d \"$body\""; + + if($this->read_timeout > 0) + $cmdline_params .= " -m ".$this->read_timeout; + + $headerfile = tempnam($temp_dir, "sno"); + + $safer_URI = strtr( $URI, "\"", " " ); // strip quotes from the URI to avoid shell access + exec($this->curl_path." -D \"$headerfile\"".$cmdline_params." \"".$safer_URI."\"",$results,$return); + + if($return) + { + $this->error = "Error: cURL could not retrieve the document, error $return."; + return false; + } + + + $results = implode("\r\n",$results); + + $result_headers = file("$headerfile"); + + $this->_redirectaddr = false; + unset($this->headers); + + for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++) + { + + // if a header begins with Location: or URI:, set the redirect + if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader])) + { + // get URL portion of the redirect + preg_match("/^(Location: |URI:)\s+(.*)/",chop($result_headers[$currentHeader]),$matches); + // look for :// in the Location header to see if hostname is included + if(!preg_match("|\:\/\/|",$matches[2])) + { + // no host in the path, so prepend + $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; + // eliminate double slash + if(!preg_match("|^/|",$matches[2])) + $this->_redirectaddr .= "/".$matches[2]; + else + $this->_redirectaddr .= $matches[2]; + } + else + $this->_redirectaddr = $matches[2]; + } + + if(preg_match("|^HTTP/|",$result_headers[$currentHeader])) + $this->response_code = $result_headers[$currentHeader]; + + $this->headers[] = $result_headers[$currentHeader]; + } + + // check if there is a a redirect meta tag + + if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) + { + $this->_redirectaddr = $this->_expandlinks($match[1],$URI); + } + + // have we hit our frame depth and is there frame src to fetch? + if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) + { + $this->results[] = $results; + for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); + } + // have we already fetched framed content? + elseif(is_array($this->results)) + $this->results[] = $results; + // no framed content + else + $this->results = $results; + + unlink("$headerfile"); + + return true; + } + +/*======================================================================*\ + Function: setcookies() + Purpose: set cookies for a redirection +\*======================================================================*/ + + function setcookies() + { + for($x=0; $xheaders); $x++) + { + if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x],$match)) + $this->cookies[$match[1]] = urldecode($match[2]); + } + } + + +/*======================================================================*\ + Function: _check_timeout + Purpose: checks whether timeout has occurred + Input: $fp file pointer +\*======================================================================*/ + + function _check_timeout($fp) + { + if ($this->read_timeout > 0) { + $fp_status = socket_get_status($fp); + if ($fp_status["timed_out"]) { + $this->timed_out = true; + return true; + } + } + return false; + } + +/*======================================================================*\ + Function: _connect + Purpose: make a socket connection + Input: $fp file pointer +\*======================================================================*/ + + function _connect(&$fp) + { + if(!empty($this->proxy_host) && !empty($this->proxy_port)) + { + $this->_isproxy = true; + + $host = $this->proxy_host; + $port = $this->proxy_port; + } + else + { + $host = $this->host; + $port = $this->port; + } + + $this->status = 0; + + if($fp = fsockopen( + $host, + $port, + $errno, + $errstr, + $this->_fp_timeout + )) + { + // socket connection succeeded + + return true; + } + else + { + // socket connection failed + $this->status = $errno; + switch($errno) + { + case -3: + $this->error="socket creation failed (-3)"; + case -4: + $this->error="dns lookup failure (-4)"; + case -5: + $this->error="connection refused or timed out (-5)"; + default: + $this->error="connection failed (".$errno.")"; + } + return false; + } + } +/*======================================================================*\ + Function: _disconnect + Purpose: disconnect a socket connection + Input: $fp file pointer +\*======================================================================*/ + + function _disconnect($fp) + { + return(fclose($fp)); + } + + +/*======================================================================*\ + Function: _prepare_post_body + Purpose: Prepare post body according to encoding type + Input: $formvars - form variables + $formfiles - form upload files + Output: post body +\*======================================================================*/ + + function _prepare_post_body($formvars, $formfiles) + { + settype($formvars, "array"); + settype($formfiles, "array"); + $postdata = ''; + + if (count($formvars) == 0 && count($formfiles) == 0) + return; + + switch ($this->_submit_type) { + case "application/x-www-form-urlencoded": + reset($formvars); + while(list($key,$val) = each($formvars)) { + if (is_array($val) || is_object($val)) { + while (list($cur_key, $cur_val) = each($val)) { + $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&"; + } + } else + $postdata .= urlencode($key)."=".urlencode($val)."&"; + } + break; + + case "multipart/form-data": + $this->_mime_boundary = "Snoopy".md5(uniqid(microtime())); + + reset($formvars); + while(list($key,$val) = each($formvars)) { + if (is_array($val) || is_object($val)) { + while (list($cur_key, $cur_val) = each($val)) { + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n"; + $postdata .= "$cur_val\r\n"; + } + } else { + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n"; + $postdata .= "$val\r\n"; + } + } + + reset($formfiles); + while (list($field_name, $file_names) = each($formfiles)) { + settype($file_names, "array"); + while (list(, $file_name) = each($file_names)) { + if (!is_readable($file_name)) continue; + + $fp = fopen($file_name, "r"); + $file_content = fread($fp, filesize($file_name)); + fclose($fp); + $base_name = basename($file_name); + + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n"; + $postdata .= "$file_content\r\n"; + } + } + $postdata .= "--".$this->_mime_boundary."--\r\n"; + break; + } + + return $postdata; + } +} + +?> Added: trunk/ofrenda-blog/html/librerias/magpierss/extlib/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/magpierss/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/magpierss/rss_cache.inc =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/rss_cache.inc 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/rss_cache.inc 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,200 @@ + + * Version: 0.51 + * License: GPL + * + * The lastest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * http://lists.sourceforge.net/lists/listinfo/magpierss-general + * + */ + +class RSSCache { + var $BASE_CACHE = './cache'; // where the cache files are stored + var $MAX_AGE = 3600; // when are files stale, default one hour + var $ERROR = ""; // accumulate error messages + + function RSSCache ($base='', $age='') { + if ( $base ) { + $this->BASE_CACHE = $base; + } + if ( $age ) { + $this->MAX_AGE = $age; + } + + // attempt to make the cache directory + if ( ! file_exists( $this->BASE_CACHE ) ) { + $status = @mkdir( $this->BASE_CACHE, 0755 ); + + // if make failed + if ( ! $status ) { + $this->error( + "Cache couldn't make dir '" . $this->BASE_CACHE . "'." + ); + } + } + } + +/*=======================================================================*\ + Function: set + Purpose: add an item to the cache, keyed on url + Input: url from wich the rss file was fetched + Output: true on sucess +\*=======================================================================*/ + function set ($url, $rss) { + $this->ERROR = ""; + $cache_file = $this->file_name( $url ); + $fp = @fopen( $cache_file, 'w' ); + + if ( ! $fp ) { + $this->error( + "Cache unable to open file for writing: $cache_file" + ); + return 0; + } + + + $data = $this->serialize( $rss ); + fwrite( $fp, $data ); + fclose( $fp ); + + return $cache_file; + } + +/*=======================================================================*\ + Function: get + Purpose: fetch an item from the cache + Input: url from wich the rss file was fetched + Output: cached object on HIT, false on MISS +\*=======================================================================*/ + function get ($url) { + $this->ERROR = ""; + $cache_file = $this->file_name( $url ); + + if ( ! file_exists( $cache_file ) ) { + $this->debug( + "Cache doesn't contain: $url (cache file: $cache_file)" + ); + return 0; + } + + $fp = @fopen($cache_file, 'r'); + if ( ! $fp ) { + $this->error( + "Failed to open cache file for reading: $cache_file" + ); + return 0; + } + + if ($filesize = filesize($cache_file) ) { + $data = fread( $fp, filesize($cache_file) ); + $rss = $this->unserialize( $data ); + + return $rss; + } + + return 0; + } + +/*=======================================================================*\ + Function: check_cache + Purpose: check a url for membership in the cache + and whether the object is older then MAX_AGE (ie. STALE) + Input: url from wich the rss file was fetched + Output: cached object on HIT, false on MISS +\*=======================================================================*/ + function check_cache ( $url ) { + $this->ERROR = ""; + $filename = $this->file_name( $url ); + + if ( file_exists( $filename ) ) { + // find how long ago the file was added to the cache + // and whether that is longer then MAX_AGE + $mtime = filemtime( $filename ); + $age = time() - $mtime; + if ( $this->MAX_AGE > $age ) { + // object exists and is current + return 'HIT'; + } + else { + // object exists but is old + return 'STALE'; + } + } + else { + // object does not exist + return 'MISS'; + } + } + + function cache_age( $cache_key ) { + $filename = $this->file_name( $url ); + if ( file_exists( $filename ) ) { + $mtime = filemtime( $filename ); + $age = time() - $mtime; + return $age; + } + else { + return -1; + } + } + +/*=======================================================================*\ + Function: serialize +\*=======================================================================*/ + function serialize ( $rss ) { + return serialize( $rss ); + } + +/*=======================================================================*\ + Function: unserialize +\*=======================================================================*/ + function unserialize ( $data ) { + return unserialize( $data ); + } + +/*=======================================================================*\ + Function: file_name + Purpose: map url to location in cache + Input: url from wich the rss file was fetched + Output: a file name +\*=======================================================================*/ + function file_name ($url) { + $filename = md5( $url ); + return join( DIRECTORY_SEPARATOR, array( $this->BASE_CACHE, $filename ) ); + } + +/*=======================================================================*\ + Function: error + Purpose: register error +\*=======================================================================*/ + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + $this->ERROR = $errormsg; + if ( MAGPIE_DEBUG ) { + trigger_error( $errormsg, $lvl); + } + else { + error_log( $errormsg, 0); + } + } + + function debug ($debugmsg, $lvl=E_USER_NOTICE) { + if ( MAGPIE_DEBUG ) { + $this->error("MagpieRSS [debug] $debugmsg", $lvl); + } + } + +} + +?> Added: trunk/ofrenda-blog/html/librerias/magpierss/rss_fetch.inc =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/rss_fetch.inc 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/rss_fetch.inc 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,458 @@ + + * License: GPL + * + * The lastest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * magpierss-general@lists.sourceforge.net + * + */ + +// Setup MAGPIE_DIR for use on hosts that don't include +// the current path in include_path. +// with thanks to rajiv and smarty +if (!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +if (!defined('MAGPIE_DIR')) { + define('MAGPIE_DIR', dirname(__FILE__) . DIR_SEP); +} + +require_once( MAGPIE_DIR . 'rss_parse.inc' ); +require_once( MAGPIE_DIR . 'rss_cache.inc' ); + +// for including 3rd party libraries +define('MAGPIE_EXTLIB', MAGPIE_DIR . 'extlib' . DIR_SEP); +require_once( MAGPIE_EXTLIB . 'Snoopy.class.inc'); + + +/* + * CONSTANTS - redefine these in your script to change the + * behaviour of fetch_rss() currently, most options effect the cache + * + * MAGPIE_CACHE_ON - Should Magpie cache parsed RSS objects? + * For me a built in cache was essential to creating a "PHP-like" + * feel to Magpie, see rss_cache.inc for rationale + * + * + * MAGPIE_CACHE_DIR - Where should Magpie cache parsed RSS objects? + * This should be a location that the webserver can write to. If this + * directory does not already exist Mapie will try to be smart and create + * it. This will often fail for permissions reasons. + * + * + * MAGPIE_CACHE_AGE - How long to store cached RSS objects? In seconds. + * + * + * MAGPIE_CACHE_FRESH_ONLY - If remote fetch fails, throw error + * instead of returning stale object? + * + * MAGPIE_DEBUG - Display debugging notices? + * +*/ + + +/*=======================================================================*\ + Function: fetch_rss: + Purpose: return RSS object for the give url + maintain the cache + Input: url of RSS file + Output: parsed RSS object (see rss_parse.inc) + + NOTES ON CACHEING: + If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache. + + NOTES ON RETRIEVING REMOTE FILES: + If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will + return a cached object, and touch the cache object upon recieving a + 304. + + NOTES ON FAILED REQUESTS: + If there is an HTTP error while fetching an RSS object, the cached + version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off) +\*=======================================================================*/ + +define('MAGPIE_VERSION', '0.72'); + +$MAGPIE_ERROR = ""; + +function fetch_rss ($url) { + // initialize constants + init(); + + if ( !isset($url) ) { + error("fetch_rss called without a url"); + return false; + } + + // if cache is disabled + if ( !MAGPIE_CACHE_ON ) { + // fetch file, and parse it + $resp = _fetch_remote_file( $url ); + if ( is_success( $resp->status ) ) { + return _response_to_rss( $resp ); + } + else { + error("Failed to fetch $url and cache is off"); + return false; + } + } + // else cache is ON + else { + // Flow + // 1. check cache + // 2. if there is a hit, make sure its fresh + // 3. if cached obj fails freshness check, fetch remote + // 4. if remote fails, return stale object, or error + + $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE ); + + if (MAGPIE_DEBUG and $cache->ERROR) { + debug($cache->ERROR, E_USER_WARNING); + } + + + $cache_status = 0; // response of check_cache + $request_headers = array(); // HTTP headers to send with fetch + $rss = 0; // parsed RSS object + $errormsg = 0; // errors, if any + + // store parsed XML by desired output encoding + // as character munging happens at parse time + $cache_key = $url . MAGPIE_OUTPUT_ENCODING; + + if (!$cache->ERROR) { + // return cache HIT, MISS, or STALE + $cache_status = $cache->check_cache( $cache_key); + } + + // if object cached, and cache is fresh, return cached obj + if ( $cache_status == 'HIT' ) { + $rss = $cache->get( $cache_key ); + if ( isset($rss) and $rss ) { + // should be cache age + $rss->from_cache = 1; + if ( MAGPIE_DEBUG > 1) { + debug("MagpieRSS: Cache HIT", E_USER_NOTICE); + } + return $rss; + } + } + + // else attempt a conditional get + + // setup headers + if ( $cache_status == 'STALE' ) { + $rss = $cache->get( $cache_key ); + if ( $rss and $rss->etag and $rss->last_modified ) { + $request_headers['If-None-Match'] = $rss->etag; + $request_headers['If-Last-Modified'] = $rss->last_modified; + } + } + + $resp = _fetch_remote_file( $url, $request_headers ); + + if (isset($resp) and $resp) { + if ($resp->status == '304' ) { + // we have the most current copy + if ( MAGPIE_DEBUG > 1) { + debug("Got 304 for $url"); + } + // reset cache on 304 (at minutillo insistent prodding) + $cache->set($cache_key, $rss); + return $rss; + } + elseif ( is_success( $resp->status ) ) { + $rss = _response_to_rss( $resp ); + if ( $rss ) { + if (MAGPIE_DEBUG > 1) { + debug("Fetch successful"); + } + // add object to cache + $cache->set( $cache_key, $rss ); + return $rss; + } + } + else { + $errormsg = "Failed to fetch $url "; + if ( $resp->status == '-100' ) { + $errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)"; + } + elseif ( $resp->error ) { + # compensate for Snoopy's annoying habbit to tacking + # on '\n' + $http_error = substr($resp->error, 0, -2); + $errormsg .= "(HTTP Error: $http_error)"; + } + else { + $errormsg .= "(HTTP Response: " . $resp->response_code .')'; + } + } + } + else { + $errormsg = "Unable to retrieve RSS file for unknown reasons."; + } + + // else fetch failed + + // attempt to return cached object + if ($rss) { + if ( MAGPIE_DEBUG ) { + debug("Returning STALE object for $url"); + } + return $rss; + } + + // else we totally failed + error( $errormsg ); + + return false; + + } // end if ( !MAGPIE_CACHE_ON ) { +} // end fetch_rss() + +/*=======================================================================*\ + Function: error + Purpose: set MAGPIE_ERROR, and trigger error +\*=======================================================================*/ + +function error ($errormsg, $lvl=E_USER_WARNING) { + global $MAGPIE_ERROR; + + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + if ( $errormsg ) { + $errormsg = "MagpieRSS: $errormsg"; + $MAGPIE_ERROR = $errormsg; + trigger_error( $errormsg, $lvl); + } +} + +function debug ($debugmsg, $lvl=E_USER_NOTICE) { + trigger_error("MagpieRSS [debug] $debugmsg", $lvl); +} + +/*=======================================================================*\ + Function: magpie_error + Purpose: accessor for the magpie error variable +\*=======================================================================*/ +function magpie_error ($errormsg="") { + global $MAGPIE_ERROR; + + if ( isset($errormsg) and $errormsg ) { + $MAGPIE_ERROR = $errormsg; + } + + return $MAGPIE_ERROR; +} + +/*=======================================================================*\ + Function: _fetch_remote_file + Purpose: retrieve an arbitrary remote file + Input: url of the remote file + headers to send along with the request (optional) + Output: an HTTP response object (see Snoopy.class.inc) +\*=======================================================================*/ +function _fetch_remote_file ($url, $headers = "" ) { + // Snoopy is an HTTP client in PHP + $client = new Snoopy(); + $client->agent = MAGPIE_USER_AGENT; + $client->read_timeout = MAGPIE_FETCH_TIME_OUT; + $client->use_gzip = MAGPIE_USE_GZIP; + if (is_array($headers) ) { + $client->rawheaders = $headers; + } + + @$client->fetch($url); + return $client; + +} + +/*=======================================================================*\ + Function: _response_to_rss + Purpose: parse an HTTP response object into an RSS object + Input: an HTTP response object (see Snoopy) + Output: parsed RSS object (see rss_parse) +\*=======================================================================*/ +function _response_to_rss ($resp) { + $rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING ); + + // if RSS parsed successfully + if ( $rss and !$rss->ERROR) { + + // find Etag, and Last-Modified + foreach($resp->headers as $h) { + // 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1" + if (strpos($h, ": ")) { + list($field, $val) = explode(": ", $h, 2); + } + else { + $field = $h; + $val = ""; + } + + if ( $field == 'ETag' ) { + $rss->etag = $val; + } + + if ( $field == 'Last-Modified' ) { + $rss->last_modified = $val; + } + } + + return $rss; + } // else construct error message + else { + $errormsg = "Failed to parse RSS file."; + + if ($rss) { + $errormsg .= " (" . $rss->ERROR . ")"; + } + error($errormsg); + + return false; + } // end if ($rss and !$rss->error) +} + +/*=======================================================================*\ + Function: init + Purpose: setup constants with default values + check for user overrides +\*=======================================================================*/ +function init () { + if ( defined('MAGPIE_INITALIZED') ) { + return; + } + else { + define('MAGPIE_INITALIZED', true); + } + + if ( !defined('MAGPIE_CACHE_ON') ) { + define('MAGPIE_CACHE_ON', true); + } + + if ( !defined('MAGPIE_CACHE_DIR') ) { + define('MAGPIE_CACHE_DIR', './cache'); + } + + if ( !defined('MAGPIE_CACHE_AGE') ) { + define('MAGPIE_CACHE_AGE', 60*60); // one hour + } + + if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) { + define('MAGPIE_CACHE_FRESH_ONLY', false); + } + + if ( !defined('MAGPIE_OUTPUT_ENCODING') ) { + define('MAGPIE_OUTPUT_ENCODING', 'ISO-8859-1'); + } + + if ( !defined('MAGPIE_INPUT_ENCODING') ) { + define('MAGPIE_INPUT_ENCODING', null); + } + + if ( !defined('MAGPIE_DETECT_ENCODING') ) { + define('MAGPIE_DETECT_ENCODING', true); + } + + if ( !defined('MAGPIE_DEBUG') ) { + define('MAGPIE_DEBUG', 0); + } + + if ( !defined('MAGPIE_USER_AGENT') ) { + $ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net'; + + if ( MAGPIE_CACHE_ON ) { + $ua = $ua . ')'; + } + else { + $ua = $ua . '; No cache)'; + } + + define('MAGPIE_USER_AGENT', $ua); + } + + if ( !defined('MAGPIE_FETCH_TIME_OUT') ) { + define('MAGPIE_FETCH_TIME_OUT', 5); // 5 second timeout + } + + // use gzip encoding to fetch rss files if supported? + if ( !defined('MAGPIE_USE_GZIP') ) { + define('MAGPIE_USE_GZIP', true); + } +} + +// NOTE: the following code should really be in Snoopy, or at least +// somewhere other then rss_fetch! + +/*=======================================================================*\ + HTTP STATUS CODE PREDICATES + These functions attempt to classify an HTTP status code + based on RFC 2616 and RFC 2518. + + All of them take an HTTP status code as input, and return true or false + + All this code is adapted from LWP's HTTP::Status. +\*=======================================================================*/ + + +/*=======================================================================*\ + Function: is_info + Purpose: return true if Informational status code +\*=======================================================================*/ +function is_info ($sc) { + return $sc >= 100 && $sc < 200; +} + +/*=======================================================================*\ + Function: is_success + Purpose: return true if Successful status code +\*=======================================================================*/ +function is_success ($sc) { + return $sc >= 200 && $sc < 300; +} + +/*=======================================================================*\ + Function: is_redirect + Purpose: return true if Redirection status code +\*=======================================================================*/ +function is_redirect ($sc) { + return $sc >= 300 && $sc < 400; +} + +/*=======================================================================*\ + Function: is_error + Purpose: return true if Error status code +\*=======================================================================*/ +function is_error ($sc) { + return $sc >= 400 && $sc < 600; +} + +/*=======================================================================*\ + Function: is_client_error + Purpose: return true if Error status code, and its a client error +\*=======================================================================*/ +function is_client_error ($sc) { + return $sc >= 400 && $sc < 500; +} + +/*=======================================================================*\ + Function: is_client_error + Purpose: return true if Error status code, and its a server error +\*=======================================================================*/ +function is_server_error ($sc) { + return $sc >= 500 && $sc < 600; +} + +?> Added: trunk/ofrenda-blog/html/librerias/magpierss/rss_parse.inc =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/rss_parse.inc 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/rss_parse.inc 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,605 @@ + +* @version 0.7a +* @license GPL +* +*/ + +define('RSS', 'RSS'); +define('ATOM', 'Atom'); + +require_once (MAGPIE_DIR . 'rss_utils.inc'); + +/** +* Hybrid parser, and object, takes RSS as a string and returns a simple object. +* +* see: rss_fetch.inc for a simpler interface with integrated caching support +* +*/ +class MagpieRSS { + var $parser; + + var $current_item = array(); // item currently being parsed + var $items = array(); // collection of parsed items + var $channel = array(); // hash of channel fields + var $textinput = array(); + var $image = array(); + var $feed_type; + var $feed_version; + var $encoding = ''; // output encoding of parsed rss + + var $_source_encoding = ''; // only set if we have to parse xml prolog + + var $ERROR = ""; + var $WARNING = ""; + + // define some constants + + var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright'); + var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'ISO-8859-1'); + + // parser variables, useless if you're not a parser, treat as private + var $stack = array(); // parser stack + var $inchannel = false; + var $initem = false; + var $incontent = false; // if in Atom field + var $intextinput = false; + var $inimage = false; + var $current_namespace = false; + + + /** + * Set up XML parser, parse source, and return populated RSS object.. + * + * @param string $source string containing the RSS to be parsed + * + * NOTE: Probably a good idea to leave the encoding options alone unless + * you know what you're doing as PHP's character set support is + * a little weird. + * + * NOTE: A lot of this is unnecessary but harmless with PHP5 + * + * + * @param string $output_encoding output the parsed RSS in this character + * set defaults to ISO-8859-1 as this is PHP's + * default. + * + * NOTE: might be changed to UTF-8 in future + * versions. + * + * @param string $input_encoding the character set of the incoming RSS source. + * Leave blank and Magpie will try to figure it + * out. + * + * + * @param bool $detect_encoding if false Magpie won't attempt to detect + * source encoding. (caveat emptor) + * + */ + function MagpieRSS ($source, $output_encoding='ISO-8859-1', + $input_encoding=null, $detect_encoding=true) + { + # if PHP xml isn't compiled in, die + # + if (!function_exists('xml_parser_create')) { + $this->error( "Failed to load PHP's XML Extension. " . + "http://www.php.net/manual/en/ref.xml.php", + E_USER_ERROR ); + } + + list($parser, $source) = $this->create_parser($source, + $output_encoding, $input_encoding, $detect_encoding); + + + if (!is_resource($parser)) { + $this->error( "Failed to create an instance of PHP's XML parser. " . + "http://www.php.net/manual/en/ref.xml.php", + E_USER_ERROR ); + } + + + $this->parser = $parser; + + # pass in parser, and a reference to this object + # setup handlers + # + xml_set_object( $this->parser, $this ); + xml_set_element_handler($this->parser, + 'feed_start_element', 'feed_end_element' ); + + xml_set_character_data_handler( $this->parser, 'feed_cdata' ); + + $status = xml_parse( $this->parser, $source ); + + if (! $status ) { + $errorcode = xml_get_error_code( $this->parser ); + if ( $errorcode != XML_ERROR_NONE ) { + $xml_error = xml_error_string( $errorcode ); + $error_line = xml_get_current_line_number($this->parser); + $error_col = xml_get_current_column_number($this->parser); + $errormsg = "$xml_error at line $error_line, column $error_col"; + + $this->error( $errormsg ); + } + } + + xml_parser_free( $this->parser ); + + $this->normalize(); + } + + function feed_start_element($p, $element, &$attrs) { + $el = $element = strtolower($element); + $attrs = array_change_key_case($attrs, CASE_LOWER); + + // check for a namespace, and split if found + $ns = false; + if ( strpos( $element, ':' ) ) { + list($ns, $el) = split( ':', $element, 2); + } + if ( $ns and $ns != 'rdf' ) { + $this->current_namespace = $ns; + } + + # if feed type isn't set, then this is first element of feed + # identify feed from root element + # + if (!isset($this->feed_type) ) { + if ( $el == 'rdf' ) { + $this->feed_type = RSS; + $this->feed_version = '1.0'; + } + elseif ( $el == 'rss' ) { + $this->feed_type = RSS; + $this->feed_version = $attrs['version']; + } + elseif ( $el == 'feed' ) { + $this->feed_type = ATOM; + $this->feed_version = $attrs['version']; + $this->inchannel = true; + } + return; + } + + if ( $el == 'channel' ) + { + $this->inchannel = true; + } + elseif ($el == 'item' or $el == 'entry' ) + { + $this->initem = true; + if ( isset($attrs['rdf:about']) ) { + $this->current_item['about'] = $attrs['rdf:about']; + } + } + + // if we're in the default namespace of an RSS feed, + // record textinput or image fields + elseif ( + $this->feed_type == RSS and + $this->current_namespace == '' and + $el == 'textinput' ) + { + $this->intextinput = true; + } + + elseif ( + $this->feed_type == RSS and + $this->current_namespace == '' and + $el == 'image' ) + { + $this->inimage = true; + } + + # handle atom content constructs + elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) + { + // avoid clashing w/ RSS mod_content + if ($el == 'content' ) { + $el = 'atom_content'; + } + + $this->incontent = $el; + + + } + + // if inside an Atom content construct (e.g. content or summary) field treat tags as text + elseif ($this->feed_type == ATOM and $this->incontent ) + { + // if tags are inlined, then flatten + $attrs_str = join(' ', + array_map('map_attrs', + array_keys($attrs), + array_values($attrs) ) ); + + $this->append_content( "<$element $attrs_str>" ); + + array_unshift( $this->stack, $el ); + } + + // Atom support many links per containging element. + // Magpie treats link elements of type rel='alternate' + // as being equivalent to RSS's simple link element. + // + elseif ($this->feed_type == ATOM and $el == 'link' ) + { + if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' ) + { + $link_el = 'link'; + } + else { + $link_el = 'link_' . $attrs['rel']; + } + + $this->append($link_el, $attrs['href']); + } + // set stack[0] to current element + else { + array_unshift($this->stack, $el); + } + } + + + + function feed_cdata ($p, $text) { + if ($this->feed_type == ATOM and $this->incontent) + { + $this->append_content( $text ); + } + else { + $current_el = join('_', array_reverse($this->stack)); + $this->append($current_el, $text); + } + } + + function feed_end_element ($p, $el) { + $el = strtolower($el); + + if ( $el == 'item' or $el == 'entry' ) + { + $this->items[] = $this->current_item; + $this->current_item = array(); + $this->initem = false; + } + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' ) + { + $this->intextinput = false; + } + elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' ) + { + $this->inimage = false; + } + elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) ) + { + $this->incontent = false; + } + elseif ($el == 'channel' or $el == 'feed' ) + { + $this->inchannel = false; + } + elseif ($this->feed_type == ATOM and $this->incontent ) { + // balance tags properly + // note: i don't think this is actually neccessary + if ( $this->stack[0] == $el ) + { + $this->append_content(""); + } + else { + $this->append_content("<$el />"); + } + + array_shift( $this->stack ); + } + else { + array_shift( $this->stack ); + } + + $this->current_namespace = false; + } + + function concat (&$str1, $str2="") { + if (!isset($str1) ) { + $str1=""; + } + $str1 .= $str2; + } + + + + function append_content($text) { + if ( $this->initem ) { + $this->concat( $this->current_item[ $this->incontent ], $text ); + } + elseif ( $this->inchannel ) { + $this->concat( $this->channel[ $this->incontent ], $text ); + } + } + + // smart append - field and namespace aware + function append($el, $text) { + if (!$el) { + return; + } + if ( $this->current_namespace ) + { + if ( $this->initem ) { + $this->concat( + $this->current_item[ $this->current_namespace ][ $el ], $text); + } + elseif ($this->inchannel) { + $this->concat( + $this->channel[ $this->current_namespace][ $el ], $text ); + } + elseif ($this->intextinput) { + $this->concat( + $this->textinput[ $this->current_namespace][ $el ], $text ); + } + elseif ($this->inimage) { + $this->concat( + $this->image[ $this->current_namespace ][ $el ], $text ); + } + } + else { + if ( $this->initem ) { + $this->concat( + $this->current_item[ $el ], $text); + } + elseif ($this->intextinput) { + $this->concat( + $this->textinput[ $el ], $text ); + } + elseif ($this->inimage) { + $this->concat( + $this->image[ $el ], $text ); + } + elseif ($this->inchannel) { + $this->concat( + $this->channel[ $el ], $text ); + } + + } + } + + function normalize () { + // if atom populate rss fields + if ( $this->is_atom() ) { + $this->channel['description'] = $this->channel['tagline']; + for ( $i = 0; $i < count($this->items); $i++) { + $item = $this->items[$i]; + if ( isset($item['summary']) ) + $item['description'] = $item['summary']; + if ( isset($item['atom_content'])) + $item['content']['encoded'] = $item['atom_content']; + + $atom_date = (isset($item['issued']) ) ? $item['issued'] : $item['modified']; + if ( $atom_date ) { + $epoch = @parse_w3cdtf($atom_date); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $this->items[$i] = $item; + } + } + elseif ( $this->is_rss() ) { + $this->channel['tagline'] = $this->channel['description']; + for ( $i = 0; $i < count($this->items); $i++) { + $item = $this->items[$i]; + if ( isset($item['description'])) + $item['summary'] = $item['description']; + if ( isset($item['content']['encoded'] ) ) + $item['atom_content'] = $item['content']['encoded']; + + if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) { + $epoch = @parse_w3cdtf($item['dc']['date']); + if ($epoch and $epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + elseif ( isset($item['pubdate']) ) { + $epoch = @strtotime($item['pubdate']); + if ($epoch > 0) { + $item['date_timestamp'] = $epoch; + } + } + + $this->items[$i] = $item; + } + } + } + + + function is_rss () { + if ( $this->feed_type == RSS ) { + return $this->feed_version; + } + else { + return false; + } + } + + function is_atom() { + if ( $this->feed_type == ATOM ) { + return $this->feed_version; + } + else { + return false; + } + } + + /** + * return XML parser, and possibly re-encoded source + * + */ + function create_parser($source, $out_enc, $in_enc, $detect) { + if ( substr(phpversion(),0,1) == 5) { + $parser = $this->php5_create_parser($in_enc, $detect); + } + else { + list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect); + } + if ($out_enc) { + $this->encoding = $out_enc; + xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc); + } + + return array($parser, $source); + } + + /** + * Instantiate an XML parser under PHP5 + * + * PHP5 will do a fine job of detecting input encoding + * if passed an empty string as the encoding. + * + * All hail libxml2! + * + */ + function php5_create_parser($in_enc, $detect) { + // by default php5 does a fine job of detecting input encodings + if(!$detect && $in_enc) { + return xml_parser_create($in_enc); + } + else { + return xml_parser_create(''); + } + } + + /** + * Instaniate an XML parser under PHP4 + * + * Unfortunately PHP4's support for character encodings + * and especially XML and character encodings sucks. As + * long as the documents you parse only contain characters + * from the ISO-8859-1 character set (a superset of ASCII, + * and a subset of UTF-8) you're fine. However once you + * step out of that comfy little world things get mad, bad, + * and dangerous to know. + * + * The following code is based on SJM's work with FoF + * @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss + * + */ + function php4_create_parser($source, $in_enc, $detect) { + if ( !$detect ) { + return array(xml_parser_create($in_enc), $source); + } + + if (!$in_enc) { + if (preg_match('//m', $source, $m)) { + $in_enc = strtoupper($m[1]); + $this->source_encoding = $in_enc; + } + else { + $in_enc = 'UTF-8'; + } + } + + if ($this->known_encoding($in_enc)) { + return array(xml_parser_create($in_enc), $source); + } + + // the dectected encoding is not one of the simple encodings PHP knows + + // attempt to use the iconv extension to + // cast the XML to a known encoding + // @see http://php.net/iconv + + if (function_exists('iconv')) { + $encoded_source = iconv($in_enc,'UTF-8', $source); + if ($encoded_source) { + return array(xml_parser_create('UTF-8'), $encoded_source); + } + } + + // iconv didn't work, try mb_convert_encoding + // @see http://php.net/mbstring + if(function_exists('mb_convert_encoding')) { + $encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc ); + if ($encoded_source) { + return array(xml_parser_create('UTF-8'), $encoded_source); + } + } + + // else + $this->error("Feed is in an unsupported character encoding. ($in_enc) " . + "You may see strange artifacts, and mangled characters.", + E_USER_NOTICE); + + return array(xml_parser_create(), $source); + } + + function known_encoding($enc) { + $enc = strtoupper($enc); + if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) { + return $enc; + } + else { + return false; + } + } + + function error ($errormsg, $lvl=E_USER_WARNING) { + // append PHP's error message if track_errors enabled + if ( isset($php_errormsg) ) { + $errormsg .= " ($php_errormsg)"; + } + if ( MAGPIE_DEBUG ) { + trigger_error( $errormsg, $lvl); + } + else { + error_log( $errormsg, 0); + } + + $notices = E_USER_NOTICE|E_NOTICE; + if ( $lvl&$notices ) { + $this->WARNING = $errormsg; + } else { + $this->ERROR = $errormsg; + } + } + + +} // end class RSS + +function map_attrs($k, $v) { + return "$k=\"$v\""; +} + +// patch to support medieval versions of PHP4.1.x, +// courtesy, Ryan Currie, ryan@digibliss.com + +if (!function_exists('array_change_key_case')) { + define("CASE_UPPER",1); + define("CASE_LOWER",0); + + + function array_change_key_case($array,$case=CASE_LOWER) { + if ($case=CASE_LOWER) $cmd=strtolower; + elseif ($case=CASE_UPPER) $cmd=strtoupper; + foreach($array as $key=>$value) { + $output[$cmd($key)]=$value; + } + return $output; + } + +} + +?> Added: trunk/ofrenda-blog/html/librerias/magpierss/rss_utils.inc =================================================================== --- trunk/ofrenda-blog/html/librerias/magpierss/rss_utils.inc 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/magpierss/rss_utils.inc 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,67 @@ + + * Version: 0.51 + * License: GPL + * + * The lastest version of MagpieRSS can be obtained from: + * http://magpierss.sourceforge.net + * + * For questions, help, comments, discussion, etc., please join the + * Magpie mailing list: + * magpierss-general@lists.sourceforge.net + */ + + +/*======================================================================*\ + Function: parse_w3cdtf + Purpose: parse a W3CDTF date into unix epoch + + NOTE: http://www.w3.org/TR/NOTE-datetime +\*======================================================================*/ + +function parse_w3cdtf ( $date_str ) { + + # regex to match wc3dtf + $pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/"; + + if ( preg_match( $pat, $date_str, $match ) ) { + list( $year, $month, $day, $hours, $minutes, $seconds) = + array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[6]); + + # calc epoch for current date assuming GMT + $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year); + + $offset = 0; + if ( $match[10] == 'Z' ) { + # zulu time, aka GMT + } + else { + list( $tz_mod, $tz_hour, $tz_min ) = + array( $match[8], $match[9], $match[10]); + + # zero out the variables + if ( ! $tz_hour ) { $tz_hour = 0; } + if ( ! $tz_min ) { $tz_min = 0; } + + $offset_secs = (($tz_hour*60)+$tz_min)*60; + + # is timezone ahead of GMT? then subtract offset + # + if ( $tz_mod == '+' ) { + $offset_secs = $offset_secs * -1; + } + + $offset = $offset_secs; + } + $epoch = $epoch + $offset; + return $epoch; + } + else { + return -1; + } +} + +?> Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Date.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Date.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Date.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,183 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Date.php,v 1.9 2005/12/27 15:28:29 lsmith Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Several methods to convert the MDB2 native timestamp format (ISO based) + * to and from data structures that are convenient to worth with in side of php. + * For more complex date arithmetic please take a look at the Date package in PEAR + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Date +{ + // {{{ mdbNow() + + /** + * return the current datetime + * + * @return string current datetime in the MDB2 format + * @access public + */ + function mdbNow() + { + return date('Y-m-d H:i:s'); + } + // }}} + + // {{{ mdbToday() + + /** + * return the current date + * + * @return string current date in the MDB2 format + * @access public + */ + function mdbToday() + { + return date('Y-m-d'); + } + // }}} + + // {{{ mdbTime() + + /** + * return the current time + * + * @return string current time in the MDB2 format + * @access public + */ + function mdbTime() + { + return date('H:i:s'); + } + // }}} + + // {{{ date2Mdbstamp() + + /** + * convert a date into a MDB2 timestamp + * + * @param int hour of the date + * @param int minute of the date + * @param int second of the date + * @param int month of the date + * @param int day of the date + * @param int year of the date + * + * @return string a valid MDB2 timestamp + * @access public + */ + function date2Mdbstamp($hour = null, $minute = null, $second = null, + $month = null, $day = null, $year = null) + { + return MDB2_Date::unix2Mdbstamp(mktime($hour, $minute, $second, $month, $day, $year, -1)); + } + // }}} + + // {{{ unix2Mdbstamp() + + /** + * convert a unix timestamp into a MDB2 timestamp + * + * @param int a valid unix timestamp + * + * @return string a valid MDB2 timestamp + * @access public + */ + function unix2Mdbstamp($unix_timestamp) + { + return date('Y-m-d H:i:s', $unix_timestamp); + } + // }}} + + // {{{ mdbstamp2Unix() + + /** + * convert a MDB2 timestamp into a unix timestamp + * + * @param int a valid MDB2 timestamp + * @return string unix timestamp with the time stored in the MDB2 format + * + * @access public + */ + function mdbstamp2Unix($mdb_timestamp) + { + $arr = MDB2_Date::mdbstamp2Date($mdb_timestamp); + + return mktime($arr['hour'], $arr['minute'], $arr['second'], $arr['month'], $arr['day'], $arr['year'], -1); + } + // }}} + + // {{{ mdbstamp2Date() + + /** + * convert a MDB2 timestamp into an array containing all + * values necessary to pass to php's date() function + * + * @param int a valid MDB2 timestamp + * + * @return array with the time split + * @access public + */ + function mdbstamp2Date($mdb_timestamp) + { + list($arr['year'], $arr['month'], $arr['day'], $arr['hour'], $arr['minute'], $arr['second']) = + sscanf($mdb_timestamp, "%04u-%02u-%02u %02u:%02u:%02u"); + return $arr; + } + // }}} +} + +?> Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/Common.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/Common.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/Common.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,1393 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.52 2006/01/18 15:18:14 quipo Exp $ + +require_once 'MDB2/LOB.php'; + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * MDB2_Driver_Common: Base class that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Datatype_Common extends MDB2_Module_Common +{ + var $valid_types = array( + 'text' => '', + 'boolean' => true, + 'integer' => 0, + 'decimal' => 0.0, + 'float' => 0.0, + 'date' => '0000-00-00 00:00:00', + 'time' => '00:00:00', + 'timestamp' => '0000-00-00', + 'clob' => '', + 'blob' => '', + ); + + /** + * contains all LOB objects created with this MDB2 instance + * @var array + * @access protected + */ + var $lobs = array(); + + // }}} + // {{{ checkResultTypes() + + /** + * Define the list of types to be associated with the columns of a given + * result set. + * + * This function may be called before invoking fetchRow(), fetchOne() + * fetchCole() and fetchAll() so that the necessary data type + * conversions are performed on the data to be retrieved by them. If this + * function is not called, the type of all result set columns is assumed + * to be text, thus leading to not perform any conversions. + * + * @param string $types array variable that lists the + * data types to be expected in the result set columns. If this array + * contains less types than the number of columns that are returned + * in the result set, the remaining columns are assumed to be of the + * type text. Currently, the types clob and blob are not fully + * supported. + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function checkResultTypes($types) + { + $types = is_array($types) ? $types : array($types); + foreach ($types as $key => $type) { + if (!isset($this->valid_types[$type])) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'setResultTypes: ' . $type . ' for '. $key .' is not a supported column type'); + } + } + return $types; + } + + // }}} + // {{{ _baseConvertResult() + + /** + * general type conversion method + * + * @param mixed $value refernce to a value to be converted + * @param int $type constant that specifies which type to convert to + * @return object a MDB2 error on failure + * @access protected + */ + function _baseConvertResult($value, $type) + { + switch ($type) { + case 'text': + return $value; + case 'integer': + return intval($value); + case 'boolean': + return !empty($value); + case 'decimal': + return $value; + case 'float': + return doubleval($value); + case 'date': + return $value; + case 'time': + return $value; + case 'timestamp': + return $value; + case 'clob': + case 'blob': + $this->lobs[] = array( + 'buffer' => null, + 'position' => 0, + 'lob_index' => null, + 'endOfLOB' => false, + 'ressource' => $value, + 'value' => null, + ); + end($this->lobs); + $lob_index = key($this->lobs); + $this->lobs[$lob_index]['lob_index'] = $lob_index; + return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index, 'r+'); + } + + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_INVALID, null, null, + 'attempt to convert result value to an unknown type ' . $type); + } + + // }}} + // {{{ convertResult() + + /** + * convert a value to a RDBMS indepdenant MDB2 type + * + * @param mixed $value value to be converted + * @param int $type constant that specifies which type to convert to + * @return mixed converted value or a MDB2 error on failure + * @access public + */ + function convertResult($value, $type) + { + if (is_null($value)) { + return null; + } + return $this->_baseConvertResult($value, $type); + } + + // }}} + // {{{ convertResultRow() + + /** + * convert a result row + * + * @param resource $result result identifier + * @param array $row array with data + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function convertResultRow($types, $row) + { + if (is_array($types)) { + reset($types); + $current_column = -1; + foreach ($row as $key => $column) { + ++$current_column; + if (!isset($column)) { + continue; + } + if (isset($types[$current_column])) { + $type = $types[$current_column]; + } elseif (isset($types[$key])) { + $type = $types[$key]; + } elseif (current($types)) { + $type = current($types); + next($types); + } else { + continue; + } + $value = $this->convertResult($row[$key], $type); + if (PEAR::isError($value)) { + return $value; + } + $row[$key] = $value; + } + } + return $row; + } + + // }}} + // {{{ getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare + * of the given type + * + * @param string $type type to which the value should be converted to + * @param string $name name the field to be declared. + * @param string $field definition of the field + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function getDeclaration($type, $name, $field) + { + if (!method_exists($this, "_get{$type}Declaration")) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError('type not defined: '.$type); + } + return $this->{"_get{$type}Declaration"}($name, $field); + } + + // }}} + // {{{ getTypeDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an text type + * field to be used in statements like CREATE TABLE. + * + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function getTypeDeclaration($field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + switch ($field['type']) { + case 'text': + return array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT'; + case 'clob': + return 'TEXT'; + case 'blob': + return 'TEXT'; + case 'integer': + return 'INT'; + case 'boolean': + return 'INT'; + case 'date': + return 'CHAR ('.strlen('YYYY-MM-DD').')'; + case 'time': + return 'CHAR ('.strlen('HH:MM:SS').')'; + case 'timestamp': + return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'; + case 'float': + return 'TEXT'; + case 'decimal': + return 'TEXT'; + } + return ''; + } + + // }}} + // {{{ _getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $default = ''; + if (array_key_exists('default', $field)) { + if ($field['default'] === '') { + $field['default'] = (array_key_exists('notnull', $field) && $field['notnull']) + ? $this->valid_types[$field['type']] : null; + } + $default = ' DEFAULT '.$this->quote($field['default'], $field['type']); + } + + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$default.$notnull; + } + + // }}} + // {{{ _getIntegerDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an integer type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * unsigned + * Boolean flag that indicates whether the field should be + * declared as unsigned integer if possible. + * + * default + * Integer value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getIntegerDeclaration($name, $field) + { + if (array_key_exists('unsigned', $field) && $field['unsigned']) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; + } + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getTextDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an text type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTextDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getCLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an character + * large object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function _getCLOBDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$notnull; + } + + // }}} + // {{{ _getBLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an binary large + * object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBLOBDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : ''; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$notnull; + } + + // }}} + // {{{ _getBooleanDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a boolean type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Boolean value to be used as default for this field. + * + * notnullL + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBooleanDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getDateDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a date type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Date value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDateDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getTimestampDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a timestamp + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Timestamp value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTimestampDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getTimeDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a time + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Time value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTimeDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getFloatDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a float type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Float value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getFloatDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getDecimalDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a decimal type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Decimal value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDecimalDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ compareDefinition() + + /** + * Obtain an array of changes that may need to applied + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access public + */ + function compareDefinition($current, $previous) + { + $type = array_key_exists('type', $current) ? $current['type'] : null; + + if (!method_exists($this, "_compare{$type}Definition")) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'type "'.$current['type'].'" is not yet supported'); + } + + if (!array_key_exists('type', $previous) || $previous['type'] != $type) { + return $current; + } + + $change = $this->{"_compare{$type}Definition"}($current, $previous); + + if ($previous['type'] != $type) { + $change['type'] = true; + } + + $previous_notnull = array_key_exists('notnull', $previous) ? $previous['notnull'] : false; + $notnull = array_key_exists('notnull', $current) ? $current['notnull'] : false; + if ($previous_notnull != $notnull) { + $change['notnull'] = true; + } + + $previous_default = array_key_exists('default', $previous) ? $previous['default'] : + ($previous_notnull ? '' : null); + $default = array_key_exists('default', $current) ? $current['default'] : + ($notnull ? '' : null); + if ($previous_default !== $default) { + $change['default'] = true; + } + + return $change; + } + + // }}} + // {{{ _compareIntegerDefinition() + + /** + * Obtain an array of changes that may need to applied to an integer field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareIntegerDefinition($current, $previous) + { + $change = array(); + $previous_unsigned = array_key_exists('unsigned', $previous) ? $previous['unsigned'] : false; + $unsigned = array_key_exists('unsigned', $current) ? $current['unsigned'] : false; + if ($previous_unsigned != $unsigned) { + $change['unsigned'] = true; + } + $previous_autoincrement = array_key_exists('autoincrement', $previous) ? $previous['autoincrement'] : false; + $autoincrement = array_key_exists('autoincrement', $current) ? $current['autoincrement'] : false; + if ($previous_autoincrement != $autoincrement) { + $change['autoincrement'] = true; + } + return $change; + } + + // }}} + // {{{ _compareTextDefinition() + + /** + * Obtain an array of changes that may need to applied to an text field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareTextDefinition($current, $previous) + { + $change = array(); + $previous_length = array_key_exists('length', $previous) ? $previous['length'] : 0; + $length = array_key_exists('length', $current) ? $current['length'] : 0; + if ($previous_length != $length) { + $change['length'] = true; + } + return $change; + } + + // }}} + // {{{ _compareCLOBDefinition() + + /** + * Obtain an array of changes that may need to applied to an CLOB field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareCLOBDefinition($current, $previous) + { + return $this->_compareTextDefinition($current, $previous); + } + + // }}} + // {{{ _compareBLOBDefinition() + + /** + * Obtain an array of changes that may need to applied to an BLOB field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareBLOBDefinition($current, $previous) + { + return $this->_compareTextDefinition($current, $previous); + } + + // }}} + // {{{ _compareDateDefinition() + + /** + * Obtain an array of changes that may need to applied to an date field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareDateDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareTimeDefinition() + + /** + * Obtain an array of changes that may need to applied to an time field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareTimeDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareTimestampDefinition() + + /** + * Obtain an array of changes that may need to applied to an timestamp field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareTimestampDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareBooleanDefinition() + + /** + * Obtain an array of changes that may need to applied to an boolean field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareBooleanDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareFloatDefinition() + + /** + * Obtain an array of changes that may need to applied to an float field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareFloatDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareDecimalDefinition() + + /** + * Obtain an array of changes that may need to applied to an decimal field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access protected + */ + function _compareDecimalDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ quote() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param string $type type to which the value should be converted to + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access public + */ + function quote($value, $type = null, $quote = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_null($value) + || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) + ) { + if (!$quote) { + return null; + } + return 'NULL'; + } + + if (is_null($type)) { + switch (gettype($value)) { + case 'integer': + $type = 'integer'; + break; + case 'double': + // todo + $type = 'decimal'; + $type = 'float'; + break; + case 'boolean': + $type = 'boolean'; + break; + case 'array': + case 'object': + $type = 'text'; + break; + default: + if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $value)) { + $type = 'timestamp'; + } elseif (preg_match('/^\d{2}:\d{2}$/', $value)) { + $type = 'time'; + } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { + $type = 'date'; + } else { + $type = 'text'; + } + break; + } + } + + if (!method_exists($this, "_quote{$type}")) { + return $db->raiseError('type not defined: '.$type); + } + $value = $this->{"_quote{$type}"}($value, $quote); + + return $value; + } + + // }}} + // {{{ _quoteInteger() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteInteger($value, $quote) + { + return (int)$value; + } + + // }}} + // {{{ _quoteText() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that already contains any DBMS specific + * escaped character sequences. + * @access protected + */ + function _quoteText($value, $quote) + { + if (!$quote) { + return $value; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return "'".$db->escape($value)."'"; + } + + // }}} + // {{{ _readFile() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _readFile($value) + { + $close = false; + if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { + $close = true; + if ($match[1] == 'file://') { + $value = $match[2]; + } + $value = @fopen($value, 'r'); + } + + if (is_resource($value)) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $fp = $value; + $value = ''; + while (!@feof($fp)) { + $value.= @fread($fp, $db->options['lob_buffer_length']); + } + if ($close) { + @fclose($fp); + } + } + + return $value; + } + + // }}} + // {{{ _quoteLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteLOB($value, $quote) + { + $value = $this->_readFile($value); + return $this->_quoteText($value, $quote); + } + + // }}} + // {{{ _quoteCLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteCLOB($value, $quote) + { + return $this->_quoteLOB($value, $quote); + } + + // }}} + // {{{ _quoteBLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteBLOB($value, $quote) + { + return $this->_quoteLOB($value, $quote); + } + + // }}} + // {{{ _quoteBoolean() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteBoolean($value, $quote) + { + return ($value ? 1 : 0); + } + + // }}} + // {{{ _quoteDate() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteDate($value, $quote) + { + return $this->_quoteText($value, $quote); + } + + // }}} + // {{{ _quoteTimestamp() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteTimestamp($value, $quote) + { + return $this->_quoteText($value, $quote); + } + + // }}} + // {{{ _quoteTime() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteTime($value, $quote) + { + return $this->_quoteText($value, $quote); + } + + // }}} + // {{{ _quoteFloat() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteFloat($value, $quote) + { + if (!$quote) { + return $value; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->escape($value); + } + + // }}} + // {{{ _quoteDecimal() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteDecimal($value, $quote) + { + if (!$quote) { + return $value; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->escape($value); + } + + // }}} + // {{{ writeLOBToFile() + + /** + * retrieve LOB from the database + * + * @param resource $lob stream handle + * @param string $file name of the file into which the LOb should be fetched + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function writeLOBToFile($lob, $file) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $fp = fopen($file, 'wb'); + while (!feof($lob)) { + $result = fread($lob, $db->options['lob_buffer_length']); + $read = strlen($result); + if (fwrite($fp, $result, $read) != $read) { + fclose($fp); + return $db->raiseError(MDB2_ERROR, null, null, + 'writeLOBToFile: could not write to the output file'); + } + } + fclose($fp); + return MDB2_OK; + } + + // }}} + // {{{ _retrieveLOB() + + /** + * retrieve LOB from the database + * + * @param resource $lob stream handle + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function _retrieveLOB(&$lob) + { + if (is_null($lob['value'])) { + $lob['value'] = $lob['ressource']; + } + return MDB2_OK; + } + + // }}} + // {{{ readLOB() + + /** + * Read data from large object input stream. + * + * @param resource $lob stream handle + * @param string $data reference to a variable that will hold data + * to be read from the large object input stream + * @param integer $length value that indicates the largest ammount ofdata + * to be read from the large object input stream. + * @return mixed the effective number of bytes read from the large object + * input stream on sucess or an MDB2 error object. + * @access public + * @see endOfLOB() + */ + function _readLOB($lob, $length) + { + return substr($lob['value'], $lob['position'], $length); + } + + // }}} + // {{{ _endOfLOB() + + /** + * Determine whether it was reached the end of the large object and + * therefore there is no more data to be read for the its input stream. + * + * @param resource $lob stream handle + * @return mixed true or false on success, a MDB2 error on failure + * @access protected + */ + function _endOfLOB($lob) + { + return $lob['endOfLOB']; + } + + // }}} + // {{{ destroyLOB() + + /** + * Free any resources allocated during the lifetime of the large object + * handler object. + * + * @param resource $lob stream handle + * @access public + */ + function destroyLOB($lob) + { + $lob_data = stream_get_meta_data($lob); + $lob_index = $lob_data['wrapper_data']->lob_index; + fclose($lob); + if (isset($this->lobs[$lob_index])) { + $this->_destroyLOB($lob_index); + unset($this->lobs[$lob_index]); + } + return MDB2_OK; + } + + // }}} + // {{{ _destroyLOB() + + /** + * Free any resources allocated during the lifetime of the large object + * handler object. + * + * @param int $lob_index from the lob array + * @access private + */ + function _destroyLOB($lob_index) + { + return MDB2_OK; + } + + // }}} + // {{{ implodeArray() + + /** + * apply a type to all values of an array and return as a comma seperated string + * useful for generating IN statements + * + * @access public + * + * @param array $array data array + * @param string $type determines type of the field + * + * @return string comma seperated values + */ + function implodeArray($array, $type = false) + { + if (!is_array($array) || empty($array)) { + return 'NULL'; + } + if ($type) { + foreach ($array as $value) { + $return[] = $this->quote($value, $type); + } + } else { + $return = $array; + } + return implode(', ', $return); + } +} + +?> \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Datatype/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/Common.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/Common.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/Common.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,166 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.9 2006/02/05 15:57:32 lsmith Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Base class for the function modules that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Function_Common extends MDB2_Module_Common +{ + // {{{ executeStoredProc() + + /** + * Execute a stored procedure and return any results + * + * @param string $name string that identifies the function to execute + * @param mixed $params array that contains the paramaters to pass the stored proc + * @param mixed $types array that contains the types of the columns in + * the result set + * @param mixed $result_class string which specifies which result class to use + * @param mixed $result_wrap_class string which specifies which class to wrap results in + * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function &executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'query: method not implemented'); + return $error; + } + + // }}} + // {{{ functionTable() + + /** + * return string for internal table used when calling only a function + * + * @return string for internal table used when calling only a function + * @access public + */ + function functionTable() + { + return ''; + } + + // }}} + // {{{ now() + + /** + * Return string to call a variable with the current timestamp inside an SQL statement + * There are three special variables for current date and time: + * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type) + * - CURRENT_DATE (date, DATE type) + * - CURRENT_TIME (time, TIME type) + * + * @return string to call a variable with the current timestamp + * @access public + */ + function now($type = 'timestamp') + { + switch ($type) { + case 'time': + return 'CURRENT_TIME'; + case 'date': + return 'CURRENT_DATE'; + case 'timestamp': + default: + return 'CURRENT_TIMESTAMP'; + } + } + + // }}} + // {{{ substring() + + /** + * return string to call a function to get a substring inside an SQL statement + * + * @return string to call a function to get a substring + * @access public + */ + function substring($value, $position = 1, $length = null) + { + if (!is_null($length)) { + return "SUBSTRING($value FROM $position FOR $length)"; + } + return "SUBSTRING($value FROM $position)"; + } + + // }}} + // {{{ concat() + + /** + * returns string to concatenate two or more string parameters + * + * @param string $value1 + * @param string $value2 + * @param string $values... + * @return string to caoncatenate two strings + * @access public + */ + function concat($value1, $value2) + { + $args = func_get_args(); + return "(".implode(' || ', $args).")"; + } + + // }}} +} +?> \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Function/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/Common.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/Common.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/Common.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,758 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.40 2006/01/12 18:27:30 lsmith Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Base class for the management modules that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Manager_Common extends MDB2_Module_Common +{ + // }}} + // {{{ getFieldDeclarationList() + + /** + * get declaration of a number of field in bulk + * + * @param string $fields a multidimensional associative array. + * The first dimension determines the field name, while the second + * dimension is keyed with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Boolean value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * + * @return mixed string on success, a MDB2 error on failure + * @access public + */ + function getFieldDeclarationList($fields) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_array($fields)) { + foreach ($fields as $field_name => $field) { + $query = $db->getDeclaration($field['type'], $field_name, $field); + if (PEAR::isError($query)) { + return $query; + } + $query_fields[] = $query; + } + return implode(', ', $query_fields); + } + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'getFieldDeclarationList: the definition of the table "'.$table_name.'" does not contain any fields'); + } + + // }}} + // {{{ _fixSequenceName() + + /** + * Removes any formatting in an sequence name using the 'seqname_format' option + * + * @param string $sqn string that containts name of a potential sequence + * @param bool $check if only formatted sequences should be returned + * @return string name of the sequence with possible formatting removed + * @access protected + */ + function _fixSequenceName($sqn, $check = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $seq_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['seqname_format']).'$/i'; + $seq_name = preg_replace($seq_pattern, '\\1', $sqn); + if ($seq_name && !strcasecmp($sqn, $db->getSequenceName($seq_name))) { + return $seq_name; + } + if ($check) { + return false; + } + return $sqn; + } + + // }}} + // {{{ _fixIndexName() + + /** + * Removes any formatting in an index name using the 'idxname_format' option + * + * @param string $idx string that containts name of anl index + * @return string name of the index with possible formatting removed + * @access protected + */ + function _fixIndexName($idx) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $idx_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['idxname_format']).'$/i'; + $idx_name = preg_replace($idx_pattern, '\\1', $idx); + if ($idx_name && !strcasecmp($idx, $db->getIndexName($idx_name))) { + return $idx_name; + } + return $idx; + } + + // }}} + // {{{ createDatabase() + + /** + * create a new database + * + * @param string $name name of the database that should be created + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createDatabase($database) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'createDatabase: database creation is not supported'); + } + + // }}} + // {{{ dropDatabase() + + /** + * drop an existing database + * + * @param string $name name of the database that should be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropDatabase($database) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'dropDatabase: database dropping is not supported'); + } + + // }}} + // {{{ createTable() + + /** + * create a new table + * + * @param string $name Name of the database that should be created + * @param array $fields Associative array that contains the definition of each field of the new table + * The indexes of the array entries are the names of the fields of the table an + * the array entry values are associative arrays like those that are meant to be + * passed with the field definitions to get[Type]Declaration() functions. + * + * Example + * array( + * + * 'id' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * 'notnull' => 1 + * 'default' => 0 + * ), + * 'name' => array( + * 'type' => 'text', + * 'length' => 12 + * ), + * 'password' => array( + * 'type' => 'text', + * 'length' => 12 + * ) + * ); + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createTable($name, $fields) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!$name) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'createTable: no valid table name specified'); + } + if (empty($fields)) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'createTable: no fields specified for table "'.$name.'"'); + } + $query_fields = $this->getFieldDeclarationList($fields); + if (PEAR::isError($query_fields)) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'createTable: unkown error'); + } + + $name = $db->quoteIdentifier($name, true); + $query = "CREATE TABLE $name ($query_fields)"; + return $db->exec($query); + } + + // }}} + // {{{ dropTable() + + /** + * drop an existing table + * + * @param string $name name of the table that should be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropTable($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($name, true); + return $db->exec("DROP TABLE $name"); + } + + // }}} + // {{{ alterTable() + + /** + * alter an existing table + * + * @param string $name name of the table that is intended to be changed. + * @param array $changes associative array that contains the details of each type + * of change that is intended to be performed. The types of + * changes that are currently supported are defined as follows: + * + * name + * + * New name for the table. + * + * add + * + * Associative array with the names of fields to be added as + * indexes of the array. The value of each entry of the array + * should be set to another associative array with the properties + * of the fields to be added. The properties of the fields should + * be the same as defined by the Metabase parser. + * + * + * remove + * + * Associative array with the names of fields to be removed as indexes + * of the array. Currently the values assigned to each entry are ignored. + * An empty array should be used for future compatibility. + * + * rename + * + * Associative array with the names of fields to be renamed as indexes + * of the array. The value of each entry of the array should be set to + * another associative array with the entry named name with the new + * field name and the entry named Declaration that is expected to contain + * the portion of the field declaration already in DBMS specific SQL code + * as it is used in the CREATE TABLE statement. + * + * change + * + * Associative array with the names of the fields to be changed as indexes + * of the array. Keep in mind that if it is intended to change either the + * name of a field and any other properties, the change array entries + * should have the new names of the fields as array indexes. + * + * The value of each entry of the array should be set to another associative + * array with the properties of the fields to that are meant to be changed as + * array entries. These entries should be assigned to the new values of the + * respective properties. The properties of the fields should be the same + * as defined by the Metabase parser. + * + * Example + * array( + * 'name' => 'userlist', + * 'add' => array( + * 'quota' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * ) + * ), + * 'remove' => array( + * 'file_limit' => array(), + * 'time_limit' => array() + * ), + * 'change' => array( + * 'name' => array( + * 'length' => '20', + * 'definition' => array( + * 'type' => 'text', + * 'length' => 20, + * ), + * ) + * ), + * 'rename' => array( + * 'sex' => array( + * 'name' => 'gender', + * 'definition' => array( + * 'type' => 'text', + * 'length' => 1, + * 'default' => 'M', + * ), + * ) + * ) + * ) + * + * @param boolean $check indicates whether the function should just check if the DBMS driver + * can perform the requested table alterations if the value is true or + * actually perform them otherwise. + * @access public + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + */ + function alterTable($name, $changes, $check) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'alterTable: database table alterations are not supported'); + } + + // }}} + // {{{ listDatabases() + + /** + * list all databases + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listDatabases() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listDatabases: list databases is not supported'); + } + + // }}} + // {{{ listUsers() + + /** + * list all users + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listUsers() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listUsers: list user is not supported'); + } + + // }}} + // {{{ listViews() + + /** + * list all views in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listViews() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listViews: list view is not supported'); + } + + // }}} + // {{{ listFunctions() + + /** + * list all functions in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listFunctions() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listFunctions: list function is not supported'); + } + + // }}} + // {{{ listTables() + + /** + * list all tables in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTables() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTables: list tables is not supported'); + } + + // }}} + // {{{ listTableFields() + + /** + * list all fields in a tables in the current database + * + * @param string $table name of table that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTableFields($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTableFields: list table fields is not supported'); + } + + // }}} + // {{{ createIndex() + + /** + * get the stucture of a field into an array + * + * @param string $table name of the table on which the index is to be created + * @param string $name name of the index to be created + * @param array $definition associative array that defines properties of the index to be created. + * Currently, only one property named FIELDS is supported. This property + * is also an associative with the names of the index fields as array + * indexes. Each entry of this array is set to another type of associative + * array that specifies properties of the index that are specific to + * each field. + * + * Currently, only the sorting property is supported. It should be used + * to define the sorting direction of the index. It may be set to either + * ascending or descending. + * + * Not all DBMS support index sorting direction configuration. The DBMS + * drivers of those that do not support it ignore this property. Use the + * function supports() to determine whether the DBMS driver can manage indexes. + * + * Example + * array( + * 'fields' => array( + * 'user_name' => array( + * 'sorting' => 'ascending' + * ), + * 'last_login' => array() + * ) + * ) + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createIndex($table, $name, $definition) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + $query = "CREATE INDEX $name ON $table"; + $fields = array(); + foreach (array_keys($definition['fields']) as $field) { + $fields[] = $db->quoteIdentifier($field, true); + } + $query .= ' ('. implode(', ', $fields) . ')'; + return $db->exec($query); + } + + // }}} + // {{{ dropIndex() + + /** + * drop existing index + * + * @param string $table name of table that should be used in method + * @param string $name name of the index to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropIndex($table, $name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($db->getIndexName($name), true); + return $db->exec("DROP INDEX $name"); + } + + // }}} + // {{{ listTableIndexes() + + /** + * list all indexes in a table + * + * @param string $table name of table that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTableIndexes($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTableIndexes: List Indexes is not supported'); + } + + // }}} + // {{{ createConstraint() + + /** + * create a constraint on a table + * + * @param string $table name of the table on which the constraint is to be created + * @param string $name name of the constraint to be created + * @param array $definition associative array that defines properties of the constraint to be created. + * Currently, only one property named FIELDS is supported. This property + * is also an associative with the names of the constraint fields as array + * constraints. Each entry of this array is set to another type of associative + * array that specifies properties of the constraint that are specific to + * each field. + * + * Example + * array( + * 'fields' => array( + * 'user_name' => array(), + * 'last_login' => array() + * ) + * ) + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createConstraint($table, $name, $definition) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + $query = "ALTER TABLE $table ADD CONSTRAINT $name"; + if (array_key_exists('primary', $definition) && $definition['primary']) { + $query.= ' PRIMARY KEY'; + } elseif (array_key_exists('unique', $definition) && $definition['unique']) { + $query.= ' UNIQUE'; + } + $fields = array(); + foreach (array_keys($definition['fields']) as $field) { + $fields[] = $db->quoteIdentifier($field, true); + } + $query .= ' ('. implode(', ', $fields) . ')'; + return $db->exec($query); + } + + // }}} + // {{{ dropConstraint() + + /** + * drop existing constraint + * + * @param string $table name of table that should be used in method + * @param string $name name of the constraint to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropConstraint($table, $name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + return $db->exec("ALTER TABLE $table DROP CONSTRAINT $name"); + } + + // }}} + // {{{ listTableConstraints() + + /** + * list all sonstraints in a table + * + * @param string $table name of table that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listTableConstraints($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listTableConstraints: List Constraints is not supported'); + } + + // }}} + // {{{ createSequence() + + /** + * create sequence + * + * @param string $seq_name name of the sequence to be created + * @param string $start start value of the sequence; default is 1 + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createSequence($seq_name, $start = 1) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'createSequence: sequence creation not supported'); + } + + // }}} + // {{{ dropSequence() + + /** + * drop existing sequence + * + * @param string $seq_name name of the sequence to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropSequence($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'dropSequence: sequence dropping not supported'); + } + + // }}} + // {{{ listSequences() + + /** + * list all sequences in the current database + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function listSequences() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'listSequences: List sequences is not supported'); + } +} + +?> \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Manager/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/Common.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/Common.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/Common.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,306 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.16 2005/11/24 14:24:04 lsmith Exp $ +// + +/** + * @package MDB2 + * @category Database + */ + +/** + * These are constants for the tableInfo-function + * they are bitwised or'ed. so if there are more constants to be defined + * in the future, adjust MDB2_TABLEINFO_FULL accordingly + */ + +define('MDB2_TABLEINFO_ORDER', 1); +define('MDB2_TABLEINFO_ORDERTABLE', 2); +define('MDB2_TABLEINFO_FULL', 3); + +/** + * Base class for the schema reverse engineering module that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_Common extends MDB2_Module_Common +{ + // }}} + // {{{ getTableFieldDefinition() + + /** + * get the stucture of a field into an array + * + * @param string $table name of table that should be used in method + * @param string $fields name of field that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableFieldDefinition($table, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'getTableFieldDefinition: table field definition is not supported'); + } + + // }}} + // {{{ getTableIndexDefinition() + + /** + * get the stucture of an index into an array + * + * @param string $table name of table that should be used in method + * @param string $index name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableIndexDefinition($table, $index) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'getTableIndexDefinition: getting index definition is not supported'); + } + + // }}} + // {{{ getTableConstraintDefinition() + + /** + * get the stucture of an constraints into an array + * + * @param string $table name of table that should be used in method + * @param string $index name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getTableConstraintDefinition($table, $index) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'getTableConstraintDefinition: getting index definition is not supported'); + } + + // }}} + // {{{ getSequenceDefinition() + + /** + * get the stucture of a sequence into an array + * + * @param string $sequence name of sequence that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function getSequenceDefinition($sequence) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $start = $db->currId($sequence); + if (PEAR::isError($start)) { + return $start; + } + if ($db->supports('current_id')) { + $start++; + } else { + $db->warnings[] = 'database does not support getting current + sequence value, the sequence value was incremented'; + } + $definition = array(); + if ($start != 1) { + $definition = array('start' => $start); + } + return $definition; + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * The format of the resulting array depends on which $mode + * you select. The sample output below is based on this query: + *

+     *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
+     *    FROM tblFoo
+     *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
+     * 
+ * + *
    + *
  • + * + * null (default) + *
    +     *   [0] => Array (
    +     *       [table] => tblFoo
    +     *       [name] => fldId
    +     *       [type] => int
    +     *       [len] => 11
    +     *       [flags] => primary_key not_null
    +     *   )
    +     *   [1] => Array (
    +     *       [table] => tblFoo
    +     *       [name] => fldPhone
    +     *       [type] => string
    +     *       [len] => 20
    +     *       [flags] =>
    +     *   )
    +     *   [2] => Array (
    +     *       [table] => tblBar
    +     *       [name] => fldId
    +     *       [type] => int
    +     *       [len] => 11
    +     *       [flags] => primary_key not_null
    +     *   )
    +     *   
    + * + *
  • + * + * MDB2_TABLEINFO_ORDER + * + *

    In addition to the information found in the default output, + * a notation of the number of columns is provided by the + * num_fields element while the order + * element provides an array with the column names as the keys and + * their location index number (corresponding to the keys in the + * the default output) as the values.

    + * + *

    If a result set has identical field names, the last one is + * used.

    + * + *
    +     *   [num_fields] => 3
    +     *   [order] => Array (
    +     *       [fldId] => 2
    +     *       [fldTrans] => 1
    +     *   )
    +     *   
    + * + *
  • + * + * MDB2_TABLEINFO_ORDERTABLE + * + *

    Similar to MDB2_TABLEINFO_ORDER but adds more + * dimensions to the array in which the table names are keys and + * the field names are sub-keys. This is helpful for queries that + * join tables which have identical field names.

    + * + *
    +     *   [num_fields] => 3
    +     *   [ordertable] => Array (
    +     *       [tblFoo] => Array (
    +     *           [fldId] => 0
    +     *           [fldPhone] => 1
    +     *       )
    +     *       [tblBar] => Array (
    +     *           [fldId] => 2
    +     *       )
    +     *   )
    +     *   
    + * + *
  • + *
+ * + * The flags element contains a space separated list + * of extra information about the field. This data is inconsistent + * between DBMS's due to the way each DBMS works. + * + primary_key + * + unique_key + * + multiple_key + * + not_null + * + * Most DBMS's only provide the table and flags + * elements if $result is a table name. The following DBMS's + * provide full information from queries: + * + fbsql + * + mysql + * + * If the 'portability' option has MDB2_PORTABILITY_FIX_CASE + * turned on, the names of tables and fields will be lower or upper cased. + * + * @param object|string $result MDB2_result object from a query or a + * string containing the name of a table. + * While this also accepts a query result + * resource identifier, this behavior is + * deprecated. + * @param int $mode either unused or one of the tableInfo modes: + * MDB2_TABLEINFO_ORDERTABLE, + * MDB2_TABLEINFO_ORDER or + * MDB2_TABLEINFO_FULL (which does both). + * These are bitwise, so the first two can be + * combined using |. + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::setOption() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'tableInfo: method not implemented'); + } +} +?> \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/Reverse/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Driver/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Extended.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Extended.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Extended.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,597 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Extended.php,v 1.36 2006/02/09 12:45:30 lsmith Exp $ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Used by autoPrepare() + */ +define('MDB2_AUTOQUERY_INSERT', 1); +define('MDB2_AUTOQUERY_UPDATE', 2); + +/** + * MDB2_Extended: class which adds several high level methods to MDB2 + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Extended extends MDB2_Module_Common +{ + // {{{ autoPrepare() + + /** + * Make automaticaly an insert or update query and call prepare() with it + * + * @param string table + * @param array the fields names + * @param int type of query to make (MDB2_AUTOQUERY_INSERT or MDB2_AUTOQUERY_UPDATE) + * @param string (in case of update queries, this string will be put after the sql WHERE statement) + * @param array that contains the types of the placeholders + * + * @return resource handle for the query + * @see buildManipSQL + * @access public + */ + function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT, + $where = false, $types = null) + { + $query = $this->buildManipSQL($table, $table_fields, $mode, $where); + if (PEAR::isError($query)) { + return $query; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->prepare($query, $types, false); + } + // }}} + + // {{{ autoExecute() + + /** + * Make automaticaly an insert or update query and call prepare() and execute() with it + * + * @param string name of the table + * @param array assoc ($key=>$value) where $key is a field name and $value its value + * @param int type of query to make (MDB2_AUTOQUERY_INSERT or MDB2_AUTOQUERY_UPDATE) + * @param string (in case of update queries, this string will be put after the sql WHERE statement) + * @param array that contains the types of the placeholders + * @param string which specifies which result class to use + * + * @return bool|MDB2_Error true on success, a MDB2 error on failure + * @see buildManipSQL + * @see autoPrepare + * @access public + */ + function &autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT, + $where = false, $types = null, $result_class = true) + { + $stmt = $this->autoPrepare($table, array_keys($fields_values), $mode, $where, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + $params = array_values($fields_values); + $result =& $stmt->execute($params, $result_class); + $stmt->free(); + return $result; + } + // }}} + + // {{{ buildManipSQL() + + /** + * Make automaticaly an sql query for prepare() + * + * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), MDB2_AUTOQUERY_INSERT) + * will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) + * NB : - This belongs more to a SQL Builder class, but this is a simple facility + * - Be carefull ! If you don't give a $where param with an UPDATE query, all + * the records of the table will be updated ! + * + * @param string name of the table + * @param ordered array containing the fields names + * @param int type of query to make (MDB2_AUTOQUERY_INSERT or MDB2_AUTOQUERY_UPDATE) + * @param string (in case of update queries, this string will be put after the sql WHERE statement) + * + * @return string sql query for prepare() + * @access public + */ + function buildManipSQL($table, $table_fields, $mode, $where = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (count($table_fields) == 0) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA); + } + switch ($mode) { + case MDB2_AUTOQUERY_INSERT: + $cols = implode(', ', $table_fields); + $values = '?'.str_repeat(', ?', count($table_fields)-1); + return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')'; + break; + case MDB2_AUTOQUERY_UPDATE: + $set = implode(' = ?, ', $table_fields).' = ?'; + $sql = 'UPDATE '.$table.' SET '.$set; + if ($where !== false) { + $sql.= ' WHERE '.$where; + } + return $sql; + break; + } + return $db->raiseError(MDB2_ERROR_SYNTAX); + } + // }}} + + // {{{ limitQuery() + + /** + * Generates a limited query + * + * @param string query + * @param array that contains the types of the columns in the result set + * @param integer the row to start to fetching + * @param integer the numbers of rows to fetch + * @param string which specifies which result class to use + * + * @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure + * @access public + */ + function &limitQuery($query, $types, $count, $from = 0, $result_class = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->setLimit($count, $from); + if (PEAR::isError($result)) { + return $result; + } + $result =& $db->query($query, $types, $result_class); + return $result; + } + // }}} + + // {{{ getOne() + + /** + * Fetch the first column of the first row of data returned from a query. + * Takes care of doing the query and freeing the results when finished. + * + * @param string the SQL query + * @param string that contains the type of the column in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int|string which column to return + * + * @return scalar|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getOne($query, $type = null, $params = array(), + $param_types = null, $colnum = 0) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + settype($type, 'array'); + if (count($params) == 0) { + return $db->queryOne($query, $type, $colnum); + } + + $stmt = $db->prepare($query, $param_types, $type); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $one = $result->fetchOne($colnum); + $stmt->free(); + $result->free(); + return $one; + } + // }}} + + // {{{ getRow() + + /** + * Fetch the first row of data returned from a query. Takes care + * of doing the query and freeing the results when finished. + * + * @param string the SQL query + * @param array that contains the types of the columns in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int the fetch mode to use + * + * @return array|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getRow($query, $types = null, $params = array(), + $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (count($params) == 0) { + return $db->queryRow($query, $types, $fetchmode); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $row = $result->fetchRow($fetchmode); + $stmt->free(); + $result->free(); + return $row; + } + // }}} + + // {{{ getCol() + + /** + * Fetch a single column from a result set and return it as an + * indexed array. + * + * @param string the SQL query + * @param string that contains the type of the column in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int|string which column to return + * + * @return array|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getCol($query, $type = null, $params = array(), + $param_types = null, $colnum = 0) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + settype($type, 'array'); + if (count($params) == 0) { + return $db->queryCol($query, $type, $colnum); + } + + $stmt = $db->prepare($query, $param_types, $type); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $col = $result->fetchCol($colnum); + $stmt->free(); + $result->free(); + return $col; + } + // }}} + + // {{{ getAll() + + /** + * Fetch all the rows returned from a query. + * + * @param string the SQL query + * @param array that contains the types of the columns in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int the fetch mode to use + * @param bool if set to true, the $all will have the first + * column as its first dimension + * @param bool $force_array used only when the query returns exactly + * two columns. If true, the values of the returned array will be + * one-element arrays instead of scalars. + * @param bool $group if true, the values of the returned array is + * wrapped in another array. If the same key value (in the first + * column) repeats itself, the values will be appended to this array + * instead of overwriting the existing values. + * + * @return array|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getAll($query, $types = null, $params = array(), + $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, + $rekey = false, $force_array = false, $group = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (count($params) == 0) { + return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); + $stmt->free(); + $result->free(); + return $all; + } + // }}} + + // {{{ getAssoc() + + /** + * Fetch the entire result set of a query and return it as an + * associative array using the first column as the key. + * + * If the result set contains more than two columns, the value + * will be an array of the values from column 2-n. If the result + * set contains only two columns, the returned value will be a + * scalar with the value of the second column (unless forced to an + * array with the $force_array parameter). A MDB2 error code is + * returned on errors. If the result set contains fewer than two + * columns, a MDB2_ERROR_TRUNCATED error is returned. + * + * For example, if the table 'mytable' contains: + * + * ID TEXT DATE + * -------------------------------- + * 1 'one' 944679408 + * 2 'two' 944679408 + * 3 'three' 944679408 + * + * Then the call getAssoc('SELECT id,text FROM mytable') returns: + * array( + * '1' => 'one', + * '2' => 'two', + * '3' => 'three', + * ) + * + * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: + * array( + * '1' => array('one', '944679408'), + * '2' => array('two', '944679408'), + * '3' => array('three', '944679408') + * ) + * + * If the more than one row occurs with the same value in the + * first column, the last row overwrites all previous ones by + * default. Use the $group parameter if you don't want to + * overwrite like this. Example: + * + * getAssoc('SELECT category,id,name FROM mytable', null, null + * MDB2_FETCHMODE_ASSOC, false, true) returns: + * array( + * '1' => array(array('id' => '4', 'name' => 'number four'), + * array('id' => '6', 'name' => 'number six') + * ), + * '9' => array(array('id' => '4', 'name' => 'number four'), + * array('id' => '6', 'name' => 'number six') + * ) + * ) + * + * Keep in mind that database functions in PHP usually return string + * values for results regardless of the database's internal type. + * + * @param string the SQL query + * @param array that contains the types of the columns in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param bool $force_array used only when the query returns + * exactly two columns. If TRUE, the values of the returned array + * will be one-element arrays instead of scalars. + * @param bool $group if TRUE, the values of the returned array + * is wrapped in another array. If the same key value (in the first + * column) repeats itself, the values will be appended to this array + * instead of overwriting the existing values. + * + * @return array|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getAssoc($query, $types = null, $params = array(), $param_types = null, + $fetchmode = MDB2_FETCHMODE_DEFAULT, $force_array = false, $group = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (count($params) == 0) { + return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $stmt->bindParamArray($params); + $result = $stmt->execute(); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, true, $force_array, $group); + $stmt->free(); + $result->free(); + return $all; + } + // }}} + + // {{{ executeMultiple() + + /** + * This function does several execute() calls on the same statement handle. + * $params must be an array indexed numerically from 0, one execute call is + * done for every 'row' in the array. + * + * If an error occurs during execute(), executeMultiple() does not execute + * the unfinished rows, but rather returns that error. + * + * @param resource query handle from prepare() + * @param array numeric array containing the data to insert into the query + * + * @return bool|MDB2_Error true on success, a MDB2 error on failure + * @access public + * @see prepare(), execute() + */ + function executeMultiple(&$stmt, $params = null) + { + for ($i = 0, $j = count($params); $i < $j; $i++) { + $stmt->bindParamArray($params[$i]); + $result = $stmt->execute(); + if (PEAR::isError($result)) { + return $result; + } + } + return MDB2_OK; + } + // }}} + + // {{{ getBeforeID() + + /** + * returns the next free id of a sequence if the RDBMS + * does not support auto increment + * + * @param string name of the table into which a new row was inserted + * @param string name of the field into which a new row was inserted + * @param bool when true the sequence is automatic created, if it not exists + * + * @return int|MDB2_Error id on success, a MDB2 error on failure + * @access public + */ + function getBeforeID($table, $field = null, $ondemand = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->supports('auto_increment') !== true) { + $seq = $table.(empty($field) ? '' : '_'.$field); + $id = $db->nextID($seq, $ondemand); + if (PEAR::isError($id)) { + return $id; + } + return $db->quote($id, 'integer'); + } + return 'NULL'; + } + // }}} + + // {{{ getAfterID() + + /** + * returns the autoincrement ID if supported or $id + * + * @param mixed value as returned by getBeforeId() + * @param string name of the table into which a new row was inserted + * @param string name of the field into which a new row was inserted + * + * @return int|MDB2_Error id on success, a MDB2 error on failure + * @access public + */ + function getAfterID($id, $table, $field = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->supports('auto_increment') !== true) { + return $id; + } + return $db->lastInsertID($table, $field); + } + // }}} +} +?> Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Iterator.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Iterator.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/Iterator.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,250 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Iterator.php,v 1.19 2006/02/08 15:42:04 lsmith Exp $ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Iterator implements Iterator +{ + protected $fetchmode; + protected $result; + protected $row; + + // {{{ constructor + + /** + * Constructor + */ + public function __construct($result, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $this->result = $result; + $this->fetchmode = $fetchmode; + } + // }}} + + // {{{ seek() + + /** + * seek forward to a specific row in a result set + * + * @param int number of the row where the data can be found + * + * @return void + * @access public + */ + public function seek($rownum) + { + $this->row = null; + if ($this->result) { + $this->result->seek($rownum); + } + } + // }}} + + // {{{ next() + + /** + * Fetch next row of data + * + * @return void + * @access public + */ + public function next() + { + $this->row = null; + } + // }}} + + // {{{ current() + + /** + * return a row of data + * + * @return void + * @access public + */ + public function current() + { + if (is_null($this->row)) { + $row = $this->result->fetchRow($this->fetchmode); + if (PEAR::isError($row)) { + $row = false; + } + $this->row = $row; + } + return $this->row; + } + // }}} + + // {{{ valid() + + /** + * check if the end of the result set has been reached + * + * @return bool true/false, false is also returned on failure + * @access public + */ + public function valid() + { + return (bool)$this->current(); + } + // }}} + + // {{{ free() + + /** + * Free the internal resources associated with result. + * + * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid + * @access public + */ + public function free() + { + if ($this->result) { + return $this->result->free(); + } + $this->result = false; + $this->row = null; + return false; + } + // }}} + + // {{{ key() + + /** + * returns the row number + * + * @return int|bool|MDB2_Error true on success, false|MDB2_Error if result is invalid + * @access public + */ + public function key() + { + if ($this->result) { + return $this->result->rowCount(); + } + return false; + } + // }}} + + // {{{ rewind() + + /** + * seek to the first row in a result set + * + * @return void + * @access public + */ + public function rewind() + { + } + // }}} + + // {{{ destructor + + /** + * Destructor + */ + public function __destruct() + { + $this->free(); + } + // }}} +} + +class MDB2_BufferedIterator extends MDB2_Iterator implements SeekableIterator +{ + // {{{ valid() + + /** + * check if the end of the result set has been reached + * + * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid + * @access public + */ + public function valid() + { + if ($this->result) { + return $this->result->valid(); + } + return false; + } + // }}} + + // {{{count() + + /** + * returns the number of rows in a result object + * + * @return int|MDB2_Error number of rows, false|MDB2_Error if result is invalid + * @access public + */ + public function count() + { + if ($this->result) { + return $this->result->numRows(); + } + return false; + } + // }}} + + // {{{ rewind() + + /** + * seek to the first row in a result set + * + * @return void + * @access public + */ + public function rewind() + { + $this->seek(0); + } + // }}} +} + +?> \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/LOB.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2/LOB.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2/LOB.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,250 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: LOB.php,v 1.24 2006/02/03 19:13:04 lsmith Exp $ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +require_once 'MDB2.php'; + +/** + * MDB2_LOB: user land stream wrapper implementation for LOB support + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_LOB +{ + /** + * contains the key to the global MDB2 instance array of the associated + * MDB2 instance + * + * @var integer + * @access protected + */ + var $db_index; + + /** + * contains the key to the global MDB2_LOB instance array of the associated + * MDB2_LOB instance + * + * @var integer + * @access protected + */ + var $lob_index; + + /** + * LOB data + * + * @var string + * @access protected + */ + var $lob; + + // {{{ stream_open() + + /** + * open stream + * + * @param string specifies the URL that was passed to fopen() + * @param string the mode used to open the file + * @param int holds additional flags set by the streams API + * @param string not used + * + * @return bool + * @access public + */ + function stream_open($path, $mode, $options, &$opened_path) + { + if (!preg_match('/^rb?\+?$/', $mode)) { + return false; + } + $url = parse_url($path); + if (!array_key_exists('host', $url) && !array_key_exists('user', $url)) { + return false; + } + $this->db_index = $url['host']; + if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + return false; + } + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $this->lob_index = $url['user']; + if (!isset($db->datatype->lobs[$this->lob_index])) { + return false; + } + $this->lob =& $db->datatype->lobs[$this->lob_index]; + $db->datatype->_retrieveLOB($this->lob); + return true; + } + // }}} + + // {{{ stream_read() + + /** + * read stream + * + * @param int number of bytes to read + * + * @return string + * @access public + */ + function stream_read($count) + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + + $data = $db->datatype->_readLOB($this->lob, $count); + $length = strlen($data); + if ($length == 0) { + $this->lob['endOfLOB'] = true; + } + $this->lob['position'] += $length; + return $data; + } + } + // }}} + + // {{{ stream_write() + + /** + * write stream, note implemented + * + * @param string data + * + * @return int + * @access public + */ + function stream_write($data) + { + return 0; + } + // }}} + + // {{{ stream_tell() + + /** + * return the current position + * + * @return int current position + * @access public + */ + function stream_tell() + { + return $this->lob['position']; + } + // }}} + + // {{{ stream_eof() + + /** + * check if stream reaches EOF + * + * @return bool + * @access public + */ + function stream_eof() + { + if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + return true; + } + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $result = $db->datatype->_endOfLOB($this->lob); + if (version_compare(phpversion(), "5.0", ">=") + && version_compare(phpversion(), "5.1", "<") + ) { + return !$result; + } + return $result; + } + // }}} + + // {{{ stream_seek() + + /** + * seek stream, not implemented + * + * @param int offset + * @param int whence + * + * @return bool + * @access public + */ + function stream_seek($offset, $whence) + { + return false; + } + // }}} + + // {{{ stream_close() + + /** + * close stream + * + * @access public + */ + function stream_close() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + if (isset($db->datatype->lobs[$this->lob_index])) { + $db->datatype->_destroyLOB($this->lob_index); + unset($db->datatype->lobs[$this->lob_index]); + } + } + } + // }}} +} + +// register streams wrapper +if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) { + MDB2::raiseError(); + return false; +} + +?> Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/mdb2/MDB2.php =================================================================== --- trunk/ofrenda-blog/html/librerias/mdb2/MDB2.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/mdb2/MDB2.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,3420 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2.php,v 1.163 2006/02/09 12:45:30 lsmith Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +require_once 'PEAR.php'; + +/** + * The method mapErrorCode in each MDB2_dbtype implementation maps + * native error codes to one of these. + * + * If you add an error code here, make sure you also add a textual + * version of it in MDB2::errorMessage(). + */ + +define('MDB2_OK', true); +define('MDB2_ERROR', -1); +define('MDB2_ERROR_SYNTAX', -2); +define('MDB2_ERROR_CONSTRAINT', -3); +define('MDB2_ERROR_NOT_FOUND', -4); +define('MDB2_ERROR_ALREADY_EXISTS', -5); +define('MDB2_ERROR_UNSUPPORTED', -6); +define('MDB2_ERROR_MISMATCH', -7); +define('MDB2_ERROR_INVALID', -8); +define('MDB2_ERROR_NOT_CAPABLE', -9); +define('MDB2_ERROR_TRUNCATED', -10); +define('MDB2_ERROR_INVALID_NUMBER', -11); +define('MDB2_ERROR_INVALID_DATE', -12); +define('MDB2_ERROR_DIVZERO', -13); +define('MDB2_ERROR_NODBSELECTED', -14); +define('MDB2_ERROR_CANNOT_CREATE', -15); +define('MDB2_ERROR_CANNOT_DELETE', -16); +define('MDB2_ERROR_CANNOT_DROP', -17); +define('MDB2_ERROR_NOSUCHTABLE', -18); +define('MDB2_ERROR_NOSUCHFIELD', -19); +define('MDB2_ERROR_NEED_MORE_DATA', -20); +define('MDB2_ERROR_NOT_LOCKED', -21); +define('MDB2_ERROR_VALUE_COUNT_ON_ROW', -22); +define('MDB2_ERROR_INVALID_DSN', -23); +define('MDB2_ERROR_CONNECT_FAILED', -24); +define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25); +define('MDB2_ERROR_NOSUCHDB', -26); +define('MDB2_ERROR_ACCESS_VIOLATION', -27); +define('MDB2_ERROR_CANNOT_REPLACE', -28); +define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29); +define('MDB2_ERROR_DEADLOCK', -30); +define('MDB2_ERROR_CANNOT_ALTER', -31); +define('MDB2_ERROR_MANAGER', -32); +define('MDB2_ERROR_MANAGER_PARSE', -33); +define('MDB2_ERROR_LOADMODULE', -34); +define('MDB2_ERROR_INSUFFICIENT_DATA', -35); + +/** + * These are just helper constants to more verbosely express parameters to prepare() + */ + +define('MDB2_PREPARE_MANIP', false); +define('MDB2_PREPARE_RESULT', null); + +/** + * This is a special constant that tells MDB2 the user hasn't specified + * any particular get mode, so the default should be used. + */ + +define('MDB2_FETCHMODE_DEFAULT', 0); + +/** + * Column data indexed by numbers, ordered from 0 and up + */ + +define('MDB2_FETCHMODE_ORDERED', 1); + +/** + * Column data indexed by column names + */ + +define('MDB2_FETCHMODE_ASSOC', 2); + +/** + * Column data as object properties + */ + +define('MDB2_FETCHMODE_OBJECT', 3); + +/** + * For multi-dimensional results: normally the first level of arrays + * is the row number, and the second level indexed by column number or name. + * MDB2_FETCHMODE_FLIPPED switches this order, so the first level of arrays + * is the column name, and the second level the row number. + */ + +define('MDB2_FETCHMODE_FLIPPED', 4); + +// }}} +// {{{ portability modes + +/** + * Portability: turn off all portability features. + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_NONE', 0); + +/** + * Portability: convert names of tables and fields to case defined in the + * "field_case" option when using the query*(), fetch*() and tableInfo() methods. + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_FIX_CASE', 1); + +/** + * Portability: right trim the data output by query*() and fetch*(). + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_RTRIM', 2); + +/** + * Portability: force reporting the number of rows deleted. + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_DELETE_COUNT', 4); + +/** + * Portability: not needed in MDB2 (just left here for compatibility to DB) + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_NUMROWS', 8); + +/** + * Portability: makes certain error messages in certain drivers compatible + * with those from other DBMS's. + * + * + mysql, mysqli: change unique/primary key constraints + * MDB2_ERROR_ALREADY_EXISTS -> MDB2_ERROR_CONSTRAINT + * + * + odbc(access): MS's ODBC driver reports 'no such field' as code + * 07001, which means 'too few parameters.' When this option is on + * that code gets mapped to MDB2_ERROR_NOSUCHFIELD. + * + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_ERRORS', 16); + +/** + * Portability: convert empty values to null strings in data output by + * query*() and fetch*(). + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_EMPTY_TO_NULL', 32); + +/** + * Portability: removes database/table qualifiers from associative indexes + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES', 64); + +/** + * Portability: turn on all portability features. + * @see MDB2_Driver_Common::setOption() + */ + +define('MDB2_PORTABILITY_ALL', 127); + +/** + * These are global variables that are used to track the various class instances + */ + +$GLOBALS['_MDB2_databases'] = array(); +$GLOBALS['_MDB2_dsninfo_default'] = array( + 'phptype' => false, + 'dbsyntax' => false, + 'username' => false, + 'password' => false, + 'protocol' => false, + 'hostspec' => false, + 'port' => false, + 'socket' => false, + 'database' => false, + 'mode' => false, +); + +/** + * The main 'MDB2' class is simply a container class with some static + * methods for creating DB objects as well as some utility functions + * common to all parts of DB. + * + * The object model of MDB2 is as follows (indentation means inheritance): + * + * MDB2 The main MDB2 class. This is simply a utility class + * with some 'static' methods for creating MDB2 objects as + * well as common utility functions for other MDB2 classes. + * + * MDB2_Driver_Common The base for each MDB2 implementation. Provides default + * | implementations (in OO lingo virtual methods) for + * | the actual DB implementations as well as a bunch of + * | query utility functions. + * | + * +-MDB2_Driver_mysql The MDB2 implementation for MySQL. Inherits MDB2_Driver_Common. + * When calling MDB2::factory or MDB2::connect for MySQL + * connections, the object returned is an instance of this + * class. + * +-MDB2_Driver_pgsql The MDB2 implementation for PostGreSQL. Inherits MDB2_Driver_Common. + * When calling MDB2::factory or MDB2::connect for PostGreSQL + * connections, the object returned is an instance of this + * class. + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2 +{ + // }}} + // {{{ setOptions() + + /** + * set option array in an exiting database object + * + * @param MDB2_Driver_Common $db MDB2 object + * @param array $options An associative array of option names and their values. + * @access public + */ + function setOptions(&$db, $options) + { + if (is_array($options)) { + foreach ($options as $option => $value) { + $test = $db->setOption($option, $value); + if (PEAR::isError($test)) { + return $test; + } + } + } + return MDB2_OK; + } + + // }}} + // {{{ factory() + + /** + * Create a new MDB2 object for the specified database type + * + * IMPORTANT: In order for MDB2 to work properly it is necessary that + * you make sure that you work with a reference of the original + * object instead of a copy (this is a PHP4 quirk). + * + * For example: + * $db =& MDB2::factory($dsn); + * ^^ + * And not: + * $db = MDB2::factory($dsn); + * + * @param mixed $dsn 'data source name', see the MDB2::parseDSN + * method for a description of the dsn format. + * Can also be specified as an array of the + * format returned by MDB2::parseDSN. + * @param array $options An associative array of option names and + * their values. + * @return mixed a newly created MDB2 object, or false on error + * @access public + */ + function &factory($dsn, $options = false) + { + $dsninfo = MDB2::parseDSN($dsn); + if (!array_key_exists('phptype', $dsninfo)) { + $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, + null, null, 'no RDBMS driver specified'); + return $err; + } + $class_name = 'MDB2_Driver_'.$dsninfo['phptype']; + + if (!class_exists($class_name)) { + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + if (is_array($options) && array_key_exists('debug', $options) && $options['debug']) { + $include = include_once($file_name); + } else { + $include = @include_once($file_name); + } + if (!$include) { + if (!MDB2::fileExists($file_name)) { + $msg = "unable to find package '$class_name' file '$file_name'"; + } else { + $msg = "unable to load driver class '$class_name' from file '$file_name'"; + } + $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, $msg); + return $err; + } + } + + $db =& new $class_name(); + $db->setDSN($dsninfo); + $err = MDB2::setOptions($db, $options); + if (PEAR::isError($err)) { + return $err; + } + + return $db; + } + + // }}} + // {{{ connect() + + /** + * Create a new MDB2 connection object and connect to the specified + * database + * + * IMPORTANT: In order for MDB2 to work properly it is necessary that + * you make sure that you work with a reference of the original + * object instead of a copy (this is a PHP4 quirk). + * + * For example: + * $db =& MDB2::connect($dsn); + * ^^ + * And not: + * $db = MDB2::connect($dsn); + * ^^ + * + * @param mixed $dsn 'data source name', see the MDB2::parseDSN + * method for a description of the dsn format. + * Can also be specified as an array of the + * format returned by MDB2::parseDSN. + * @param array $options An associative array of option names and + * their values. + * @return mixed a newly created MDB2 connection object, or a MDB2 + * error object on error + * @access public + * @see MDB2::parseDSN + */ + function &connect($dsn, $options = false) + { + $db =& MDB2::factory($dsn, $options); + if (PEAR::isError($db)) { + return $db; + } + + $err = $db->connect(); + if (PEAR::isError($err)) { + $dsn = $db->getDSN('string', 'xxx'); + $db->disconnect(); + $err->addUserInfo($dsn); + return $err; + } + + return $db; + } + + // }}} + // {{{ singleton() + + /** + * Returns a MDB2 connection with the requested DSN. + * A newnew MDB2 connection object is only created if no object with the + * reuested DSN exists yet. + * + * IMPORTANT: In order for MDB2 to work properly it is necessary that + * you make sure that you work with a reference of the original + * object instead of a copy (this is a PHP4 quirk). + * + * For example: + * $db =& MDB2::singleton($dsn); + * ^^ + * And not: + * $db = MDB2::singleton($dsn); + * ^^ + * + * @param mixed $dsn 'data source name', see the MDB2::parseDSN + * method for a description of the dsn format. + * Can also be specified as an array of the + * format returned by MDB2::parseDSN. + * @param array $options An associative array of option names and + * their values. + * @return mixed a newly created MDB2 connection object, or a MDB2 + * error object on error + * @access public + * @see MDB2::parseDSN + */ + function &singleton($dsn = null, $options = false) + { + if ($dsn) { + $dsninfo = MDB2::parseDSN($dsn); + $dsninfo = array_merge($GLOBALS['_MDB2_dsninfo_default'], $dsninfo); + $keys = array_keys($GLOBALS['_MDB2_databases']); + for ($i=0, $j=count($keys); $i<$j; ++$i) { + $tmp_dsn = $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array'); + if (count(array_diff($tmp_dsn, $dsninfo)) == 0) { + MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]], $options); + return $GLOBALS['_MDB2_databases'][$keys[$i]]; + } + } + } elseif (is_array($GLOBALS['_MDB2_databases']) && reset($GLOBALS['_MDB2_databases'])) { + $db =& $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])]; + return $db; + } + $db =& MDB2::factory($dsn, $options); + return $db; + } + + // }}} + // {{{ loadFile() + + /** + * load a file (like 'Date') + * + * @param string $file name of the file in the MDB2 directory (without '.php') + * @return string name of the file that was included + * @access public + */ + function loadFile($file) + { + $file_name = 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php'; + if (!MDB2::fileExists($file_name)) { + return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'unable to find: '.$file_name); + } + if (!include_once($file_name)) { + return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'unable to load driver class: '.$file_name); + } + return $file_name; + } + + // }}} + // {{{ apiVersion() + + /** + * Return the MDB2 API version + * + * @return string the MDB2 API version number + * @access public + */ + function apiVersion() + { + return '@package_version@'; + } + + // }}} + // {{{ raiseError() + + /** + * This method is used to communicate an error and invoke error + * callbacks etc. Basically a wrapper for PEAR::raiseError + * without the message string. + * + * @param mixed integer error code + * + * @param int error mode, see PEAR_Error docs + * + * @param mixed If error mode is PEAR_ERROR_TRIGGER, this is the + * error level (E_USER_NOTICE etc). If error mode is + * PEAR_ERROR_CALLBACK, this is the callback function, + * either as a function name, or as an array of an + * object and method name. For other error modes this + * parameter is ignored. + * + * @param string Extra debug information. Defaults to the last + * query and native error code. + * + * @return object a PEAR error object + * + * @see PEAR_Error + */ + function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) + { + $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true); + return $err; + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a MDB2 error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $db->getMessage() == $code or + * $code is an integer and $db->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (is_a($data, 'MDB2_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() === $code; + } else { + $code = (array)$code; + return in_array($data->getCode(), $code); + } + } + return false; + } + + // }}} + // {{{ isConnection() + /** + * Tell whether a value is a MDB2 connection + * + * @param mixed $value value to test + * @return bool whether $value is a MDB2 connection + * @access public + */ + function isConnection($value) + { + return is_a($value, 'MDB2_Driver_Common'); + } + + // }}} + // {{{ isResult() + /** + * Tell whether a value is a MDB2 result + * + * @param mixed $value value to test + * @return bool whether $value is a MDB2 result + * @access public + */ + function isResult($value) + { + return is_a($value, 'MDB2_Result'); + } + + // }}} + // {{{ isResultCommon() + /** + * Tell whether a value is a MDB2 result implementing the common interface + * + * @param mixed $value value to test + * @return bool whether $value is a MDB2 result implementing the common interface + * @access public + */ + function isResultCommon($value) + { + return is_a($value, 'MDB2_Result_Common'); + } + + // }}} + // {{{ isStatement() + /** + * Tell whether a value is a MDB2 statement interface + * + * @param mixed $value value to test + * @return bool whether $value is a MDB2 statement interface + * @access public + */ + function isStatement($value) + { + return is_a($value, 'MDB2_Statement'); + } + + // }}} + // {{{ errorMessage() + + /** + * Return a textual error message for a MDB2 error code + * + * @param int $value error code + * @return string error message, or false if the error code was + * not recognized + * @access public + */ + function errorMessage($value) + { + static $errorMessages; + if (!isset($errorMessages)) { + $errorMessages = array( + MDB2_ERROR => 'unknown error', + MDB2_ERROR_ALREADY_EXISTS => 'already exists', + MDB2_ERROR_CANNOT_CREATE => 'can not create', + MDB2_ERROR_CANNOT_ALTER => 'can not alter', + MDB2_ERROR_CANNOT_REPLACE => 'can not replace', + MDB2_ERROR_CANNOT_DELETE => 'can not delete', + MDB2_ERROR_CANNOT_DROP => 'can not drop', + MDB2_ERROR_CONSTRAINT => 'constraint violation', + MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', + MDB2_ERROR_DIVZERO => 'division by zero', + MDB2_ERROR_INVALID => 'invalid', + MDB2_ERROR_INVALID_DATE => 'invalid date or time', + MDB2_ERROR_INVALID_NUMBER => 'invalid number', + MDB2_ERROR_MISMATCH => 'mismatch', + MDB2_ERROR_NODBSELECTED => 'no database selected', + MDB2_ERROR_NOSUCHFIELD => 'no such field', + MDB2_ERROR_NOSUCHTABLE => 'no such table', + MDB2_ERROR_NOT_CAPABLE => 'MDB2 backend not capable', + MDB2_ERROR_NOT_FOUND => 'not found', + MDB2_ERROR_NOT_LOCKED => 'not locked', + MDB2_ERROR_SYNTAX => 'syntax error', + MDB2_ERROR_UNSUPPORTED => 'not supported', + MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', + MDB2_ERROR_INVALID_DSN => 'invalid DSN', + MDB2_ERROR_CONNECT_FAILED => 'connect failed', + MDB2_OK => 'no error', + MDB2_ERROR_NEED_MORE_DATA => 'insufficient data supplied', + MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', + MDB2_ERROR_NOSUCHDB => 'no such database', + MDB2_ERROR_ACCESS_VIOLATION => 'insufficient permissions', + MDB2_ERROR_LOADMODULE => 'error while including on demand module', + MDB2_ERROR_TRUNCATED => 'truncated', + MDB2_ERROR_DEADLOCK => 'deadlock detected', + ); + } + + if (PEAR::isError($value)) { + $value = $value->getCode(); + } + + return isset($errorMessages[$value]) ? + $errorMessages[$value] : $errorMessages[MDB2_ERROR]; + } + + // }}} + // {{{ parseDSN() + + /** + * Parse a data source name. + * + * Additional keys can be added by appending a URI query string to the + * end of the DSN. + * + * The format of the supplied DSN is in its fullest form: + * + * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true + * + * + * Most variations are allowed: + * + * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 + * phptype://username:password@hostspec/database_name + * phptype://username:password@hostspec + * phptype://username@hostspec + * phptype://hostspec/database + * phptype://hostspec + * phptype(dbsyntax) + * phptype + * + * + * @param string $dsn Data Source Name to be parsed + * + * @return array an associative array with the following keys: + * + phptype: Database backend used in PHP (mysql, odbc etc.) + * + dbsyntax: Database used with regards to SQL syntax etc. + * + protocol: Communication protocol to use (tcp, unix etc.) + * + hostspec: Host specification (hostname[:port]) + * + database: Database to use on the DBMS server + * + username: User name for login + * + password: Password for login + * + * @author Tomas V.V.Cox + */ + function parseDSN($dsn) + { + $parsed = $GLOBALS['_MDB2_dsninfo_default']; + + if (is_array($dsn)) { + $dsn = array_merge($parsed, $dsn); + if (!$dsn['dbsyntax']) { + $dsn['dbsyntax'] = $dsn['phptype']; + } + return $dsn; + } + + // Find phptype and dbsyntax + if (($pos = strpos($dsn, '://')) !== false) { + $str = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 3); + } else { + $str = $dsn; + $dsn = null; + } + + // Get phptype and dbsyntax + // $str => phptype(dbsyntax) + if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { + $parsed['phptype'] = $arr[1]; + $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; + } else { + $parsed['phptype'] = $str; + $parsed['dbsyntax'] = $str; + } + + if (!count($dsn)) { + return $parsed; + } + + // Get (if found): username and password + // $dsn => username:password@protocol+hostspec/database + if (($at = strrpos($dsn,'@')) !== false) { + $str = substr($dsn, 0, $at); + $dsn = substr($dsn, $at + 1); + if (($pos = strpos($str, ':')) !== false) { + $parsed['username'] = rawurldecode(substr($str, 0, $pos)); + $parsed['password'] = rawurldecode(substr($str, $pos + 1)); + } else { + $parsed['username'] = rawurldecode($str); + } + } + + // Find protocol and hostspec + + // $dsn => proto(proto_opts)/database + if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { + $proto = $match[1]; + $proto_opts = $match[2] ? $match[2] : false; + $dsn = $match[3]; + + // $dsn => protocol+hostspec/database (old format) + } else { + if (strpos($dsn, '+') !== false) { + list($proto, $dsn) = explode('+', $dsn, 2); + } + if (strpos($dsn, '/') !== false) { + list($proto_opts, $dsn) = explode('/', $dsn, 2); + } else { + $proto_opts = $dsn; + $dsn = null; + } + } + + // process the different protocol options + $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; + $proto_opts = rawurldecode($proto_opts); + if ($parsed['protocol'] == 'tcp') { + if (strpos($proto_opts, ':') !== false) { + list($parsed['hostspec'], $parsed['port']) = explode(':', $proto_opts); + } else { + $parsed['hostspec'] = $proto_opts; + } + } elseif ($parsed['protocol'] == 'unix') { + $parsed['socket'] = $proto_opts; + } + + // Get dabase if any + // $dsn => database + if ($dsn) { + // /database + if (($pos = strpos($dsn, '?')) === false) { + $parsed['database'] = $dsn; + // /database?param1=value1¶m2=value2 + } else { + $parsed['database'] = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 1); + if (strpos($dsn, '&') !== false) { + $opts = explode('&', $dsn); + } else { // database?param1=value1 + $opts = array($dsn); + } + foreach ($opts as $opt) { + list($key, $value) = explode('=', $opt); + if (!isset($parsed[$key])) { + // don't allow params overwrite + $parsed[$key] = rawurldecode($value); + } + } + } + } + + return $parsed; + } + + // }}} + // {{{ fileExists() + + /** + * checks if a file exists in the include path + * + * @access public + * @param string filename + * + * @return boolean true success and false on error + */ + function fileExists($file) + { + $dirs = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($dirs as $dir) { + if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) { + return true; + } + } + return false; + } +} + +/** + * MDB2_Error implements a class for reporting portable database error + * messages. + * + * @package MDB2 + * @category Database + * @author Stig Bakken + */ +class MDB2_Error extends PEAR_Error +{ + // }}} + // {{{ constructor + + /** + * MDB2_Error constructor. + * + * @param mixed $code MDB2 error code, or string with error message. + * @param integer $mode what 'error mode' to operate in + * @param integer $level what error level to use for + * $mode & PEAR_ERROR_TRIGGER + * @param smixed $debuginfo additional debug info, such as the last query + */ + function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code), $code, + $mode, $level, $debuginfo); + } +} + +/** + * MDB2_Driver_Common: Base class that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Common extends PEAR +{ + /** + * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array + * @var integer + * @access public + */ + var $db_index = 0; + + /** + * DSN used for the next query + * @var array + * @access protected + */ + var $dsn = array(); + + /** + * DSN that was used to create the current connection + * @var array + * @access protected + */ + var $connected_dsn = array(); + + /** + * connection resource + * @var mixed + * @access protected + */ + var $connection = 0; + + /** + * if the current opened connection is a persistent connection + * @var boolean + * @access protected + */ + var $opened_persistent; + + /** + * the name of the database for the next query + * @var string + * @access protected + */ + var $database_name = ''; + + /** + * the name of the database currrently selected + * @var string + * @access protected + */ + var $connected_database_name = ''; + + /** + * list of all supported features of the given driver + * @var array + * @access public + */ + var $supported = array( + 'sequences' => false, + 'indexes' => false, + 'affected_rows' => false, + 'summary_functions' => false, + 'order_by_text' => false, + 'transactions' => false, + 'current_id' => false, + 'limit_queries' => false, + 'LOBs' => false, + 'replace' => false, + 'sub_selects' => false, + 'auto_increment' => false, + 'primary_key' => false, + ); + + /** + * $options['ssl'] -> determines if ssl should be used for connections + * $options['field_case'] -> determines what case to force on field/table names + * $options['disable_query'] -> determines if querys should be executed + * $options['result_class'] -> class used for result sets + * $options['buffered_result_class'] -> class used for buffered result sets + * $options['result_wrap_class'] -> class used to wrap result sets into + * $options['result_buffering'] -> boolean|integer should results be buffered or not? + * $options['fetch_class'] -> class to use when fetch mode object is used + * $options['persistent'] -> boolean persistent connection? + * $options['debug'] -> integer numeric debug level + * $options['debug_handler'] -> string function/meothd that captures debug messages + * $options['lob_buffer_length'] -> integer LOB buffer length + * $options['log_line_break'] -> string line-break format + * $options['idxname_format'] -> string pattern for index name + * $options['seqname_format'] -> string pattern for sequence name + * $options['seqcol_name'] -> string sequence column name + * $options['quote_identifier'] -> if identifier quoting should be done when check_option is used + * $options['use_transactions'] -> boolean + * $options['decimal_places'] -> integer + * $options['portability'] -> portability constant + * $options['modules'] -> short to long module name mapping for __call() + * @var array + * @access public + */ + var $options = array( + 'ssl' => false, + 'field_case' => CASE_LOWER, + 'disable_query' => false, + 'result_class' => 'MDB2_Result_%s', + 'buffered_result_class' => 'MDB2_BufferedResult_%s', + 'result_wrap_class' => false, + 'result_buffering' => true, + 'fetch_class' => 'stdClass', + 'persistent' => false, + 'debug' => 0, + 'debug_handler' => 'MDB2_defaultDebugOutput', + 'lob_buffer_length' => 8192, + 'log_line_break' => "\n", + 'idxname_format' => '%s_idx', + 'seqname_format' => '%s_seq', + 'seqcol_name' => 'sequence', + 'quote_identifier' => false, + 'use_transactions' => false, + 'decimal_places' => 2, + 'portability' => MDB2_PORTABILITY_ALL, + 'modules' => array( + 'ex' => 'Extended', + 'dt' => 'Datatype', + 'mg' => 'Manager', + 'rv' => 'Reverse', + 'na' => 'Native', + 'fc' => 'Function', + ), + ); + + /** + * escape character + * @var string + * @access protected + */ + var $escape_quotes = ''; + + /** + * warnings + * @var array + * @access protected + */ + var $warnings = array(); + + /** + * string with the debugging information + * @var string + * @access public + */ + var $debug_output = ''; + + /** + * determine if there is an open transaction + * @var boolean + * @access protected + */ + var $in_transaction = false; + + /** + * result offset used in the next query + * @var integer + * @access protected + */ + var $offset = 0; + + /** + * result limit used in the next query + * @var integer + * @access protected + */ + var $limit = 0; + + /** + * Database backend used in PHP (mysql, odbc etc.) + * @var string + * @access protected + */ + var $phptype; + + /** + * Database used with regards to SQL syntax etc. + * @var string + * @access protected + */ + var $dbsyntax; + + /** + * the last query sent to the driver + * @var string + * @access public + */ + var $last_query; + + /** + * the default fetchmode used + * @var integer + * @access protected + */ + var $fetchmode = MDB2_FETCHMODE_ORDERED; + + /** + * array of module instances + * @var array + * @access protected + */ + var $modules = array(); + + /** + * determines of the PHP4 destructor emulation has been enabled yet + * @var array + * @access protected + */ + var $destructor_registered = true; + + // }}} + // {{{ constructor + + /** + * Constructor + */ + function __construct() + { + end($GLOBALS['_MDB2_databases']); + $db_index = key($GLOBALS['_MDB2_databases']) + 1; + $GLOBALS['_MDB2_databases'][$db_index] = &$this; + $this->db_index = $db_index; + } + + // }}} + // {{{ MDB2_Driver_Common + + /** + * PHP 4 Constructor + */ + function MDB2_Driver_Common() + { + $this->destructor_registered = false; + $this->__construct(); + } + + // }}} + // {{{ Destructor + + /** + * Destructor + */ + function __destruct() + { + $this->disconnect(false); + } + + // }}} + // {{{ free() + + /** + * Free the internal references so that the instance can be destroyed + * + * @return boolean true on success, false if result is invalid + * @access public + */ + function free() + { + unset($GLOBALS['_MDB2_databases'][$this->db_index]); + unset($this->db_index); + return MDB2_OK; + } + + // }}} + // {{{ __toString() + + /** + * String conversation + * + * @return string + * @access public + */ + function __toString() + { + $info = get_class($this); + $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')'; + if ($this->connection) { + $info.= ' [connected]'; + } + return $info; + } + + // }}} + // {{{ errorInfo() + + /** + * This method is used to collect information about an error + * + * @param integer $error + * @return array + * @access public + */ + function errorInfo($error = null) + { + return array($error, null, null); + } + + // }}} + // {{{ raiseError() + + /** + * This method is used to communicate an error and invoke error + * callbacks etc. Basically a wrapper for PEAR::raiseError + * without the message string. + * + * @param mixed integer error code, or a PEAR error object (all + * other parameters are ignored if this parameter is + * an object + * + * @param int error mode, see PEAR_Error docs + * + * @param mixed If error mode is PEAR_ERROR_TRIGGER, this is the + * error level (E_USER_NOTICE etc). If error mode is + * PEAR_ERROR_CALLBACK, this is the callback function, + * either as a function name, or as an array of an + * object and method name. For other error modes this + * parameter is ignored. + * + * @param string Extra debug information. Defaults to the last + * query and native error code. + * + * @return object a PEAR error object + * + * @see PEAR_Error + */ + function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) + { + // The error is yet a MDB2 error object + if (PEAR::isError($code)) { + // because we use the static PEAR::raiseError, our global + // handler should be used if it is set + if (is_null($mode) && !empty($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + } + } elseif (is_null($userinfo) && isset($this->connection)) { + if (!empty($this->last_query)) { + $userinfo = "[Last query: {$this->last_query}]\n"; + } + $native_errno = $native_msg = null; + list($code, $native_errno, $native_msg) = $this->errorInfo($code); + if (!is_null($native_errno)) { + $userinfo.= "[Native code: $native_errno]\n"; + } + if (!is_null($native_msg)) { + $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n"; + } + } else { + $userinfo = "[Error message: $userinfo]\n"; + } + + $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true); + return $err; + } + + // }}} + // {{{ resetWarnings() + + /** + * reset the warning array + * + * @access public + */ + function resetWarnings() + { + $this->warnings = array(); + } + + // }}} + // {{{ getWarnings() + + /** + * get all warnings in reverse order. + * This means that the last warning is the first element in the array + * + * @return array with warnings + * @access public + * @see resetWarnings() + */ + function getWarnings() + { + return array_reverse($this->warnings); + } + + // }}} + // {{{ setFetchMode() + + /** + * Sets which fetch mode should be used by default on queries + * on this connection + * + * @param integer $fetchmode MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC + * or MDB2_FETCHMODE_OBJECT + * @param string $object_class the class name of the object to be returned + * by the fetch methods when the + * MDB2_FETCHMODE_OBJECT mode is selected. + * If no class is specified by default a cast + * to object from the assoc array row will be + * done. There is also the posibility to use + * and extend the 'MDB2_row' class. + * + * @return mixed MDB2_OK or MDB2 Error Object + * @see MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT + * @access public + */ + function setFetchMode($fetchmode, $object_class = 'stdClass') + { + switch ($fetchmode) { + case MDB2_FETCHMODE_OBJECT: + $this->options['fetch_class'] = $object_class; + case MDB2_FETCHMODE_ORDERED: + case MDB2_FETCHMODE_ASSOC: + $this->fetchmode = $fetchmode; + break; + default: + return $this->raiseError('invalid fetchmode mode'); + } + + return MDB2_OK; + } + + // }}} + // {{{ setOption() + + /** + * set the option for the db class + * + * @param string $option option name + * @param mixed $value value for the option + * @return mixed MDB2_OK or MDB2 Error Object + * @access public + */ + function setOption($option, $value) + { + if (array_key_exists($option, $this->options)) { + $this->options[$option] = $value; + return MDB2_OK; + } + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + "unknown option $option"); + } + + // }}} + // {{{ getOption() + + /** + * returns the value of an option + * + * @param string $option option name + * @return mixed the option value or error object + * @access public + */ + function getOption($option) + { + if (array_key_exists($option, $this->options)) { + return $this->options[$option]; + } + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + "unknown option $option"); + } + + // }}} + // {{{ debug() + + /** + * set a debug message + * + * @param string $message Message with information for the user. + * @access public + */ + function debug($message, $scope = '', $is_manip = null) + { + if ($this->options['debug'] && $this->options['debug_handler']) { + call_user_func_array($this->options['debug_handler'], array(&$this, $scope, $message, $is_manip)); + } + } + + // }}} + // {{{ getDebugOutput() + + /** + * output debug info + * + * @return string content of the debug_output class variable + * @access public + */ + function getDebugOutput() + { + return $this->debug_output; + } + + // }}} + // {{{ escape() + + /** + * Quotes a string so it can be safely used in a query. It will quote + * the text so it can safely be used within a query. + * + * @param string $text the input string to quote + * @return string quoted string + * @access public + */ + function escape($text) + { + if ($this->escape_quotes !== "'") { + $text = str_replace($this->escape_quotes, $this->escape_quotes.$this->escape_quotes, $text); + } + return str_replace("'", $this->escape_quotes . "'", $text); + } + + // }}} + // {{{ quoteIdentifier() + + /** + * Quote a string so it can be safely used as a table or column name + * + * Delimiting style depends on which database driver is being used. + * + * NOTE: just because you CAN use delimited identifiers doesn't mean + * you SHOULD use them. In general, they end up causing way more + * problems than they solve. + * + * Portability is broken by using the following characters inside + * delimited identifiers: + * + backtick (`) -- due to MySQL + * + double quote (") -- due to Oracle + * + brackets ([ or ]) -- due to Access + * + * Delimited identifiers are known to generally work correctly under + * the following drivers: + * + mssql + * + mysql + * + mysqli + * + oci8 + * + odbc(access) + * + odbc(db2) + * + pgsql + * + sqlite + * + sybase + * + * InterBase doesn't seem to be able to use delimited identifiers + * via PHP 4. They work fine under PHP 5. + * + * @param string $str identifier name to be quoted + * @param bool $check_option check the 'quote_identifier' option + * + * @return string quoted identifier string + * + * @access public + */ + function quoteIdentifier($str, $check_option = false) + { + if ($check_option && !$this->options['quote_identifier']) { + return $str; + } + return '"' . str_replace('"', '""', $str) . '"'; + } + + // }}} + // {{{ getConnection() + + /** + * Returns a native connection + * + * @return mixed a valid MDB2 connection object, + * or a MDB2 error object on error + * @access public + */ + function getConnection() + { + $result = $this->connect(); + if (PEAR::isError($result)) { + return $result; + } + return $this->connection; + } + + // }}} + // {{{ _fixResultArrayValues() + + /** + * Do all necessary conversions on result arrays to fix DBMS quirks + * + * @param array $array the array to be fixed (passed by reference) + * @return void + * @access protected + */ + function _fixResultArrayValues(&$array, $mode) + { + switch ($mode) { + case MDB2_PORTABILITY_RTRIM: + foreach ($array as $key => $value) { + if (is_string($value)) { + $array[$key] = rtrim($value); + } + } + break; + case MDB2_PORTABILITY_EMPTY_TO_NULL: + foreach ($array as $key => $value) { + if ($value === '') { + $array[$key] = null; + } + } + break; + case MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES: + $tmp_array = array(); + foreach ($array as $key => $value) { + $tmp_array[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $array = $tmp_array; + break; + case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL): + foreach ($array as $key => $value) { + if ($value === '') { + $array[$key] = null; + } elseif (is_string($value)) { + $array[$key] = rtrim($value); + } + } + break; + case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): + $tmp_array = array(); + foreach ($array as $key => $value) { + if (is_string($value)) { + $value = rtrim($value); + } + $tmp_array[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $array = $tmp_array; + break; + case (MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): + $tmp_array = array(); + foreach ($array as $key => $value) { + if ($value === '') { + $value = null; + } + $tmp_array[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $array = $tmp_array; + break; + case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): + $tmp_array = array(); + foreach ($array as $key => $value) { + if ($value === '') { + $value = null; + } elseif (is_string($value)) { + $value = rtrim($value); + } + $tmp_array[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $array = $tmp_array; + break; + } + } + + // }}} + // {{{ loadModule() + + /** + * loads a module + * + * @param string $module name of the module that should be loaded + * (only used for error messages) + * @param string $property name of the property into which the class will be loaded + * @param boolean $phptype_specific if the class to load for the module + is specific to the phptype + * @return object on success a reference to the given module is returned + * and on failure a PEAR error + * @access public + */ + function &loadModule($module, $property = null, $phptype_specific = null) + { + if (!$property) { + $property = strtolower($module); + } + + if (!isset($this->{$property})) { + $version = $phptype_specific; + if ($phptype_specific !== false) { + $version = true; + $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype; + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + } + if ($phptype_specific === false + || (!class_exists($class_name) && !MDB2::fileExists($file_name)) + ) { + $version = false; + $class_name = 'MDB2_'.$module; + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + } + + if (!class_exists($class_name)) { + if ($this->options['debug']) { + $include = include_once($file_name); + } else { + $include = @include_once($file_name); + } + if (!$include) { + if (!MDB2::fileExists($file_name)) { + $msg = "unable to find module '$module' file '$file_name'"; + } else { + $msg = "unable to load '$module' driver class from file '$file_name'"; + } + $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null, $msg); + return $err; + } + } + + // load modul in a specific version + if ($version) { + if (method_exists($class_name, 'getClassName')) { + $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index); + if ($class_name != $class_name_new) { + $class_name = $class_name_new; + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + if ($this->options['debug']) { + $include = include_once($file_name); + } else { + $include = @include_once($file_name); + } + if (!$include) { + if (!MDB2::fileExists($file_name)) { + $msg = "unable to find module '$module' file '$file_name'"; + } else { + $msg = "unable to load '$module' driver class from file '$file_name'"; + } + $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null, $msg); + return $err; + } + } + } + } + + if (!class_exists($class_name)) { + $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null, + "unable to load module '$module' into property '$property'"); + return $err; + } + $this->{$property} =& new $class_name($this->db_index); + $this->modules[$module] =& $this->{$property}; + if ($version) { + // this wil be used in the connect method to determine if the module + // needs to be loaded with a different version if the server + // version changed in between connects + $this->loaded_version_modules[] = $property; + } + } + + return $this->{$property}; + } + + /** + * Calls a module method using the __call magic method + * + * @param string Method name. + * @param array Arguments. + * @return mixed Returned value. + */ + function __call($method, $params) + { + $module = null; + if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match) + && isset($this->options['modules'][$match[1]]) + ) { + $module = $this->options['modules'][$match[1]]; + $method = strtolower($match[2]).$match[3]; + if (!isset($this->modules[$module]) || !is_object($this->modules[$module])) { + $result =& $this->loadModule($module); + if (PEAR::isError($result)) { + return $result; + } + } + } else { + foreach ($this->modules as $key => $foo) { + if (is_object($this->modules[$key]) + && method_exists($this->modules[$key], $method) + ) { + $module = $key; + break; + } + } + } + if (!is_null($module)) { + return call_user_func_array(array(&$this->modules[$module], $method), $params); + } + trigger_error(sprintf('Call to undefined function: %s::%s().', get_class($this), $method), E_USER_ERROR); + } + + // }}} + // {{{ beginTransaction() + + /** + * Start a transaction. + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function beginTransaction() + { + $this->debug('Starting transaction', 'beginTransaction'); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'beginTransaction: transactions are not supported'); + } + + // }}} + // {{{ commit() + + /** + * Commit the database changes done during a transaction that is in + * progress. This function may only be called when auto-committing is + * disabled, otherwise it will fail. Therefore, a new transaction is + * implicitly started after committing the pending changes. + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function commit() + { + $this->debug('commiting transaction', 'commit'); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'commit: commiting transactions is not supported'); + } + + // }}} + // {{{ rollback() + + /** + * Cancel any database changes done during a transaction that is in + * progress. This function may only be called when auto-committing is + * disabled, otherwise it will fail. Therefore, a new transaction is + * implicitly started after canceling the pending changes. + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function rollback() + { + $this->debug('rolling back transaction', 'rollback'); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'rollback: rolling back transactions is not supported'); + } + + // }}} + // {{{ disconnect() + + /** + * Log out and disconnect from the database. + * + * @return mixed true on success, false if not connected and error + * object on error + * @access public + */ + function disconnect() + { + return MDB2_OK; + } + + // }}} + // {{{ setDatabase() + + /** + * Select a different database + * + * @param string $name name of the database that should be selected + * @return string name of the database previously connected to + * @access public + */ + function setDatabase($name) + { + $previous_database_name = (isset($this->database_name)) ? $this->database_name : ''; + $this->database_name = $name; + return $previous_database_name; + } + + // }}} + // {{{ getDatabase() + + /** + * get the current database + * + * @return string name of the database + * @access public + */ + function getDatabase() + { + return $this->database_name; + } + + // }}} + // {{{ setDSN() + + /** + * set the DSN + * + * @param mixed $dsn DSN string or array + * @return MDB2_OK + * @access public + */ + function setDSN($dsn) + { + $dsn_default = $GLOBALS['_MDB2_dsninfo_default']; + $dsn = MDB2::parseDSN($dsn); + if (array_key_exists('database', $dsn)) { + $this->database_name = $dsn['database']; + unset($dsn['database']); + } + $this->dsn = array_merge($dsn_default, $dsn); + return MDB2_OK; + } + + // }}} + // {{{ getDSN() + + /** + * return the DSN as a string + * + * @param string $type format to return ("array", "string") + * @param string $hidepw string to hide the password with + * @return mixed DSN in the chosen type + * @access public + */ + function getDSN($type = 'string', $hidepw = false) + { + $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn); + $dsn['phptype'] = $this->phptype; + $dsn['database'] = $this->database_name; + if ($hidepw) { + $dsn['password'] = $hidepw; + } + switch ($type) { + // expand to include all possible options + case 'string': + $dsn = $dsn['phptype']. + ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : ''). + '://'.$dsn['username'].':'. + $dsn['password'].'@'.$dsn['hostspec']. + ($dsn['port'] ? (':'.$dsn['port']) : ''). + '/'.$dsn['database']; + break; + case 'array': + default: + break; + } + return $dsn; + } + + // }}} + // {{{ standaloneQuery() + + /** + * execute a query as database administrator + * + * @param string $query the SQL query + * @param mixed $types array that contains the types of the columns in + * the result set + * @param boolean $is_manip if the query is a manipulation query + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function &standaloneQuery($query, $types = null, $is_manip = false) + { + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $result = $this->_doQuery($query, $is_manip, $connection, false); + if (PEAR::isError($result)) { + return $result; + } + + if ($is_manip) { + $affected_rows = $this->_affectedRows($connection, $result); + return $affected_rows; + } + $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset); + return $result; + } + + // }}} + // {{{ _modifyQuery() + + /** + * Changes a query string for various DBMS specific reasons + * + * @param string $query query to modify + * @return the new (modified) query + * @access protected + */ + function _modifyQuery($query) + { + return $query; + } + + // }}} + // {{{ _doQuery() + + /** + * Execute a query + * @param string $query query + * @param boolean $is_manip if the query is a manipulation query + * @param resource $connection + * @param string $database_name + * @return result or error object + * @access protected + */ + function _doQuery($query, $is_manip = false, $connection = null, $database_name = null) + { + $this->last_query = $query; + $this->debug($query, 'query', $is_manip); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + '_doQuery: method not implemented'); + } + + // }}} + // {{{ _affectedRows() + + /** + * returns the number of rows affected + * + * @param resource $result + * @param resource $connection + * @return mixed MDB2 Error Object or the number of rows affected + * @access private + */ + function _affectedRows($connection, $result = null) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + '_affectedRows: method not implemented'); + } + + // }}} + // {{{ exec() + + /** + * Execute a manipulation query to the database and return any the affected rows + * + * @param string $query the SQL query + * @return mixed affected rows on success, a MDB2 error on failure + * @access public + */ + function exec($query) + { + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $query = $this->_modifyQuery($query, true, $limit, $offset); + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $result = $this->_doQuery($query, true, $connection, $this->database_name); + if (PEAR::isError($result)) { + return $result; + } + + return $this->_affectedRows($connection, $result); + } + + // }}} + // {{{ query() + + /** + * Send a query to the database and return any results + * + * @param string $query the SQL query + * @param mixed $types array that contains the types of the columns in + * the result set + * @param mixed $result_class string which specifies which result class to use + * @param mixed $result_wrap_class string which specifies which class to wrap results in + * @return object a result handle on success, a MDB2 error on failure + * @access public + */ + function &query($query, $types = null, $result_class = true, $result_wrap_class = false) + { + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $query = $this->_modifyQuery($query, false, $limit, $offset); + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $result = $this->_doQuery($query, false, $connection, $this->database_name); + if (PEAR::isError($result)) { + return $result; + } + + $result =& $this->_wrapResult($result, $types, $result_class, $result_wrap_class, $limit, $offset); + return $result; + } + + // }}} + // {{{ _wrapResult() + + /** + * wrap a result set into the correct class + * + * @param ressource $result + * @param mixed $types array that contains the types of the columns in + * the result set + * @param mixed $result_class string which specifies which result class to use + * @param mixed $result_wrap_class string which specifies which class to wrap results in + * @param string $limit number of rows to select + * @param string $offset first row to select + * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function &_wrapResult($result, $types = array(), $result_class = true, + $result_wrap_class = false, $limit = null, $offset = null) + { + if ($types === true) { + $this->loadModule('Reverse', null, true); + $tableInfo = $this->reverse->tableInfo($result); + if (PEAR::isError($tableInfo)) { + return $tableInfo; + } + $types = array(); + foreach ($tableInfo as $field) { + $types[] = $field['mdb2type']; + } + } + + if ($result_class === true) { + $result_class = $this->options['result_buffering'] + ? $this->options['buffered_result_class'] : $this->options['result_class']; + } + + if ($result_class) { + $class_name = sprintf($result_class, $this->phptype); + if (!class_exists($class_name)) { + $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + '_wrapResult: result class does not exist '.$class_name); + return $err; + } + $result =& new $class_name($this, $result, $limit, $offset); + if (!MDB2::isResultCommon($result)) { + $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + '_wrapResult: result class is not extended from MDB2_Result_Common'); + return $err; + } + if (!empty($types)) { + $err = $result->setResultTypes($types); + if (PEAR::isError($err)) { + $result->free(); + return $err; + } + } + } + if ($result_wrap_class === true) { + $result_wrap_class = $this->options['result_wrap_class']; + } + if ($result_wrap_class) { + if (!class_exists($result_wrap_class)) { + $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + '_wrapResult: result wrap class does not exist '.$result_wrap_class); + return $err; + } + $result =& new $result_wrap_class($result, $this->fetchmode); + } + return $result; + } + + // }}} + // {{{ getServerVersion() + + /** + * return version information about the server + * + * @param string $native determines if the raw version string should be returned + * @return mixed array with versoin information or row string + * @access public + */ + function getServerVersion($native = false) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'getServerVersion: method not implemented'); + } + + // }}} + // {{{ setLimit() + + /** + * set the range of the next query + * + * @param string $limit number of rows to select + * @param string $offset first row to select + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function setLimit($limit, $offset = null) + { + if (!$this->supports('limit_queries')) { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'setLimit: limit is not supported by this driver'); + } + $limit = (int)$limit; + if ($limit < 0) { + return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'setLimit: it was not specified a valid selected range row limit'); + } + $this->limit = $limit; + if (!is_null($offset)) { + $offset = (int)$offset; + if ($offset < 0) { + return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'setLimit: it was not specified a valid first selected range row'); + } + $this->offset = $offset; + } + return MDB2_OK; + } + + // }}} + // {{{ subSelect() + + /** + * simple subselect emulation: leaves the query untouched for all RDBMS + * that support subselects + * + * @access public + * + * @param string $query the SQL query for the subselect that may only + * return a column + * @param string $type determines type of the field + * + * @return string the query + */ + function subSelect($query, $type = false) + { + if ($this->supports('sub_selects') === true) { + return $query; + } + + if (!$this->supports('sub_selects')) { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'subSelect: method not implemented'); + } + + $col = $this->queryCol($query, $type); + if (PEAR::isError($col)) { + return $col; + } + if (!is_array($col) || count($col) == 0) { + return 'NULL'; + } + if ($type) { + $this->loadModule('Datatype', null, true); + return $this->datatype->implodeArray($col, $type); + } + return implode(', ', $col); + } + + // }}} + // {{{ replace() + + /** + * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT + * query, except that if there is already a row in the table with the same + * key field values, the REPLACE query just updates its values instead of + * inserting a new row. + * + * The REPLACE type of query does not make part of the SQL standards. Since + * pratically only MySQL implements it natively, this type of query is + * emulated through this method for other DBMS using standard types of + * queries inside a transaction to assure the atomicity of the operation. + * + * @param string $table name of the table on which the REPLACE query will + * be executed. + * @param array $fields associative array that describes the fields and the + * values that will be inserted or updated in the specified table. The + * indexes of the array are the names of all the fields of the table. + * The values of the array are also associative arrays that describe + * the values and other properties of the table fields. + * + * Here follows a list of field properties that need to be specified: + * + * value + * Value to be assigned to the specified field. This value may be + * of specified in database independent type format as this + * function can perform the necessary datatype conversions. + * + * Default: this property is required unless the Null property is + * set to 1. + * + * type + * Name of the type of the field. Currently, all types Metabase + * are supported except for clob and blob. + * + * Default: no type conversion + * + * null + * Boolean property that indicates that the value for this field + * should be set to null. + * + * The default value for fields missing in INSERT queries may be + * specified the definition of a table. Often, the default value + * is already null, but since the REPLACE may be emulated using + * an UPDATE query, make sure that all fields of the table are + * listed in this function argument array. + * + * Default: 0 + * + * key + * Boolean property that indicates that this field should be + * handled as a primary key or at least as part of the compound + * unique index of the table that will determine the row that will + * updated if it exists or inserted a new row otherwise. + * + * This function will fail if no key field is specified or if the + * value of a key field is set to null because fields that are + * part of unique index they may not be null. + * + * Default: 0 + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function replace($table, $fields) + { + if (!$this->supports('replace')) { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'replace: replace query is not supported'); + } + $count = count($fields); + $condition = $values = array(); + for ($colnum = 0, reset($fields); $colnum < $count; next($fields), $colnum++) { + $name = key($fields); + if (isset($fields[$name]['null']) && $fields[$name]['null']) { + $value = 'NULL'; + } else { + if (isset($fields[$name]['type'])) { + $value = $this->quote($fields[$name]['value'], $fields[$name]['type']); + } else { + $value = $fields[$name]['value']; + } + } + $values[$name] = $value; + if (isset($fields[$name]['key']) && $fields[$name]['key']) { + if ($value === 'NULL') { + return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, + 'replace: key value '.$name.' may not be NULL'); + } + $condition[] = $name . '=' . $value; + } + } + if (empty($condition)) { + return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, + 'replace: not specified which fields are keys'); + } + + $result = null; + $in_transaction = $this->in_transaction; + if (!$in_transaction && PEAR::isError($result = $this->beginTransaction())) { + return $result; + } + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $condition = ' WHERE '.implode(' AND ', $condition); + $query = "DELETE FROM $table$condition"; + $result = $this->_doQuery($query, true, $connection); + if (!PEAR::isError($result)) { + $affected_rows = $this->_affectedRows($connection, $result); + $insert = implode(', ', array_keys($values)); + $values = implode(', ', $values); + $query = "INSERT INTO $table ($insert) VALUES ($values)"; + $result = $this->_doQuery($query, true, $connection); + if (!PEAR::isError($result)) { + $affected_rows += $this->_affectedRows($connection, $result);; + } + } + + if (!$in_transaction) { + if (PEAR::isError($result)) { + $this->rollback(); + } else { + $result = $this->commit(); + } + } + + if (PEAR::isError($result)) { + return $result; + } + + return $affected_rows; + } + + // }}} + // {{{ prepare() + + /** + * Prepares a query for multiple execution with execute(). + * With some database backends, this is emulated. + * prepare() requires a generic query as string like + * 'INSERT INTO numbers VALUES(?,?)' or + * 'INSERT INTO numbers VALUES(:foo,:bar)'. + * The ? and :[a-zA-Z] and are placeholders which can be set using + * bindParam() and the query can be send off using the execute() method. + * + * @param string $query the query to prepare + * @param mixed $types array that contains the types of the placeholders + * @param mixed $result_types array that contains the types of the columns in + * the result set, if set to MDB2_PREPARE_MANIP the + query is handled as a manipulation query + * @param mixed $lobs key (field) value (parameter) pair for all lob placeholders + * @return mixed resource handle for the prepared query on success, a MDB2 + * error on failure + * @access public + * @see bindParam, execute + */ + function &prepare($query, $types = null, $result_types = null, $lobs = array()) + { + $is_manip = ($result_types === MDB2_PREPARE_MANIP); + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $this->debug($query, 'prepare', $is_manip); + $positions = array(); + $placeholder_type_guess = $placeholder_type = null; + $question = '?'; + $colon = ':'; + $positions = array(); + $position = 0; + while ($position < strlen($query)) { + $q_position = strpos($query, $question, $position); + $c_position = strpos($query, $colon, $position); + if ($q_position && $c_position) { + $p_position = min($q_position, $c_position); + } elseif ($q_position) { + $p_position = $q_position; + } elseif ($c_position) { + $p_position = $c_position; + } else { + break; + } + if (is_null($placeholder_type)) { + $placeholder_type_guess = $query[$p_position]; + } + if (is_int($quote = strpos($query, "'", $position)) && $quote < $p_position) { + if (!is_int($end_quote = strpos($query, "'", $quote + 1))) { + $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'prepare: query with an unterminated text string specified'); + return $err; + } + switch ($this->escape_quotes) { + case '': + case "'": + $position = $end_quote + 1; + break; + default: + if ($end_quote == $quote + 1) { + $position = $end_quote + 1; + } else { + if ($query[$end_quote-1] == $this->escape_quotes) { + $position = $end_quote; + } else { + $position = $end_quote + 1; + } + } + break; + } + } elseif ($query[$position] == $placeholder_type_guess) { + if (is_null($placeholder_type)) { + $placeholder_type = $query[$p_position]; + $question = $colon = $placeholder_type; + if (is_array($types) && !empty($types)) { + if ($placeholder_type == ':') { + if (is_int(key($types))) { + $types_tmp = $types; + $types = array(); + $count = -1; + } + } else { + $types = array_values($types); + } + } + } + if ($placeholder_type == ':') { + $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); + if ($parameter === '') { + $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'prepare: named parameter with an empty name'); + return $err; + } + $positions[$parameter] = $p_position; + $query = substr_replace($query, '?', $position, strlen($parameter)+1); + // use parameter name in type array + if (isset($count) && isset($types_tmp[++$count])) { + $types[$parameter] = $types_tmp[$count]; + } + } else { + $positions[] = $p_position; + } + $position = $p_position + 1; + } else { + $position = $p_position; + } + } + $class_name = 'MDB2_Statement_'.$this->phptype; + $statement = null; + $obj =& new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); + return $obj; + } + + // }}} + // {{{ quote() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param string $type type to which the value should be converted to + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access public + */ + function quote($value, $type = null, $quote = true) + { + $result = $this->loadModule('Datatype', null, true); + if (PEAR::isError($result)) { + return $result; + } + return $this->datatype->quote($value, $type, $quote); + } + + // }}} + // {{{ getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare + * of the given type + * + * @param string $type type to which the value should be converted to + * @param string $name name the field to be declared. + * @param string $field definition of the field + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function getDeclaration($type, $name, $field) + { + $result = $this->loadModule('Datatype', null, true); + if (PEAR::isError($result)) { + return $result; + } + return $this->datatype->getDeclaration($type, $name, $field); + } + + // }}} + // {{{ compareDefinition() + + /** + * Obtain an array of changes that may need to applied + * + * @param array $current new definition + * @param array $previous old definition + * @return array containg all changes that will need to be applied + * @access public + */ + function compareDefinition($current, $previous) + { + $result = $this->loadModule('Datatype', null, true); + if (PEAR::isError($result)) { + return $result; + } + return $this->datatype->compareDefinition($current, $previous); + } + + // }}} + // {{{ supports() + + /** + * Tell whether a DB implementation or its backend extension + * supports a given feature. + * + * @param string $feature name of the feature (see the MDB2 class doc) + * @return boolean|string whether this DB implementation supports $feature + * false means no, true means native, 'emulated' means emulated + * @access public + */ + function supports($feature) + { + if (array_key_exists($feature, $this->supported)) { + return $this->supported[$feature]; + } + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + "unknown support feature $feature"); + } + + // }}} + // {{{ getSequenceName() + + /** + * adds sequence name formatting to a sequence name + * + * @param string $sqn name of the sequence + * @return string formatted sequence name + * @access public + */ + function getSequenceName($sqn) + { + return sprintf($this->options['seqname_format'], + preg_replace('/[^a-z0-9_]/i', '_', $sqn)); + } + + // }}} + // {{{ getIndexName() + + /** + * adds index name formatting to a index name + * + * @param string $idx name of the index + * @return string formatted index name + * @access public + */ + function getIndexName($idx) + { + return sprintf($this->options['idxname_format'], + preg_replace('/[^a-z0-9_]/i', '_', $idx)); + } + + // }}} + // {{{ nextID() + + /** + * returns the next free id of a sequence + * + * @param string $seq_name name of the sequence + * @param boolean $ondemand when true the seqence is + * automatic created, if it + * not exists + * @return mixed MDB2 Error Object or id + * @access public + */ + function nextID($seq_name, $ondemand = true) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'nextID: method not implemented'); + } + + // }}} + // {{{ lastInsertID() + + /** + * returns the autoincrement ID if supported or $id + * + * @param mixed $id value as returned by getBeforeId() + * @param string $table name of the table into which a new row was inserted + * @return mixed MDB2 Error Object or id + * @access public + */ + function lastInsertID($table = null, $field = null) + { + $seq = $table.(empty($field) ? '' : '_'.$field); + return $this->currID($seq); + } + + // }}} + // {{{ currID() + + /** + * returns the current id of a sequence + * + * @param string $seq_name name of the sequence + * @return mixed MDB2 Error Object or id + * @access public + */ + function currID($seq_name) + { + $this->warnings[] = 'database does not support getting current + sequence value, the sequence value was incremented'; + return $this->nextID($seq_name); + } + + // }}} + // {{{ queryOne() + + /** + * Execute the specified query, fetch the value from the first column of + * the first row of the result set and then frees + * the result set. + * + * @param string $query the SELECT query statement to be executed. + * @param string $type optional argument that specifies the expected + * datatype of the result set field, so that an eventual conversion + * may be performed. The default datatype is text, meaning that no + * conversion is performed + * @return mixed MDB2_OK or field value on success, a MDB2 error on failure + * @access public + */ + function queryOne($query, $type = null) + { + $result = $this->query($query, $type); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $one = $result->fetchOne(); + $result->free(); + return $one; + } + + // }}} + // {{{ queryRow() + + /** + * Execute the specified query, fetch the values from the first + * row of the result set into an array and then frees + * the result set. + * + * @param string $query the SELECT query statement to be executed. + * @param array $types optional array argument that specifies a list of + * expected datatypes of the result set columns, so that the eventual + * conversions may be performed. The default list of datatypes is + * empty, meaning that no conversion is performed. + * @param int $fetchmode how the array data should be indexed + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $result = $this->query($query, $types); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $row = $result->fetchRow($fetchmode); + $result->free(); + return $row; + } + + // }}} + // {{{ queryCol() + + /** + * Execute the specified query, fetch the value from the first column of + * each row of the result set into an array and then frees the result set. + * + * @param string $query the SELECT query statement to be executed. + * @param string $type optional argument that specifies the expected + * datatype of the result set field, so that an eventual conversion + * may be performed. The default datatype is text, meaning that no + * conversion is performed + * @param int $colnum the row number to fetch + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function queryCol($query, $type = null, $colnum = 0) + { + $result = $this->query($query, $type); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $col = $result->fetchCol($colnum); + $result->free(); + return $col; + } + + // }}} + // {{{ queryAll() + + /** + * Execute the specified query, fetch all the rows of the result set into + * a two dimensional array and then frees the result set. + * + * @param string $query the SELECT query statement to be executed. + * @param array $types optional array argument that specifies a list of + * expected datatypes of the result set columns, so that the eventual + * conversions may be performed. The default list of datatypes is + * empty, meaning that no conversion is performed. + * @param int $fetchmode how the array data should be indexed + * @param boolean $rekey if set to true, the $all will have the first + * column as its first dimension + * @param boolean $force_array used only when the query returns exactly + * two columns. If true, the values of the returned array will be + * one-element arrays instead of scalars. + * @param boolean $group if true, the values of the returned array is + * wrapped in another array. If the same key value (in the first + * column) repeats itself, the values will be appended to this array + * instead of overwriting the existing values. + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, + $rekey = false, $force_array = false, $group = false) + { + $result = $this->query($query, $types); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); + $result->free(); + return $all; + } +} + +class MDB2_Result +{ +} + +class MDB2_Result_Common extends MDB2_Result +{ + var $db; + var $result; + var $rownum = -1; + var $types = array(); + var $values = array(); + var $offset; + var $offset_count = 0; + var $limit; + var $column_names; + + // {{{ constructor + + /** + * Constructor + */ + function __construct(&$db, &$result, $limit = 0, $offset = 0) + { + $this->db =& $db; + $this->result =& $result; + $this->offset = $offset; + $this->limit = max(0, $limit - 1); + } + + function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0) + { + $this->__construct($db, $result, $limit, $offset); + } + + // }}} + // {{{ setResultTypes() + + /** + * Define the list of types to be associated with the columns of a given + * result set. + * + * This function may be called before invoking fetchRow(), fetchOne(), + * fetchCol() and fetchAll() so that the necessary data type + * conversions are performed on the data to be retrieved by them. If this + * function is not called, the type of all result set columns is assumed + * to be text, thus leading to not perform any conversions. + * + * @param string $types array variable that lists the + * data types to be expected in the result set columns. If this array + * contains less types than the number of columns that are returned + * in the result set, the remaining columns are assumed to be of the + * type text. Currently, the types clob and blob are not fully + * supported. + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function setResultTypes($types) + { + $load = $this->db->loadModule('Datatype', null, true); + if (PEAR::isError($load)) { + return $load; + } + $types = $this->db->datatype->checkResultTypes($types); + if (PEAR::isError($types)) { + return $types; + } + $this->types = $types; + return MDB2_OK; + } + + // }}} + // {{{ seek() + + /** + * seek to a specific row in a result set + * + * @param int $rownum number of the row where the data can be found + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function seek($rownum = 0) + { + $target_rownum = $rownum - 1; + if ($this->rownum > $target_rownum) { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'seek: seeking to previous rows not implemented'); + } + while ($this->rownum < $target_rownum) { + $this->fetchRow(); + } + return MDB2_OK; + } + + // }}} + // {{{ fetchRow() + + /** + * Fetch and return a row of data + * + * @param int $fetchmode how the array data should be indexed + * @param int $rownum number of the row where the data can be found + * @return int data array on success, a MDB2 error on failure + * @access public + */ + function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) + { + $err =& $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'fetch: method not implemented'); + return $err; + } + + // }}} + // {{{ fetchOne() + + /** + * fetch single column from the first row from a result set + * + * @param int $colnum the column number to fetch + * @return string data on success, a MDB2 error on failure + * @access public + */ + function fetchOne($colnum = 0) + { + $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC; + $row = $this->fetchRow($fetchmode); + if (!is_array($row) || PEAR::isError($row)) { + return $row; + } + if (!array_key_exists($colnum, $row)) { + return $this->db->raiseError(MDB2_ERROR_TRUNCATED); + } + return $row[$colnum]; + } + + // }}} + // {{{ fetchCol() + + /** + * Fetch and return a column of data (it uses current for that) + * + * @param int $colnum the column number to fetch + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function fetchCol($colnum = 0) + { + $column = array(); + $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC; + $row = $this->fetchRow($fetchmode); + if (is_array($row)) { + if (!array_key_exists($colnum, $row)) { + return $this->db->raiseError(MDB2_ERROR_TRUNCATED); + } + do { + $column[] = $row[$colnum]; + } while (is_array($row = $this->fetchRow($fetchmode))); + } + if (PEAR::isError($row)) { + return $row; + } + return $column; + } + + // }}} + // {{{ fetchAll() + + /** + * Fetch and return a column of data (it uses fetchRow for that) + * + * @param int $fetchmode the fetch mode to use: + * + MDB2_FETCHMODE_ORDERED + * + MDB2_FETCHMODE_ASSOC + * + MDB2_FETCHMODE_ORDERED | MDB2_FETCHMODE_FLIPPED + * + MDB2_FETCHMODE_ASSOC | MDB2_FETCHMODE_FLIPPED + * @param boolean $rekey if set to true, the $all will have the first + * column as its first dimension + * @param boolean $force_array used only when the query returns exactly + * two columns. If true, the values of the returned array will be + * one-element arrays instead of scalars. + * @param boolean $group if true, the values of the returned array is + * wrapped in another array. If the same key value (in the first + * column) repeats itself, the values will be appended to this array + * instead of overwriting the existing values. + * @return mixed data array on success, a MDB2 error on failure + * @access public + * @see getAssoc() + */ + function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, + $force_array = false, $group = false) + { + $all = array(); + $row = $this->fetchRow($fetchmode); + if (PEAR::isError($row)) { + return $row; + } elseif (!$row) { + return $all; + } + + $shift_array = $rekey ? false : null; + if (!is_null($shift_array)) { + if (is_object($row)) { + $colnum = count(get_object_vars($row)); + } else { + $colnum = count($row); + } + if ($colnum < 2) { + return $this->db->raiseError(MDB2_ERROR_TRUNCATED); + } + $shift_array = (!$force_array && $colnum == 2); + } + + if ($rekey) { + do { + if (is_object($row)) { + $arr = get_object_vars($row); + $key = reset($arr); + unset($row->{$key}); + } else { + if ($fetchmode & MDB2_FETCHMODE_ASSOC) { + $key = reset($row); + unset($row[key($row)]); + } else { + $key = array_shift($row); + } + if ($shift_array) { + $row = array_shift($row); + } + } + if ($group) { + $all[$key][] = $row; + } else { + $all[$key] = $row; + } + } while (($row = $this->fetchRow($fetchmode))); + } elseif ($fetchmode & MDB2_FETCHMODE_FLIPPED) { + do { + foreach ($row as $key => $val) { + $all[$key][] = $val; + } + } while (($row = $this->fetchRow($fetchmode))); + } else { + do { + $all[] = $row; + } while (($row = $this->fetchRow($fetchmode))); + } + + return $all; + } + + // }}} + // {{{ rowCount() + + /** + * returns the actual row number that was last fetched (count from 0) + * @return integer + */ + function rowCount() + { + return $this->rownum + 1; + } + + // }}} + // {{{ numRows() + + /** + * returns the number of rows in a result object + * + * @return mixed MDB2 Error Object or the number of rows + * @access public + */ + function numRows() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'numRows: method not implemented'); + } + + // }}} + // {{{ nextResult() + + /** + * Move the internal result pointer to the next available result + * + * @param a valid result resource + * @return true on success, false if there is no more result set or an error object on failure + * @access public + */ + function nextResult() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'nextResult: method not implemented'); + } + + // }}} + // {{{ getColumnNames() + + /** + * Retrieve the names of columns returned by the DBMS in a query result or + * from the cache. + * + * @return mixed associative array variable + * that holds the names of columns. The indexes of the array are + * the column names mapped to lower case and the values are the + * respective numbers of the columns starting from 0. Some DBMS may + * not return any columns when the result set does not contain any + * rows. + * a MDB2 error on failure + * @access public + */ + function getColumnNames() + { + if (!isset($this->column_names)) { + $result = $this->_getColumnNames(); + if (PEAR::isError($result)) { + return $result; + } + $this->column_names = $result; + } + return $this->column_names; + } + + // }}} + // {{{ _getColumnNames() + + /** + * Retrieve the names of columns returned by the DBMS in a query result. + * + * @return mixed associative array variable + * that holds the names of columns. The indexes of the array are + * the column names mapped to lower case and the values are the + * respective numbers of the columns starting from 0. Some DBMS may + * not return any columns when the result set does not contain any + * rows. + * a MDB2 error on failure + * @access private + */ + function _getColumnNames() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'getColumnNames: method not implemented'); + } + + // }}} + // {{{ numCols() + + /** + * Count the number of columns returned by the DBMS in a query result. + * + * @return mixed integer value with the number of columns, a MDB2 error + * on failure + * @access public + */ + function numCols() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'numCols: method not implemented'); + } + + // }}} + // {{{ getResource() + + /** + * return the resource associated with the result object + * + * @return resource + * @access public + */ + function getResource() + { + return $this->result; + } + + // }}} + // {{{ bindColumn() + + /** + * Set bind variable to a column. + * + * @param int $column + * @param mixed $value + * @param string $type specifies the type of the field + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function bindColumn($column, &$value, $type = null) + { + if (!is_numeric($column)) { + $column_names = $this->getColumnNames(); + if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($this->db->options['field_case'] == CASE_LOWER) { + $column = strtolower($column); + } else { + $column = strtoupper($column); + } + } + $column = $column_names[$column]; + } + $this->values[$column] =& $value; + if (!is_null($type)) { + $this->types[$column] = $type; + } + return MDB2_OK; + } + + // }}} + // {{{ _assignBindColumns() + + /** + * Bind a variable to a value in the result row. + * + * @param array $row + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access private + */ + function _assignBindColumns($row) + { + $row = array_values($row); + foreach ($row as $column => $value) { + if (array_key_exists($column, $this->values)) { + $this->values[$column] = $value; + } + } + return MDB2_OK; + } + + // }}} + // {{{ free() + + /** + * Free the internal resources associated with result. + * + * @return boolean true on success, false if result is invalid + * @access public + */ + function free() + { + $this->result = false; + return MDB2_OK; + } +} + +// }}} +// {{{ class MDB2_Row + +/** + * Pear MDB2 Row Object + * @see MDB2_Driver_Common::setFetchMode() + */ +class MDB2_Row +{ + // {{{ constructor + + /** + * constructor + * + * @param resource row data as array + */ + function __construct(&$row) + { + foreach ($row as $key => $value) { + $this->$key = &$row[$key]; + } + } + + function MDB2_Row(&$row) + { + $this->__construct($row); + } +} + +class MDB2_Statement_Common +{ + var $db; + var $statement; + var $query; + var $result_types; + var $types; + var $values = array(); + var $limit; + var $offset; + var $is_manip; + + // {{{ constructor + + /** + * Constructor + */ + function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) + { + $this->db =& $db; + $this->statement =& $statement; + $this->positions = $positions; + $this->query = $query; + $this->types = (array)$types; + $this->result_types = (array)$result_types; + $this->limit = $limit; + $this->is_manip = $is_manip; + $this->offset = $offset; + } + + function MDB2_Statement_Common(&$db, &$statement, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) + { + $this->__construct($db, $statement, $query, $types, $result_types, $is_manip, $limit, $offset); + } + + // }}} + // {{{ bindParam() + + /** + * Set the value of a parameter of a prepared query. + * + * @param int $parameter the order number of the parameter in the query + * statement. The order number of the first parameter is 1. + * @param mixed $value value that is meant to be assigned to specified + * parameter. The type of the value depends on the $type argument. + * @param string $type specifies the type of the field + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function bindParam($parameter, &$value, $type = null) + { + if (!is_numeric($parameter)) { + $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter); + } + if (!array_key_exists($parameter, $this->positions)) { + return $this->db->raiseError(); + } + $this->values[$parameter] =& $value; + if (!is_null($type)) { + $this->types[$parameter] = $type; + } + return MDB2_OK; + } + + // }}} + // {{{ bindParamArray() + + /** + * Set the values of multiple a parameter of a prepared query in bulk. + * + * @param array $values array thats specifies all necessary infromation + * for bindParam() the array elements must use keys corresponding to + * the number of the position of the parameter. + * @param array $types specifies the types of the fields + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + * @see bindParam() + */ + function bindParamArray(&$values, $types = null) + { + $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null); + $parameters = array_keys($values); + foreach ($parameters as $key => $parameter) { + $this->bindParam($parameter, $values[$parameter], $types[$key]); + } + return MDB2_OK; + } + + // }}} + // {{{ execute() + + /** + * Execute a prepared query statement. + * + * @param array $values array thats specifies all necessary infromation + * for bindParam() the array elements must use keys corresponding to + * the number of the position of the parameter. + * @param mixed $result_class string which specifies which result class to use + * @param mixed $result_wrap_class string which specifies which class to wrap results in + * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function &execute($values = null, $result_class = true, $result_wrap_class = false) + { + if (!empty($values)) { + $this->bindParamArray($values); + } + $result =& $this->_execute($result_class, $result_wrap_class); + if (is_numeric($result)) { + $this->rownum = $result - 1; + } + return $result; + } + + // }}} + // {{{ _execute() + + /** + * Execute a prepared query statement helper method. + * + * @param mixed $result_class string which specifies which result class to use + * @param mixed $result_wrap_class string which specifies which class to wrap results in + * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure + * @access private + */ + function &_execute($result_class = true, $result_wrap_class = false) + { + $query = ''; + $last_position = 0; + foreach ($this->positions as $parameter => $current_position) { + if (!array_key_exists($parameter, $this->values)) { + return $this->db->raiseError(); + } + $value = $this->values[$parameter]; + $query.= substr($this->query, $last_position, $current_position - $last_position); + if (!isset($value)) { + $value_quoted = 'NULL'; + } else { + $type = array_key_exists($parameter, $this->types) ? $this->types[$parameter] : null; + $value_quoted = $this->db->quote($value, $type); + if (PEAR::isError($value_quoted)) { + return $value_quoted; + } + } + $query.= $value_quoted; + $last_position = $current_position + 1; + } + $query.= substr($this->query, $last_position); + + $this->db->offset = $this->offset; + $this->db->limit = $this->limit; + if ($this->is_manip) { + $result = $this->db->exec($query); + } else { + $result =& $this->db->query($query, $this->result_types, $result_class, $result_wrap_class); + } + return $result; + } + + // }}} + // {{{ free() + + /** + * Release resources allocated for the specified prepared query. + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function free() + { + return MDB2_OK; + } +} + +class MDB2_Module_Common +{ + /** + * contains the key to the global MDB2 instance array of the associated + * MDB2 instance + * + * @var integer + * @access protected + */ + var $db_index; + + // {{{ constructor + + /** + * Constructor + */ + function __construct($db_index) + { + $this->db_index = $db_index; + } + + function MDB2_Module_Common($db_index) + { + $this->__construct($db_index); + } + + // }}} + // {{{ getDBInstance() + + /** + * get the instance of MDB2 associated with the module instance + * + * @return object MDB2 instance or a MDB2 error on failure + * @access public + */ + function &getDBInstance() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $result =& $GLOBALS['_MDB2_databases'][$this->db_index]; + } else { + $result =& MDB2::raiseError(MDB2_ERROR, null, null, 'could not find MDB2 instance'); + } + return $result; + } +} + +// }}} +// {{{ MDB2_closeOpenTransactions() + +/** + * close any open transactions form persistant connections + * + * @return void + * @access public + */ +function MDB2_closeOpenTransactions() +{ + reset($GLOBALS['_MDB2_databases']); + while (next($GLOBALS['_MDB2_databases'])) { + $key = key($GLOBALS['_MDB2_databases']); + if ($GLOBALS['_MDB2_databases'][$key]->opened_persistent + && $GLOBALS['_MDB2_databases'][$key]->in_transaction + ) { + $GLOBALS['_MDB2_databases'][$key]->rollback(); + } + } +} + +// }}} +// {{{ MDB2_defaultDebugOutput() + +/** + * default debug output handler + * + * @param object $db reference to an MDB2 database object + * @param string $message message that should be appended to the debug + * variable + * @return string the corresponding error message, of false + * if the error code was unknown + * @access public + */ +function MDB2_defaultDebugOutput(&$db, $scope, $message, $is_manip = null) +{ + $db->debug_output.= $scope.'('.$db->db_index.'): '; + $db->debug_output.= $message.$db->getOption('log_line_break'); +} + +?> \ No newline at end of file Added: trunk/ofrenda-blog/html/librerias/mdb2/index.html =================================================================== Added: trunk/ofrenda-blog/html/librerias/phpmailer/ChangeLog.txt =================================================================== --- trunk/ofrenda-blog/html/librerias/phpmailer/ChangeLog.txt 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/phpmailer/ChangeLog.txt 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,184 @@ +ChangeLog + +Version 1.73 (Sun, Jun 10 2005) +* Fixed denial of service bug: http://www.cybsec.com/vuln/PHPMailer-DOS.pdf +* Now has a total of 20 translations +* Fixed alt attachments bug: http://tinyurl.com/98u9k + +Version 1.72 (Wed, May 25 2004) +* Added Dutch, Swedish, Czech, Norwegian, and Turkish translations. +* Received: Removed this method because spam filter programs like +SpamAssassin reject this header. +* Fixed error count bug. +* SetLanguage default is now "language/". +* Fixed magic_quotes_runtime bug. + +Version 1.71 (Tue, Jul 28 2003) +* Made several speed enhancements +* Added German and Italian translation files +* Fixed HELO/AUTH bugs on keep-alive connects +* Now provides an error message if language file does not load +* Fixed attachment EOL bug +* Updated some unclear documentation +* Added additional tests and improved others + +Version 1.70 (Mon, Jun 20 2003) +* Added SMTP keep-alive support +* Added IsError method for error detection +* Added error message translation support (SetLanguage) +* Refactored many methods to increase library performance +* Hello now sends the newer EHLO message before HELO as per RFC 2821 +* Removed the boundary class and replaced it with GetBoundary +* Removed queue support methods +* New $Hostname variable +* New Message-ID header +* Received header reformat +* Helo variable default changed to $Hostname +* Removed extra spaces in Content-Type definition (#667182) +* Return-Path should be set to Sender when set +* Adds Q or B encoding to headers when necessary +* quoted-encoding should now encode NULs \000 +* Fixed encoding of body/AltBody (#553370) +* Adds "To: undisclosed-recipients:;" when all recipients are hidden (BCC) +* Multiple bug fixes + +Version 1.65 (Fri, Aug 09 2002) +* Fixed non-visible attachment bug (#585097) for Outlook +* SMTP connections are now closed after each transaction +* Fixed SMTP::Expand return value +* Converted SMTP class documentation to phpDocumentor format + +Version 1.62 (Wed, Jun 26 2002) +* Fixed multi-attach bug +* Set proper word wrapping +* Reduced memory use with attachments +* Added more debugging +* Changed documentation to phpDocumentor format + +Version 1.60 (Sat, Mar 30 2002) +* Sendmail pipe and address patch (Christian Holtje) +* Added embedded image and read confirmation support (A. Ognio) +* Added unit tests +* Added SMTP timeout support (*nix only) +* Added possibly temporary PluginDir variable for SMTP class +* Added LE message line ending variable +* Refactored boundary and attachment code +* Eliminated SMTP class warnings +* Added SendToQueue method for future queuing support + +Version 1.54 (Wed, Dec 19 2001) +* Add some queuing support code +* Fixed a pesky multi/alt bug +* Messages are no longer forced to have "To" addresses + +Version 1.50 (Thu, Nov 08 2001) +* Fix extra lines when not using SMTP mailer +* Set WordWrap variable to int with a zero default + +Version 1.47 (Tue, Oct 16 2001) +* Fixed Received header code format +* Fixed AltBody order error +* Fixed alternate port warning + +Version 1.45 (Tue, Sep 25 2001) +* Added enhanced SMTP debug support +* Added support for multiple ports on SMTP +* Added Received header for tracing +* Fixed AddStringAttachment encoding +* Fixed possible header name quote bug +* Fixed wordwrap() trim bug +* Couple other small bug fixes + +Version 1.41 (Wed, Aug 22 2001) +* Fixed AltBody bug w/o attachments +* Fixed rfc_date() for certain mail servers + +Version 1.40 (Sun, Aug 12 2001) +* Added multipart/alternative support (AltBody) +* Documentation update +* Fixed bug in Mercury MTA + +Version 1.29 (Fri, Aug 03 2001) +* Added AddStringAttachment() method +* Added SMTP authentication support + +Version 1.28 (Mon, Jul 30 2001) +* Fixed a typo in SMTP class +* Fixed header issue with Imail (win32) SMTP server +* Made fopen() calls for attachments use "rb" to fix win32 error + +Version 1.25 (Mon, Jul 02 2001) +* Added RFC 822 date fix (Patrice) +* Added improved error handling by adding a $ErrorInfo variable +* Removed MailerDebug variable (obsolete with new error handler) + +Version 1.20 (Mon, Jun 25 2001) +* Added quoted-printable encoding (Patrice) +* Set Version as public and removed PrintVersion() +* Changed phpdoc to only display public variables and methods + +Version 1.19 (Thu, Jun 21 2001) +* Fixed MS Mail header bug +* Added fix for Bcc problem with mail(). *Does not work on Win32* + (See PHP bug report: http://www.php.net/bugs.php?id=11616) +* mail() no longer passes a fifth parameter when not needed + +Version 1.15 (Fri, Jun 15 2001) +[Note: these changes contributed by Patrice Fournier] +* Changed all remaining \n to \r\n +* Bcc: header no longer writen to message except +when sent directly to sendmail +* Added a small message to non-MIME compliant mail reader +* Added Sender variable to change the Sender email +used in -f for sendmail/mail and in 'MAIL FROM' for smtp mode +* Changed boundary setting to a place it will be set only once +* Removed transfer encoding for whole message when using multipart +* Message body now uses Encoding in multipart messages +* Can set encoding and type to attachments 7bit, 8bit +and binary attachment are sent as is, base64 are encoded +* Can set Encoding to base64 to send 8 bits body +through 7 bits servers + +Version 1.10 (Tue, Jun 12 2001) +* Fixed win32 mail header bug (printed out headers in message body) + +Version 1.09 (Fri, Jun 08 2001) +* Changed date header to work with Netscape mail programs +* Altered phpdoc documentation + +Version 1.08 (Tue, Jun 05 2001) +* Added enhanced error-checking +* Added phpdoc documentation to source + +Version 1.06 (Fri, Jun 01 2001) +* Added optional name for file attachments + +Version 1.05 (Tue, May 29 2001) +* Code cleanup +* Eliminated sendmail header warning message +* Fixed possible SMTP error + +Version 1.03 (Thu, May 24 2001) +* Fixed problem where qmail sends out duplicate messages + +Version 1.02 (Wed, May 23 2001) +* Added multiple recipient and attachment Clear* methods +* Added Sendmail public variable +* Fixed problem with loading SMTP library multiple times + +Version 0.98 (Tue, May 22 2001) +* Fixed problem with redundant mail hosts sending out multiple messages +* Added additional error handler code +* Added AddCustomHeader() function +* Added support for Microsoft mail client headers (affects priority) +* Fixed small bug with Mailer variable +* Added PrintVersion() function + +Version 0.92 (Tue, May 15 2001) +* Changed file names to class.phpmailer.php and class.smtp.php to match + current PHP class trend. +* Fixed problem where body not being printed when a message is attached +* Several small bug fixes + +Version 0.90 (Tue, April 17 2001) +* Intial public release Added: trunk/ofrenda-blog/html/librerias/phpmailer/LICENSE =================================================================== --- trunk/ofrenda-blog/html/librerias/phpmailer/LICENSE 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/phpmailer/LICENSE 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + Added: trunk/ofrenda-blog/html/librerias/phpmailer/README =================================================================== --- trunk/ofrenda-blog/html/librerias/phpmailer/README 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/phpmailer/README 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,102 @@ +PHPMailer +Full Featured Email Transfer Class for PHP +========================================== + +http://phpmailer.sourceforge.net/ + +This software is licenced under the LGPL. Please read LICENSE for information on the +software availability and distribution. + +Class Features: +- Send emails with multiple TOs, CCs, BCCs and REPLY-TOs +- Redundant SMTP servers +- Multipart/alternative emails for mail clients that do not read HTML email +- Support for 8bit, base64, binary, and quoted-printable encoding +- Uses the same methods as the very popular AspEmail active server (COM) component +- SMTP authentication +- Native language support +- Word wrap, and more! + +Why you might need it: + +Many PHP developers utilize email in their code. The only PHP function +that supports this is the mail() function. However, it does not expose +any of the popular features that many email clients use nowadays like +HTML-based emails and attachments. There are two proprietary +development tools out there that have all the functionality built into +easy to use classes: AspEmail(tm) and AspMail. Both of these +programs are COM components only available on Windows. They are also a +little pricey for smaller projects. + +Since I do Linux development I’ve missed these tools for my PHP coding. +So I built a version myself that implements the same methods (object +calls) that the Windows-based components do. It is open source and the +LGPL license allows you to place the class in your proprietary PHP +projects. + + +Installation: + +Copy class.phpmailer.php into your php.ini include_path. If you are +using the SMTP mailer then place class.smtp.php in your path as well. +In the language directory you will find several files like +phpmailer.lang-en.php. If you look right before the .php extension +that there are two letters. These represent the language type of the +translation file. For instance "en" is the English file and "br" is +the Portuguese file. Chose the file that best fits with your language +and place it in the PHP include path. If your language is English +then you have nothing more to do. If it is a different language then +you must point PHPMailer to the correct translation. To do this, call +the PHPMailer SetLanguage method like so: + +// To load the Portuguese version +$mail->SetLanguage("br", "/optional/path/to/language/directory/"); + +That's it. You should now be ready to use PHPMailer! + + +A Simple Example: + +IsSMTP(); // set mailer to use SMTP +$mail->Host = "smtp1.example.com;smtp2.example.com"; // specify main and backup server +$mail->SMTPAuth = true; // turn on SMTP authentication +$mail->Username = "jswan"; // SMTP username +$mail->Password = "secret"; // SMTP password + +$mail->From = "from@example.com"; +$mail->FromName = "Mailer"; +$mail->AddAddress("josh@example.net", "Josh Adams"); +$mail->AddAddress("ellen@example.com"); // name is optional +$mail->AddReplyTo("info@example.com", "Information"); + +$mail->WordWrap = 50; // set word wrap to 50 characters +$mail->AddAttachment("/var/tmp/file.tar.gz"); // add attachments +$mail->AddAttachment("/tmp/image.jpg", "new.jpg"); // optional name +$mail->IsHTML(true); // set email format to HTML + +$mail->Subject = "Here is the subject"; +$mail->Body = "This is the HTML message body in bold!"; +$mail->AltBody = "This is the body in plain text for non-HTML mail clients"; + +if(!$mail->Send()) +{ + echo "Message could not be sent.

"; + echo "Mailer Error: " . $mail->ErrorInfo; + exit; +} + +echo "Message has been sent"; +?> + +CHANGELOG + +See ChangeLog.txt + +Download: http://sourceforge.net/project/showfiles.php?group_id=26031 + +Brent R. Matzelle Added: trunk/ofrenda-blog/html/librerias/phpmailer/class.phpmailer.php =================================================================== --- trunk/ofrenda-blog/html/librerias/phpmailer/class.phpmailer.php 2006-02-14 00:44:04 UTC (rev 25) +++ trunk/ofrenda-blog/html/librerias/phpmailer/class.phpmailer.php 2006-02-14 06:20:45 UTC (rev 26) @@ -0,0 +1,1499 @@ +ContentType = "text/html"; + else + $this->ContentType = "text/plain"; + } + + /** + * Sets Mailer to send message using SMTP. + * @return void + */ + function IsSMTP() { + $this->Mailer = "smtp"; + } + + /** + * Sets Mailer to send message using PHP mail() function. + * @return void + */ + function IsMail() { + $this->Mailer = "mail"; + } + + /** + * Sets Mailer to send message using the $Sendmail program. + * @return void + */ + function IsSendmail() { + $this->Mailer = "sendmail"; + } + + /** + * Sets Mailer to send message using the qmail MTA. + * @return void + */ + function IsQmail() { + $this->Sendmail = "/var/qmail/bin/sendmail"; + $this->Mailer = "sendmail"; + } + + + ///////////////////////////////////////////////// + // RECIPIENT METHODS + ///////////////////////////////////////////////// + + /** + * Adds a "To" address. + * @param string $address + * @param string $name + * @return void + */ + function AddAddress($address, $name = "") { + $cur = count($this->to); + $this->to[$cur][0] = trim($address); + $this->to[$cur][1] = $name; + } + + /** + * Adds a "Cc" address. Note: this function works + * with the SMTP mailer on win32, not with the "mail" + * mailer. + * @param string $address + * @param string $name + * @return void + */ + function AddCC($address, $name = "") { + $cur = count($this->cc); + $this->cc[$cur][0] = trim($address); + $this->cc[$cur][1] = $name; + } + + /** + * Adds a "Bcc" address. Note: this function works + * with the SMTP mailer on win32, not with the "mail" + * mailer. + * @param string $address + * @param string $name + * @return void + */ + function AddBCC($address, $name = "") { + $cur = count($this->bcc); + $this->bcc[$cur][0] = trim($address); + $this->bcc[$cur][1] = $name; + } + + /** + * Adds a "Reply-to" address. + * @param string $address + * @param string $name + * @return void + */ + function AddReplyTo($address, $name = "") { + $cur = count($this->ReplyTo); + $this->ReplyTo[$cur][0] = trim($address); + $this->ReplyTo[$cur][1] = $name; + } + + + ///////////////////////////////////////////////// + // MAIL SENDING METHODS + ///////////////////////////////////////////////// + + /** + * Creates message and assigns Mailer. If the message is + * not sent successfully then it returns false. Use the ErrorInfo + * variable to view description of the error. + * @return bool + */ + function Send() { + $header = ""; + $body = ""; + $result = true; + + if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) + { + $this->SetError($this->Lang("provide_address")); + return false; + } + + // Set whether the message is multipart/alternative + if(!empty($this->AltBody)) + $this->ContentType = "multipart/alternative"; + + $this->error_count = 0; // reset errors + $this->SetMessageType(); + $header .= $this->CreateHeader(); + $body = $this->CreateBody(); + + if($body == "") { return false; } + + // Choose the mailer + switch($this->Mailer) + { + case "sendmail": + $result = $this->SendmailSend($header, $body); + break; + case "mail": + $result = $this->MailSend($header, $body); + break; + case "smtp": + $result = $this->SmtpSend($header, $body); + break; + default: + $this->SetError($this->Mailer . $this->Lang("mailer_not_supported")); + $result = false; + break; + } + + return $result; + } + + /** + * Sends mail using the $Sendmail program. + * @access private + * @return bool + */ + function SendmailSend($header, $body) { + if ($this->Sender != "") + $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, $this->Sender); + else + $sendmail = sprintf("%s -oi -t", $this->Sendmail); + + if(!@$mail = popen($sendmail, "w")) + { + $this->SetError($this->Lang("execute") . $this->Sendmail); + return false; + } + + fputs($mail, $header); + fputs($mail, $body); + + $result = pclose($mail) >> 8 & 0xFF; + if($result != 0) + { + $this->SetError($this->Lang("execute") . $this->Sendmail); + return false; + } + + return true; + } + + /** + * Sends mail using the PHP mail() function. + * @access private + * @return bool + */ + function MailSend($header, $body) { + $to = ""; + for($i = 0; $i < count($this->to); $i++) + { + if($i != 0) { $to .= ", "; } + $to .= $this->to[$i][0]; + } + + if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1) + { + $old_from = ini_get("sendmail_from"); + ini_set("sendmail_from", $this->Sender); + $params = sprintf("-oi -f %s", $this->Sender); + $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, + $header, $params); + } + else + $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header); + + if (isset($old_from)) + ini_set("sendmail_from", $old_from); + + if(!$rt) + { + $this->SetError($this->Lang("instantiate")); + return false; + } + + return true; + } + + /** + * Sends mail via SMTP using PhpSMTP (Author: + * Chris Ryan). Returns bool. Returns false if there is a + * bad MAIL FROM, RCPT, or DATA input. + * @access private + * @return bool + */ + function SmtpSend($header, $body) { + include_once($this->PluginDir . "class.smtp.php"); + $error = ""; + $bad_rcpt = array(); + + if(!$this->SmtpConnect()) + return false; + + $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender; + if(!$this->smtp->Mail($smtp_from)) + { + $error = $this->Lang("from_failed") . $smtp_from; + $this->SetError($error); + $this->smtp->Reset(); + return false; + } + + // Attempt to send attach all recipients + for($i = 0; $i < count($this->to); $i++) + { + if(!$this->smtp->Recipient($this->to[$i][0])) + $bad_rcpt[] = $this->to[$i][0]; + } + for($i = 0; $i < count($this->cc); $i++) + { + if(!$this->smtp->Recipient($this->cc[$i][0])) + $bad_rcpt[] = $this->cc[$i][0]; + } + for($i = 0; $i < count($this->bcc); $i++) + { + if(!$this->smtp->Recipient($this->bcc[$i][0])) + $bad_rcpt[] = $this->bcc[$i][0]; + } + + if(count($bad_rcpt) > 0) // Create error message + { + for($i = 0; $i < count($bad_rcpt); $i++) + { + if($i != 0) { $error .= ", "; } + $error .= $bad_rcpt[$i]; + } + $error = $this->Lang("recipients_failed") . $error; + $this->SetError($error); + $this->smtp->Reset(); + return false; + } + + if(!$this->smtp->Data($header . $body)) + { + $this->SetError($this->Lang("data_not_accepted")); + $this->smtp->Reset(); + return false; + } + if($this->SMTPKeepAlive == true) + $this->smtp->Reset(); + else + $this->SmtpClose(); + + return true; + } + + /** + * Initiates a connection to an SMTP server. Returns false if the + * operation failed. + * @access private + * @return bool + */ + function SmtpConnect() { + if($this->smtp == NULL) { $this->smtp = new SMTP(); } + + $this->smtp->do_debug = $this->SMTPDebug; + $hosts = explode(";", $this->Host); + $index = 0; + $connection = ($this->smtp->Connected()); + + // Retry while there is no connection + while($index < count($hosts) && $connection == false) + { + if(strstr($hosts[$index], ":")) + list($host, $port) = explode(":", $hosts[$index]); + else + { + $host = $hosts[$index]; + $port = $this->Port; + } + + if($this->smtp->Connect($host, $port, $this->Timeout)) + { + if ($this->Helo != '') + $this->smtp->Hello($this->Helo); + else + $this->smtp->Hello($this->ServerHostname()); + + if($this->SMTPAuth) + { + if(!$this->smtp->Authenticate($this->Username, + $this->Password)) + { + $this->SetError($this->Lang("authenticate")); + $this->smtp->Reset(); + $connection = false; + } + } + $connection = true; + } + $index++; + } + if(!$connection) + $this->SetError($this->Lang("connect_host")); + + return $connection; + } + + /** + * Closes the active SMTP session if one exists. + * @return void + */ + function SmtpClose() { + if($this->smtp != NULL) + { + if($this->smtp->Connected()) + { + $this->smtp->Quit(); + $this->smtp->Close(); + } + } + } + + /** + * Sets the language for all class error messages. Returns false + * if it cannot load the language file. The default language type + * is English. + * @param string $lang_type Type of language (e.g. Portuguese: "br") + * @param string $lang_path Path to the language file directory + * @access public + * @return bool + */ + function SetLanguage($lang_type, $lang_path = "language/") { + if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) + include($lang_path.'phpmailer.lang-'.$lang_type.'.php'); + else if(file_exists($lang_path.'phpmailer.lang-en.php')) + include($lang_path.'phpmailer.lang-en.php'); + else + { + $this->SetError("Could not load language file"); + return false; + } + $this->language = $PHPMAILER_LANG; + + return true; + } + + ///////////////////////////////////////////////// + // MESSAGE CREATION METHODS + ///////////////////////////////////////////////// + + /** + * Creates recipient headers. + * @access private + * @return string + */ + function AddrAppend($type, $addr) { + $addr_str = $type . ": "; + $addr_str .= $this->AddrFormat($addr[0]); + if(count($addr) > 1) + { + for($i = 1; $i < count($addr); $i++) + $addr_str .= ", " . $this->AddrFormat($addr[$i]); + } + $addr_str .= $this->LE; + + return $addr_str; + } + + /** + * Formats an address correctly. + * @access private + * @return string + */ + function AddrFormat($addr) { + if(empty($addr[1])) + $formatted = $addr[0]; + else + { + $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" . + $addr[0] . ">"; + } + + return $formatted; + } + + /** + * Wraps message for use with mailers that do not + * automatically perform wrapping and for quoted-printable. + * Original written by philippe. + * @access private + * @return string + */ + function WrapText($message, $length, $qp_mode = false) { + $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; + + $message = $this->FixEOL($message); + if (substr($message, -1) == $this->LE) + $message = substr($message, 0, -1); + + $line = explode($this->LE, $message); + $message = ""; + for ($i=0 ;$i < count($line); $i++) + { + $line_part = explode(" ", $line[$i]); + $buf = ""; + for ($e = 0; $e $length)) + { + $space_left = $length - strlen($buf) - 1; + if ($e != 0) + { + if ($space_left > 20) + { + $len = $space_left; + if (substr($word, $len - 1, 1) == "=") + $len--; + elseif (substr($word, $len - 2, 1) == "=") + $len -= 2; + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= " " . $part; + $message .= $buf . sprintf("=%s", $this->LE); + } + else + { + $message .= $buf . $soft_break; + } + $buf = ""; + } + while (strlen($word) > 0) + { + $len = $length; + if (substr($word, $len - 1, 1) == "=") + $len--; + elseif (substr($word, $len - 2, 1) == "=") + $len -= 2; + $part = substr($word, 0, $len); + $word = substr($word, $len); + + if (strlen($word) > 0) + $message .= $part . sprintf("=%s", $this->LE); + else + $buf = $part; + } + } + else + { + $buf_o = $buf; + $buf .= ($e == 0) ? $word : (" " . $word); + + if (strlen($buf) > $length and $buf_o != "") + { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + } + $message .= $buf . $this->LE; + } + + return $message; + } + + /** + * Set the body wrapping. + * @access private + * @return void + */ + function SetWordWrap() { + if($this->WordWrap < 1) + return; + + switch($this->message_type) + { + case "alt": + // fall through + case "alt_attachments": + $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->WrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assembles message header. + * @access private + * @return string + */ + function CreateHeader() { + $result = ""; + + // Set the boundaries + $uniq_id = md5(uniqid(time())); + $this->boundary[1] = "b1_" . $uniq_id; + $this->boundary[2] = "b2_" . $uniq_id; + + $result .= $this->HeaderLine("Date", $this->RFCDate()); + if($this->Sender == "") + $result .= $this->HeaderLine("Return-Path", trim($this->From)); + else + $result .= $this->HeaderLine("Return-Path", trim($this->Sender)); + + // To be created automatically by mail() + if($this->Mailer != "mail") + { + if(count($this->to) > 0) + $result .= $this->AddrAppend("To", $this->to); + else if (count($this->cc) == 0) + $result .= $this->HeaderLine("To", "undisclosed-recipients:;"); + if(count($this->cc) > 0) + $result .= $this->AddrAppend("Cc", $this->cc); + } + + $from = array(); + $from[0][0] = trim($this->From); + $from[0][1] = $this->FromName; + $result .= $this->AddrAppend("From", $from); + + // sendmail and mail() extract Bcc from the header before sending + if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0)) + $result .= $this->AddrAppend("Bcc", $this->bcc); + + if(count($this->ReplyTo) > 0) + $result .= $this->AddrAppend("Reply-to", $this->ReplyTo); + + // mail() sets the subject itself + if($this->Mailer != "mail") + $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject))); + + $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); + $result .= $this->HeaderLine("X-Priority", $this->Priority); + $result .= $this->HeaderLine("X-Mailer", "PHPMailer [version " . $this->Version . "]"); + + if($this->ConfirmReadingTo != "") + { + $result .= $this->HeaderLine("Disposition-Notification-To", + "<" . trim($this->ConfirmReadingTo) . ">"); + } + + // Add custom headers + for($index = 0; $index < count($this->CustomHeader); $index++) + { + $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), + $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); + } + $result .= $this->HeaderLine("MIME-Version", "1.0"); + + switch($this->message_type) + { + case "plain": + $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding); + $result .= sprintf("Content-Type: %s; charset=\"%s\"", + $this->ContentType, $this->CharSet); + break; + case "attachments": + // fall through + case "alt_attachments": + if($this->InlineImageExists()) + { + $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", + "multipart/related", $this->LE, $this->LE, + $this->boundary[1], $this->LE); + } + else + { + $result .= $this->HeaderLine("Content-Type", "multipart/mixed;"); + $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); + } + break; + case "alt": + $result .= $this->HeaderLine("Content-Type", "multipart/alternative;"); + $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + } + + if($this->Mailer != "mail") + $result .= $this->LE.$this->LE; + + return $result; + } + + /** + * Assembles the message body. Returns an empty string on failure. + * @access private + * @return string + */ + function CreateBody() { + $result = ""; + + $this->SetWordWrap(); + + switch($this->message_type) + { + case "alt": + $result .= $this->GetBoundary($this->boundary[1], "", + "text/plain", ""); + $result .= $this->EncodeString($this->AltBody, $this->Encoding); + $result .= $this->LE.$this->LE; + $result .= $this->GetBoundary($this->boundary[1], "", + "text/html", ""); + + $result .= $this->EncodeString($this->Body, $this->Encoding); + $result .= $this->LE.$this->LE; + + $result .= $this->EndBoundary($this->boundary[1]); + break; + case "plain": + $result .= $this->EncodeString($this->Body, $this->Encoding); + break; + case "attachments": + $result .= $this->GetBoundary($this->boundary[1], "", "", ""); + $result .= $this->EncodeString($this->Body, $this->Encoding); + $result .= $this->LE; + + $result .= $this->AttachAll(); + break; + case "alt_attachments": + $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); + $result .= sprintf("Content-Type: %s;%s" . + "\tboundary=\"%s\"%s", + "multipart/alternative", $this->LE, + $this->boundary[2], $this->LE.$this->LE); + + // Create text body + $result .= $this->GetBoundary($this->boundary[2], "", + "text/plain", "") . $this->LE; + + $result .= $this->EncodeString($this->AltBody, $this->Encoding); + $result .= $this->LE.$this->LE; + + // Create the HTML body + $result .= $this->GetBoundary($this->boundary[2], "", + "text/html", "") . $this->LE; + + $result .= $this->EncodeString($this->Body, $this->Encoding); + $result .= $this->LE.$this->LE; + + $result .= $this->EndBoundary($this->boundary[2]); + + $result .= $this->AttachAll(); + break; + } + if($this->IsError()) + $result = ""; + + return $result; + } + + /** + * Returns the start of a message boundary. + * @access private + */ + function GetBoundary($boundary, $charSet, $contentType, $encoding) { + $result = ""; + if($charSet == "") { $charSet = $this->CharSet; } + if($contentType == "") { $contentType = $this->ContentType; } + if($encoding == "") { $encoding = $this->Encoding; } + + $result .= $this->TextLine("--" . $boundary); + $result .= sprintf("Content-Type: %s; charset = \"%s\"", + $contentType, $charSet); + $result .= $this->LE; + $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding); + $result .= $this->LE; + + return $result; + } + + /** + * Returns the end of a message boundary. + * @access private + */ + function EndBoundary($boundary) { + return $this->LE . "--" . $boundary . "--" . $this->LE; + } + + /** + * Sets the message type. + * @access private + * @return void + */ + function SetMessageType() { + if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) + $this->message_type = "plain"; + else + { + if(count($this->attachment) > 0) + $this->message_type = "attachments"; + if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) + $this->message_type = "alt"; + if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) + $this->message_type = "alt_attachments"; + } + } + + /** + * Returns a formatted header line. + * @access private + * @return string + */ + function HeaderLine($name, $value) { + return $name . ": " . $value . $this->LE; + } + + /** + * Returns a formatted mail line. + * @access private + * @return string + */ + function TextLine($value) { + return $value . $this->LE; + } + + ///////////////////////////////////////////////// + // ATTACHMENT METHODS + ///////////////////////////////////////////////// + + /** + * Adds an attachment from a path on the filesystem. + * Returns false if the file could not be found + * or accessed. + * @param string $path Path to the attachment. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return bool + */ + function AddAttachment($path, $name = "", $encoding = "base64", + $type = "application/octet-stream") { + if(!@is_file($path)) + { + $this->SetError($this->Lang("file_access") . $path); + return false; + } + + $filename = basename($path); + if($name == "") + $name = $filename; + + $cur = count($this->attachment); + $this->attachment[$cur][0] = $path; + $this->attachment[$cur][1] = $filename; + $this->attachment[$cur][2] = $name; + $this->attachment[$cur][3] = $encoding; + $this->attachment[$cur][4] = $type; + $this->attachment[$cur][5] = false; // isStringAttachment + $this->attachment[$cur][6] = "attachment"; + $this->attachment[$cur][7] = 0; + + return true; + } + + /** + * Attaches all fs, string, and binary attachments to the message. + * Returns an empty string on failure. + * @access private + * @return string + */ + function AttachAll() { + // Return text of body + $mime = array(); + + // Add all attachments + for($i = 0; $i < count($this->attachment); $i++) + { + // Check for string attachment + $bString = $this->attachment[$i][5]; + if ($bString) + $string = $this->attachment[$i][0]; + else + $path = $this->attachment[$i][0]; + + $filename = $this->attachment[$i][1]; + $name = $this->attachment[$i][2]; + $encoding = $this->attachment[$i][3]; + $type = $this->attachment[$i][4]; + $disposition = $this->attachment[$i][6]; + $cid = $this->attachment[$i][7]; + + $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); + $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE); + $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); + + if($disposition == "inline") + $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); + + $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", + $disposition, $name, $this->LE.$this->LE); + + // Encode as string attachment + if($bString) + { + $mime[] = $this->EncodeString($string, $encoding); + if($this->IsError()) { return ""; } + $mime[] = $this->LE.$this->LE; + } + else + { + $mime[] = $this->EncodeFile($path, $encoding); + if($this->IsError()) { return ""; } + $mime[] = $this->LE.$this->LE; + } + } + + $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); + + return join("", $mime); + } + + /** + * Encodes attachment in requested format. Returns an + * empty string on failure. + * @access private + * @return string + */ + function EncodeFile ($path, $encoding = "base64") { + if(!@$fd = fopen($path, "rb")) + { + $this->SetError($this->Lang("file_open") . $path); + return ""; + } + $magic_quotes = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $file_buffer = fread($fd, filesize($path)); + $file_buffer = $this->EncodeString($file_buffer, $encoding); + fclose($fd); + set_magic_quotes_runtime($magic_quotes); + + return $file_buffer; + } + + /** + * Encodes string to requested format. Returns an + * empty string on failure. + * @access private + * @return string + */ + function EncodeString ($str, $encoding = "base64") { + $encoded = ""; + switch(strtolower($encoding)) { + case "base64": + // chunk_split is found in PHP >= 3.0.6 + $encoded = chunk_split(base64_encode($str), 76, $this->LE); + break; + case "7bit": + case "8bit": + $encoded = $this->FixEOL($str); + if (substr($encoded, -(strlen($this->LE))) != $this->LE) + $encoded .= $this->LE; + break; + case "binary": + $encoded = $str; + break; + case "quoted-printable": + $encoded = $this->EncodeQP($str); + break; + default: + $this->SetError($this->Lang("encoding") . $encoding); + break; + } + return $encoded; + } + + /** + * Encode a header string to best of Q, B, quoted or none. + * @access private + * @return string + */ + function EncodeHeader ($str, $position = 'text') { + $x = 0; + + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + // Can't use addslashes as we don't know what value has magic_quotes_sybase. + $encoded = addcslashes($str, "\0..\37\177\\\""); + + if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) + return ($encoded); + else + return ("\"$encoded\""); + } + $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + case 'comment': + $x = preg_match_all('/[()"]/', $str, $matches); + // Fall-through + case 'text': + default: + $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + if ($x == 0) + return ($str); + + $maxlen = 75 - 7 - strlen($this->CharSet); + // Try to select the encoding which should produce the shortest output + if (strlen($str)/3 < $x) { + $encoding = 'B'; + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } else { + $encoding = 'Q'; + $encoded = $this->EncodeQ($str, $position); + $encoded = $this->WrapText($encoded, $maxlen, true); + $encoded = str_replace("=".$this->LE, "\n", trim($encoded)); + } + + $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); + $encoded = trim(str_replace("\n", $this->LE, $encoded)); + + return $encoded; + } + + /** + * Encode string to quoted-printable. + * @access private + * @return string + */ + function EncodeQP ($str) { + $encoded = $this->FixEOL($str); + if (substr($encoded, -(strlen($this->LE))) != $this->LE) + $encoded .= $this->LE; + + // Replace every high ascii, control and = characters + $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e', + "'='.sprintf('%02X', ord('\\1'))", $encoded); + // Replace every spaces and tabs when it's the last character on a line + $encoded = preg_replace("/([\011\040])".$this->LE."/e", + "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded); + + // Maximum line length of 76 characters before CRLF (74 + space + '=') + $encoded = $this->WrapText($encoded, 74, true); + + return $encoded; + } + + /** + * Encode string to q encoding. + * @access private + * @return string + */ + function EncodeQ ($str, $position = "text") { + // There should not be any EOL in the string + $encoded = preg_replace("[\r\n]", "", $str); + + switch (strtolower($position)) { + case "phrase": + $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); + break; + case "comment": + $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); + case "text": + default: + // Replace every high ascii, control =, ? and _ characters + $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', + "'='.sprintf('%02X', ord('\\1'))", $encoded); + break; + } + + // Replace every spaces to _ (more readable than =20) + $encoded = str_replace(" ", "_", $encoded); + + return $encoded; + } + + /** + * Adds a string or binary attachment (non-filesystem) to the list. + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * @param string $string String attachment data. + * @param string $filename Name of the attachment. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return void + */ + function AddStringAttachment($string, $filename, $encoding = "base64", + $type = "application/octet-stream") { + // Append to $attachment array + $cur = count($this->attachment); + $this->attachment[$cur][0] = $string; + $this->attachment[$cur][1] = $filename; + $this->attachment[$cur][2] = $filename; + $this->attachment[$cur][3] = $encoding; + $this->attachment[$cur][4] = $type; + $this->attachment[$cur][5] = true; // isString + $this->attachment[$cur][6] = "attachment"; + $this->attachment[$cur][7] = 0; + } + + /** + * Adds an embedded attachment. This can include images, sounds, and + * just about any other document. Make sure to set the $type to an + * image type. For JPEG images use "image/jpeg" and for GIF images + * use "image/gif". + * @param string $path Path to the attachment. + * @param string $cid Content ID of the attachment. Use this to identify + * the Id for accessing the image in an HTML form. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @return bool + */ + function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64", + $type = "application/octet-stream") { + + if(!@is_file($path)) + { + $this->SetError($this->Lang("file_access") . $path); + return false; + } + + $filename = basename($path); + if($name == "") + $name = $filename; + + // Append to $attachment array + $cur = count($this->attachment); + $this->attachment[$cur][0] = $path; + $this->attachment[$cur][1] = $filename; + $this->attachment[$cur][2] = $name; + $this->attachment[$cur][3] = $encoding; + $this->attachment[$cur][4] = $type; + $this->attachment[$cur][5] = false; // isStringAttachment + $this->attachment[$cur][6] = "inline"; + $this->attachment[$cur][7] = $cid; + + return true; + } + + /** + * Returns true if an inline attachment is present. + * @access private + * @return bool + */ + function InlineImageExists() { + $result = false; + for($i = 0; $i < count($this->attachment); $i++) + { + if($this->attachment[$i][6] == "inline") + { + $result = true; + break; + } + } + + return $result; + } + + ///////////////////////////////////////////////// + // MESSAGE RESET METHODS + ///////////////////////////////////////////////// + + /** + * Clears all recipients assigned in the TO array. Returns void. + * @return void + */ + fun