Selaa lähdekoodia

first commit

import/raw
memespring 18 vuotta sitten
vanhempi
commit
8b56449638
100 muutettua tiedostoa jossa 36144 lisäystä ja 0 poistoa
  1. +35
    -0
      trunk/data/%%0A^0A3^0A3EFF25%%faq.tpl.php
  2. +27
    -0
      trunk/data/%%0E^0E4^0E407559%%footer.tpl.php
  3. +26
    -0
      trunk/data/%%0F^0F1^0F1856BC%%unsubscribed.tpl.php
  4. +18
    -0
      trunk/data/%%3A^3A4^3A4E0A75%%checkmail.tpl.php
  5. +65
    -0
      trunk/data/%%45^45E^45E480CD%%index.tpl.php
  6. +41
    -0
      trunk/data/%%6D^6DB^6DB28CFA%%about.tpl.php
  7. +24
    -0
      trunk/data/%%6E^6E1^6E190D42%%preview.tpl.php
  8. +32
    -0
      trunk/data/%%80^80A^80A14535%%confirmed.tpl.php
  9. +15
    -0
      trunk/data/%%A4^A42^A42CC6E6%%confirm_email_text.tpl.php
  10. +35
    -0
      trunk/data/%%AD^AD7^AD71B708%%rss.tpl.php
  11. +42
    -0
      trunk/data/%%D2^D26^D26D8BFE%%xml.tpl.php
  12. +33
    -0
      trunk/data/%%F7^F75^F752BDC0%%getinvolved.tpl.php
  13. +41
    -0
      trunk/data/%%F7^F7F^F7F34188%%header.tpl.php
  14. +5
    -0
      trunk/docs/.htaccess
  15. +4
    -0
      trunk/docs/.htaccess.haggis
  16. +4
    -0
      trunk/docs/.htaccess.live
  17. +57
    -0
      trunk/docs/about.php
  18. +79
    -0
      trunk/docs/api.php
  19. +34
    -0
      trunk/docs/checkmail.php
  20. +76
    -0
      trunk/docs/confirmed.php
  21. +33
    -0
      trunk/docs/cron.php
  22. +81
    -0
      trunk/docs/css/main.css
  23. +59
    -0
      trunk/docs/css/memespring.css
  24. +34
    -0
      trunk/docs/faq.php
  25. BIN
      trunk/docs/favicon.ico
  26. +35
    -0
      trunk/docs/getinvolved.php
  27. BIN
      trunk/docs/images/background.png
  28. BIN
      trunk/docs/images/logo.png
  29. +1388
    -0
      trunk/docs/include/PEAR/DB.php
  30. +2157
    -0
      trunk/docs/include/PEAR/DB/common.php
  31. +1034
    -0
      trunk/docs/include/PEAR/DB/mysql.php
  32. +1097
    -0
      trunk/docs/include/PEAR/DB/pgsql.php
  33. +504
    -0
      trunk/docs/include/PEAR/DB/storage.php
  34. +1395
    -0
      trunk/docs/include/PEAR/HTTP/Request.php
  35. +668
    -0
      trunk/docs/include/PEAR/Log.php
  36. +200
    -0
      trunk/docs/include/PEAR/Log/composite.php
  37. +202
    -0
      trunk/docs/include/PEAR/Log/console.php
  38. +230
    -0
      trunk/docs/include/PEAR/Log/daemon.php
  39. +117
    -0
      trunk/docs/include/PEAR/Log/display.php
  40. +103
    -0
      trunk/docs/include/PEAR/Log/error_log.php
  41. +324
    -0
      trunk/docs/include/PEAR/Log/file.php
  42. +220
    -0
      trunk/docs/include/PEAR/Log/mail.php
  43. +170
    -0
      trunk/docs/include/PEAR/Log/mcal.php
  44. +358
    -0
      trunk/docs/include/PEAR/Log/mdb2.php
  45. +67
    -0
      trunk/docs/include/PEAR/Log/null.php
  46. +125
    -0
      trunk/docs/include/PEAR/Log/observer.php
  47. +287
    -0
      trunk/docs/include/PEAR/Log/sql.php
  48. +225
    -0
      trunk/docs/include/PEAR/Log/sqlite.php
  49. +160
    -0
      trunk/docs/include/PEAR/Log/syslog.php
  50. +255
    -0
      trunk/docs/include/PEAR/Log/win.php
  51. +4211
    -0
      trunk/docs/include/PEAR/MDB2.php
  52. +183
    -0
      trunk/docs/include/PEAR/MDB2/Date.php
  53. BIN
      trunk/docs/include/PEAR/MDB2/Driver/Datatype/.Common.php.swp
  54. +1672
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Datatype/Common.php
  55. +426
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Datatype/mysql.php
  56. +210
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Function/Common.php
  57. +104
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Function/mysql.php
  58. +805
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Manager/Common.php
  59. +915
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Manager/mysql.php
  60. +58
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Native/Common.php
  61. +60
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Native/mysql.php
  62. +423
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Reverse/Common.php
  63. +369
    -0
      trunk/docs/include/PEAR/MDB2/Driver/Reverse/mysql.php
  64. +1416
    -0
      trunk/docs/include/PEAR/MDB2/Driver/mysql.php
  65. +704
    -0
      trunk/docs/include/PEAR/MDB2/Extended.php
  66. +259
    -0
      trunk/docs/include/PEAR/MDB2/Iterator.php
  67. +245
    -0
      trunk/docs/include/PEAR/MDB2/LOB.php
  68. +713
    -0
      trunk/docs/include/PEAR/Mail/mime.php
  69. +837
    -0
      trunk/docs/include/PEAR/Mail/mimeDecode.php
  70. +351
    -0
      trunk/docs/include/PEAR/Mail/mimePart.php
  71. +19
    -0
      trunk/docs/include/PEAR/Mail/xmail.dtd
  72. +70
    -0
      trunk/docs/include/PEAR/Mail/xmail.xsl
  73. +629
    -0
      trunk/docs/include/PEAR/Net/DIME.php
  74. +554
    -0
      trunk/docs/include/PEAR/Net/Socket.php
  75. +410
    -0
      trunk/docs/include/PEAR/Net/URL.php
  76. +1095
    -0
      trunk/docs/include/PEAR/PEAR.php
  77. +146
    -0
      trunk/docs/include/application.php
  78. +43
    -0
      trunk/docs/include/config.php
  79. +43
    -0
      trunk/docs/include/config.php.live
  80. +43
    -0
      trunk/docs/include/config.php.svn
  81. +776
    -0
      trunk/docs/include/phpcoord.php
  82. +413
    -0
      trunk/docs/include/scraper_support.php
  83. +389
    -0
      trunk/docs/include/smarty/Config_File.class.php
  84. +1944
    -0
      trunk/docs/include/smarty/Smarty.class.php
  85. +2320
    -0
      trunk/docs/include/smarty/Smarty_Compiler.class.php
  86. +157
    -0
      trunk/docs/include/smarty/debug.tpl
  87. +67
    -0
      trunk/docs/include/smarty/internals/core.assemble_plugin_filepath.php
  88. +43
    -0
      trunk/docs/include/smarty/internals/core.assign_smarty_interface.php
  89. +79
    -0
      trunk/docs/include/smarty/internals/core.create_dir_structure.php
  90. +61
    -0
      trunk/docs/include/smarty/internals/core.display_debug_console.php
  91. +44
    -0
      trunk/docs/include/smarty/internals/core.get_include_path.php
  92. +23
    -0
      trunk/docs/include/smarty/internals/core.get_microtime.php
  93. +80
    -0
      trunk/docs/include/smarty/internals/core.get_php_resource.php
  94. +59
    -0
      trunk/docs/include/smarty/internals/core.is_secure.php
  95. +47
    -0
      trunk/docs/include/smarty/internals/core.is_trusted.php
  96. +125
    -0
      trunk/docs/include/smarty/internals/core.load_plugins.php
  97. +74
    -0
      trunk/docs/include/smarty/internals/core.load_resource_plugin.php
  98. +71
    -0
      trunk/docs/include/smarty/internals/core.process_cached_inserts.php
  99. +37
    -0
      trunk/docs/include/smarty/internals/core.process_compiled_include.php
  100. +101
    -0
      trunk/docs/include/smarty/internals/core.read_cache_file.php

+ 35
- 0
trunk/data/%%0A^0A3^0A3EFF25%%faq.tpl.php Näytä tiedosto

@@ -0,0 +1,35 @@
<?php /* Smarty version 2.6.16, created on 2007-01-18 21:20:37
compiled from faq.tpl */ ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

<dl class="faq">
<dt>What does PlanningAlerts.com do?</dt>
<dd>
It sends you emails of any planning applications we find based on the postcode you give us when you sign up.
</dd>
<dt>Where does the data come from?</dt>
<dd>
We search as many local authority websites as we can find and forward the data on to you.
</dd>
<dt>How can I stop receiving alerts?</dt>
<dd>
At the bottom of each email you receive there is a link to unsubscribe from that alert. Just click on it and we'll delete your alert.
</dd>
<dt>Do you cover the whole country?</dt>
<dd>
No, but we are working on it. There is a list of the local authorities we currently cover <a href="about.php#authorities">here</a>. Not every local authority publishes their planning data online so some places will always be missing. If your local authority is missing, you could always <a href="about.php#contact">help out by writing a screen scraper to search their website.</a>
</dd>
<dt>Can I help?</dt>
<dd>
Yes please! To be able to cover the whole country we need help in writing screen scrapers to search the websites of every local authority in the country. If you'd like to write one for your local council <a href="about.php#contact">get in touch</a>.
</dd>
</dl>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 27
- 0
trunk/data/%%0E^0E4^0E407559%%footer.tpl.php Näytä tiedosto

@@ -0,0 +1,27 @@
<?php /* Smarty version 2.6.16, created on 2007-03-17 15:57:52
compiled from footer.tpl */ ?>
</div>
<div id="divFooter">
<ul class="inline">
<li><a href="/">Home</a></li>
<li><a href="about.php">About</a></li>
<li><a href="about.php#contact">Contact</a></li>
</ul>
</div>
</div>
<?php if ($this->_tpl_vars['onloadscript'] != "" || $this->_tpl_vars['set_focus_control'] != ""): ?>
<script type="text/javascript" defer="defer">
<?php if ($this->_tpl_vars['set_focus_control'] != ""): ?>setFocus('<?php echo $this->_tpl_vars['set_focus_control']; ?>
');<?php endif; ?>
<?php if ($this->_tpl_vars['onloadscript'] != ""): ?> <?php echo $this->_tpl_vars['onloadscript']; ?>
; <?php endif; ?>
</script>
<?php endif; ?>
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-321882-8";
urchinTracker();
</script>
</body>
</html>

+ 26
- 0
trunk/data/%%0F^0F1^0F1856BC%%unsubscribed.tpl.php Näytä tiedosto

@@ -0,0 +1,26 @@
<?php /* Smarty version 2.6.16, created on 2006-12-28 14:35:03
compiled from unsubscribed.tpl */ ?>
<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
smarty_core_load_plugins(array('plugins' => array(array('modifier', 'upper', 'unsubscribed.tpl', 5, false),)), $this); ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>
<div class="attention">
<h3>You have been unsubscribed</h3>
<p>
You will no longer receive email alerts for any planning applications we find near <strong><?php echo ((is_array($_tmp=$this->_tpl_vars['postcode'])) ? $this->_run_mod_handler('upper', true, $_tmp) : smarty_modifier_upper($_tmp)); ?>
</strong> (within approximately <?php echo $this->_tpl_vars['alert_area_size']; ?>
m).
</p>
<p>
If you have unsubscribed because you were getting too many emails, you could always create a new alert for a smaller area?
</p>
</div>

<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 18
- 0
trunk/data/%%3A^3A4^3A4E0A75%%checkmail.tpl.php Näytä tiedosto

@@ -0,0 +1,18 @@
<?php /* Smarty version 2.6.16, created on 2007-01-07 11:04:37
compiled from checkmail.tpl */ ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>
<div class="attention">
<h3>Now check your email</h3>
<p>
We have sent you an email to confirm your alerts, <span class="highlight">click on the link in the email to start receiving planning alerts</span>. If you don't get an email in the next few minutes, try checking your spam filter.
</p>
</div>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 65
- 0
trunk/data/%%45^45E^45E480CD%%index.tpl.php Näytä tiedosto

@@ -0,0 +1,65 @@
<?php /* Smarty version 2.6.16, created on 2007-03-17 15:24:25
compiled from index.tpl */ ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>
<form action="<?php echo $this->_tpl_vars['form_action']; ?>
" method="post">
<fieldset>
<input type="hidden" name="_is_postback" value="1" />
</fieldset>
<p id="pBeta"><span>This site is in Beta (test) mode, so local authorities near you may not be included in alerts.</span></p>
<ul id="ulSignup" class="form nobullets">
<li id="liEmail">
<label for="txtEmail"><span class="number">1</span> Enter your email address</label>
<input type="text" class="textbox <?php if ($this->_tpl_vars['email_warn'] == true): ?>error<?php endif; ?>" id="txtEmail" name="txtEmail" value="<?php echo $this->_tpl_vars['email']; ?>
" />
</li>
<li id="liPostcode">
<label for="txtPostcode"><span class="number">2</span> Enter a postcode</label>
<input type="text" class="textbox <?php if ($this->_tpl_vars['postcode_warn'] == true): ?>error<?php endif; ?>" id="txtPostcode" name="txtPostcode" value="<?php echo $this->_tpl_vars['postcode']; ?>
" />
<small>e.g. SW9 8JX</small>
</li>
<li id="liAlertArea">
<p id="pAlertArea"><span class="number">3</span> Choose what size area would you like to receive alerts for</p>
<fieldset>
<ul id="ulAlertArea" class="form nobullets">
<li>
<input type="radio" id="radAlertAreaSize_street" name="radAlertAreaSize" value="s" <?php if ($this->_tpl_vars['alert_area_size'] == s): ?>checked="checked"<?php endif; ?> />
<label for="radAlertAreaSize_street">My street (approximately <?php echo $this->_tpl_vars['small_zone_size']; ?>
m)</label> <small><a href="javascript:previewMap('s');">view on a map (new window)</a></small>
</li>
<li>
<input type="radio" id="radAlertAreaSize_neihgbourhood" name="radAlertAreaSize" value="m" <?php if ($this->_tpl_vars['alert_area_size'] == m): ?>checked="checked"<?php endif; ?> />
<label for="radAlertAreaSize_neihgbourhood">My neighbourhood (approximately <?php echo $this->_tpl_vars['medium_zone_size']; ?>
m)</label> <small><a href="javascript:previewMap('m');">view on a map (new window)</a></small>
</li>
<li>
<input type="radio" id="radAlertAreaSize_town" name="radAlertAreaSize" value="l" <?php if ($this->_tpl_vars['alert_area_size'] == l): ?>checked="checked"<?php endif; ?> />
<label for="radAlertAreaSize_town">Wider area (approximately <?php echo $this->_tpl_vars['large_zone_size']; ?>
m)</label> <small><a href="javascript:previewMap('l');">view on a map (new window)</a></small>
</li>
<li>
<noscript><fieldset>Note: viewing the alert area on a map requires javascript</fieldset></noscript>
</li>
</ul>
</fieldset>
</li>
<li id="liSignup"><input type="submit" class="button" value="Create alert >>" /></li>
</ul>
</form>
<div id="divSiteUpdates">
<h4>Recent site updates</h4>
<ul class="nobullets">
<li><em>December 2006</em> beta launch</li>
</ul>
</div>

<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 41
- 0
trunk/data/%%6D^6DB^6DB28CFA%%about.tpl.php Näytä tiedosto

@@ -0,0 +1,41 @@
<?php /* Smarty version 2.6.16, created on 2007-03-17 15:57:51
compiled from about.tpl */ ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

<p>You'd probably know if your next door neighbour was going to knock their house down (you'd get a letter through the door telling you they had applied for planning permission and asking you what you thought about it). But you probably never find out if the old cinema or pub 5 streets away is going to be converted into luxury flats until <a href="http://www.bbc.co.uk/cult/hitchhikers/gallery/tv/fordprosser.shtml">the bulldozers turned up</a>.</p>
<p>
PlanningAlerts.com is a free service built by <a href="http://www.memespring.co.uk">Richard Pope</a> and <a href="http://brainoff.com">Mikel Maron</a> kindly hosted by <a href="http://www.mysociety.org">mySociety.org</a>. It searches as many local authority planning websites as it can find and emails you details of applications near you. The aim of this to enable shared scrutiny of what is being built (and <a href="http://www.urban75.net/vbulletin/showthread.php?t=154006" title="Death of the Queen">knocked down</a>) in peoples communities.
</p>

<h3 id="authorities">Planning authorities currently covered by the service</h3>
<p><small><span class="highlight">New authorities are being added all the time, so if your local authority isn't listed below <a href="/">sign up any way</a> and you'll start receiving alerts once it has been included</span>.</small></p>

<ul class="nobullets">
<?php $_from = ($this->_tpl_vars['authorities']); if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }$this->_foreach['authorities'] = array('total' => count($_from), 'iteration' => 0);
if ($this->_foreach['authorities']['total'] > 0):
foreach ($_from as $this->_tpl_vars['authority']):
$this->_foreach['authorities']['iteration']++;
?>
<li><?php echo $this->_tpl_vars['authority']; ?>
</li>
<?php endforeach; endif; unset($_from); ?>
</ul>

<p>If you are a programmer and would like to write a scraper for your local authority, or work for a local authority and would like to make your data available, <a href="/getinvolved.php">find out how you can get involved</a>.</p>

<h3 id="contact">Contact</h3>
<p>
You can get in touch at <a href="#">team@planningalerts.com</a>
</p>

<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 24
- 0
trunk/data/%%6E^6E1^6E190D42%%preview.tpl.php Näytä tiedosto

@@ -0,0 +1,24 @@
<?php /* Smarty version 2.6.16, created on 2007-03-17 15:24:58
compiled from preview.tpl */ ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>PlanningAlerts.com | Alert area preview</title>
<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=<?php echo $this->_tpl_vars['google_maps_key']; ?>
"
type="text/javascript"></script>
<script src="./javascript/preview.js" type="text/javascript"></script>
</head>

<body onload="load(<?php echo $this->_tpl_vars['center_long']; ?>
, <?php echo $this->_tpl_vars['center_lat']; ?>
, <?php echo $this->_tpl_vars['bottom_left_long']; ?>
, <?php echo $this->_tpl_vars['bottom_left_lat']; ?>
, <?php echo $this->_tpl_vars['top_right_long']; ?>
, <?php echo $this->_tpl_vars['top_right_lat']; ?>
)" onunload="GUnload()">
<div id="map" style="width: 500px; height: 500px"></div>
</body>
</html>

+ 32
- 0
trunk/data/%%80^80A^80A14535%%confirmed.tpl.php Näytä tiedosto

@@ -0,0 +1,32 @@
<?php /* Smarty version 2.6.16, created on 2006-12-29 16:27:29
compiled from confirmed.tpl */ ?>
<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
smarty_core_load_plugins(array('plugins' => array(array('modifier', 'upper', 'confirmed.tpl', 9, false),)), $this); ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>
<form action="<?php echo $this->_tpl_vars['form_action']; ?>
" method="post">
<fieldset>
<input type="hidden" name="_is_postback" value="1" />
</fieldset>
<div class="attention">
<h3>Thanks, your alert has been activated</h3>
<p>
You will now receive email alerts for any planning applications we find near <strong><?php echo ((is_array($_tmp=$this->_tpl_vars['postcode'])) ? $this->_run_mod_handler('upper', true, $_tmp) : smarty_modifier_upper($_tmp)); ?>
</strong> (within approximately <?php echo $this->_tpl_vars['alert_area_size']; ?>
m). If this alert doesn't cover everywhere you are interested in <span class="highlight"><a href="/">you can sign up for multiple alerts</a></span>
</p>

<p>
If you are interested in discussing local issues with your MP and other local people you can also join <a href="http://www.hearfromyourmp.com">HearFromYourMP.com</a>!
</p>
</div>
</form>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 15
- 0
trunk/data/%%A4^A42^A42CC6E6%%confirm_email_text.tpl.php Näytä tiedosto

@@ -0,0 +1,15 @@
<?php /* Smarty version 2.6.16, created on 2007-01-07 11:04:37
compiled from confirm_email_text.tpl */ ?>
<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
smarty_core_load_plugins(array('plugins' => array(array('block', 'textformat', 'confirm_email_text.tpl', 1, false),)), $this); ?>
<?php $this->_tag_stack[] = array('textformat', array('style' => 'email')); $_block_repeat=true;smarty_block_textformat($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);while ($_block_repeat) { ob_start(); ?>

Please click on the link below to confirm you want to receive email alerts for planning applications near <?php echo $this->_tpl_vars['postcode']; ?>
:

<?php echo $this->_tpl_vars['url']; ?>


If your email program does not let you click on this link, just copy and paste it into your web browser and hit return.

<?php $_block_content = ob_get_contents(); ob_end_clean(); $_block_repeat=false;echo smarty_block_textformat($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat); } array_pop($this->_tag_stack); ?>

+ 35
- 0
trunk/data/%%AD^AD7^AD71B708%%rss.tpl.php Näytä tiedosto

@@ -0,0 +1,35 @@
<?php /* Smarty version 2.6.16, created on 2007-03-20 21:55:51
compiled from rss.tpl */ ?>
<?php echo '<?xml'; ?>
version="1.0" encoding="UTF-8"<?php echo '?>'; ?>

<rss version="2.0" xmlns:georss="http://georss.org/georss">
<channel>
<title>Search Results</title>
<link></link>
<description></description>
<?php $_from = ($this->_tpl_vars['applications']); if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }$this->_foreach['applications'] = array('total' => count($_from), 'iteration' => 0);
if ($this->_foreach['applications']['total'] > 0):
foreach ($_from as $this->_tpl_vars['application']):
$this->_foreach['applications']['iteration']++;
?>
<item>
<guid><?php echo $this->_tpl_vars['application']->council_reference; ?>
</guid>
<georss:featurename><?php echo $this->_tpl_vars['application']->address; ?>
</georss:featurename>
<georss:point><?php echo $this->_tpl_vars['application']->lat; ?>
<?php echo $this->_tpl_vars['application']->lon; ?>
</georss:point>
<description><?php echo $this->_tpl_vars['application']->description; ?>
</description>
<link><?php echo $this->_tpl_vars['application']->info_url; ?>
</link>
<comments><?php echo $this->_tpl_vars['application']->comment_url; ?>
</comments>
<pubDate><?php echo $this->_tpl_vars['application']->date_received; ?>
</pubDate>
</item>
<?php endforeach; endif; unset($_from); ?>
</channel>
</rss>

+ 42
- 0
trunk/data/%%D2^D26^D26D8BFE%%xml.tpl.php Näytä tiedosto

@@ -0,0 +1,42 @@
<?php /* Smarty version 2.6.16, created on 2007-02-04 11:17:43
compiled from xml.tpl */ ?>
<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
smarty_core_load_plugins(array('plugins' => array(array('modifier', 'escape', 'xml.tpl', 6, false),)), $this); ?>
<?php echo '<?xml'; ?>
version="1.0" encoding="UTF-8"<?php echo '?>'; ?>

<planning>
<authority_name>
<?php echo ((is_array($_tmp=$this->_tpl_vars['authority_name'])) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>

</authority_name>
<authority_short_name>
<?php echo ((is_array($_tmp=$this->_tpl_vars['authority_short_name'])) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>

</authority_short_name>
<applications>
<?php $_from = ($this->_tpl_vars['applications']); if (!is_array($_from) && !is_object($_from)) { settype($_from, 'array'); }$this->_foreach['applications'] = array('total' => count($_from), 'iteration' => 0);
if ($this->_foreach['applications']['total'] > 0):
foreach ($_from as $this->_tpl_vars['application']):
$this->_foreach['applications']['iteration']++;
?>
<application>
<council_reference><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->council_reference)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</council_reference>
<address><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->address)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</address>
<postcode><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->postcode)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</postcode>
<description><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->description)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</description>
<info_url><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->info_url)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</info_url>
<comment_url><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->comment_url)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</comment_url>
<date_received><?php echo ((is_array($_tmp=$this->_tpl_vars['application']->date_received)) ? $this->_run_mod_handler('escape', true, $_tmp, 'html') : smarty_modifier_escape($_tmp, 'html')); ?>
</date_received>
</application>
<?php endforeach; endif; unset($_from); ?>
</applications>
</planning>

+ 33
- 0
trunk/data/%%F7^F75^F752BDC0%%getinvolved.tpl.php Näytä tiedosto

@@ -0,0 +1,33 @@
<?php /* Smarty version 2.6.16, created on 2007-01-26 09:58:31
compiled from getinvolved.tpl */ ?>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "header.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

<p>PlanningAlerts.com is run by volunteers if you would like to get involved we'd love to here from you:</p>

<h3>I am a programmer and want to add my local authority</h3>
<p>
You can help by writing a <a href="http://en.wikipedia.org/wiki/Screen_scraping">screen scraper</a> for your local authority that was can import into plannignalerts.com. There are only 2 criteria for the screen scraper:
</p>
<ol>
<li>That it can output data in the following format: <a href="http://www.planningalerts.com/lambeth.xml">http://www.planningalerts.com/lambeth.xml</a></li>
<li>That it can accept a query sting in the format day=X&month=Y&year=Z</li>
</ol>
<p>
Other than that it's up to you. It can be in any language. You can host them yourself or we can host it for you.
</p>

<h3>I work for a local authority and would like to make our data available</h3>
<p>
The most important thing you can do is publish your data in a simple format that is freely available on the internet. Something <a href="/lambeth.xml">like this</a> is good but we can work with most formats. Please <a href="/about.php#contact">get in touch</a> if you would like to discuss how you can help.
</p>
<?php $_smarty_tpl_vars = $this->_tpl_vars;
$this->_smarty_include(array('smarty_include_tpl_file' => "footer.tpl", 'smarty_include_vars' => array()));
$this->_tpl_vars = $_smarty_tpl_vars;
unset($_smarty_tpl_vars);
?>

+ 41
- 0
trunk/data/%%F7^F7F^F7F34188%%header.tpl.php Näytä tiedosto

@@ -0,0 +1,41 @@
<?php /* Smarty version 2.6.16, created on 2007-03-17 15:57:51
compiled from header.tpl */ ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<title>PlanningAlerts.com | <?php echo $this->_tpl_vars['page_title']; ?>
</title>
<link rel="stylesheet" media="all" type="text/css" href="./css/memespring.css" />
<link rel="stylesheet" media="all" type="text/css" href="./css/main.css" />
<script src="./javascript/main.js" type="text/javascript"></script>
</head>

<body>

<div class="hide">
<a href="#divContent">Skip navigation</a>
</div>
<div id="divMenu">
<ul class="collapse">
<li <?php if ($this->_tpl_vars['menu_item'] == 'about'): ?>class="selected"<?php endif; ?>><a href="about.php">About</a></li>
<li <?php if ($this->_tpl_vars['menu_item'] == 'getinvolved'): ?>class="selected"<?php endif; ?>><a href="getinvolved.php">Get involved</a></li>
<li <?php if ($this->_tpl_vars['menu_item'] == 'faq'): ?>class="selected"<?php endif; ?>><a href="faq.php"><acronym title="Frequently asked questions">FAQ</acronym>s</a></li>
<li <?php if ($this->_tpl_vars['menu_item'] == 'signup'): ?>class="selected"<?php endif; ?>><a href="/">Signup</a></li>
</ul>
</div>
<div id="divPage">
<div id="divHeader">
<h1><a href="/">PlanningAlerts<span>.</span>com</a><small>beta</small></h1>
<h2>Email alerts of planning applications <em>near you</em></h2>
<img alt="logo" title="logo" src="./images/logo.png" />
</div>
<div id="divContent">
<div id="divWarning" <?php if ($this->_tpl_vars['warnings'] == ""): ?>class="hide"<?php endif; ?>>
<?php echo $this->_tpl_vars['warnings']; ?>

</div>

+ 5
- 0
trunk/docs/.htaccess Näytä tiedosto

@@ -0,0 +1,5 @@
php_value include_path ".:/data/vhost/planning/docs/include/:/data/vhost/planning/docs/include/PEAR"





+ 4
- 0
trunk/docs/.htaccess.haggis Näytä tiedosto

@@ -0,0 +1,4 @@
php_value include_path ".:/data/vhost/www.planningalerts.com/docs/include/:/data/vhost/www.planningalerts.com/docs/include/PEAR"
php_value register_globals 0
php_value error_reporting E_ALL
php_value display_errors 1

+ 4
- 0
trunk/docs/.htaccess.live Näytä tiedosto

@@ -0,0 +1,4 @@
php_value include_path ".:/data/vhost/www.planningalerts.com/docs/include/:/data/vhost/www.planningalerts.com/docs/include/PEAR"
php_value register_globals 0
php_value error_reporting E_ALL
php_value log_errors 1

+ 57
- 0
trunk/docs/about.php Näytä tiedosto

@@ -0,0 +1,57 @@
<?php
require_once ("config.php");
require_once ("DB.php");
$about_page = new about_page;

class about_page {

//Properties
var $authorities = array();

//Constructor
function about_page() {
$this->setup();
$this->bind();
}
//Setup
function setup (){
$db = DB::connect(DB_CONNECTION_STRING);
//Grab a list of local authorities
$sql = "Select full_name, disabled from authority where disabled = 0 or disabled is null order by full_name";
$results = $db->getAll($sql);
for ($i=0; $i < sizeof($results); $i++){
array_push($this->authorities, $results[$i][0]);
}
}
//Bind
function bind() {
//page vars
$form_action = $_SERVER['PHP_SELF'];
//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;

$smarty->assign("page_title","About");
$smarty->assign("menu_item", "about");
$smarty->assign("authorities",$this->authorities);
//Render
$smarty->display('about.tpl');
}

}



?>

+ 79
- 0
trunk/docs/api.php Näytä tiedosto

@@ -0,0 +1,79 @@
<?php
require_once ("include/config.php");
require_once ("phpcoord.php");
$api = new api;

class api {

//Properties
var $warnings = "";
var $easting = 0;
var $northing = 0;
var $area_size = 0;
var $applications;

//Constructor
function api() {
$this->setup();
$this->bind();
}
//setup
function setup (){
//Grab the postcode and area size from the get string
if (!isset($_GET['area_size'])){ //check is_numeric and isn't too big
$this->warnings .= "No area size specified ";
}
if (!(isset($_GET['lat']) && isset($_GET['lng']))
|| !(isset($_GET['postcode'])) ) {
$this->warmings .= "No location specified ";
}
if ($this->warnings == ""){
//Get OS ref from postcode
if (isset($_GET['postcode'])) {
$xy = postcode_to_location($_GET['postcode']);
} else {
$latlng = new LatLng($_GET['lat'], $_GET['lng']);
$xy = $latlng->toOSRef();
}

$this->easting = $xy->easting;
$this->northing = $xy->northing;
$this->area_size = $_GET['area_size'];

$this->applications = Applications::query($this->easting, $this->northing, alert_size_to_meters($this->area_size));
}

}

//Bind
function bind () {
//page vars
$form_action = $_SERVER['PHP_SELF'];

header("Content-Type: text/xml");

//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;
$smarty->assign("warnings", $this->warnings);
$smarty->assign("applications", $this->applications);
//Render
$smarty->display('rss.tpl');
}

}



?>

+ 34
- 0
trunk/docs/checkmail.php Näytä tiedosto

@@ -0,0 +1,34 @@
<?php
require_once ("config.php");
require_once ("user.php");
$checkmail_page = new checkmail_page;

class checkmail_page {

//Constructor
function checkmail_page() {
$this->bind();
}
//Bind
function bind() {
//page vars
$form_action = $_SERVER['PHP_SELF'];
//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;

$smarty->assign("page_title","Now check your email");
$smarty->assign("menu_item", "signup");
//Render
$smarty->display('checkmail.tpl');
}

}



?>

+ 76
- 0
trunk/docs/confirmed.php Näytä tiedosto

@@ -0,0 +1,76 @@
<?php
require_once ("config.php");
require_once ("user.php");
$confirmed_page = new confirmed_page;

class confirmed_page {

//Properties
var $postcode = "";
var $alert_area_size = 0;
//Constructor
function confirmed_page() {
$this->setup();
$this->bind();
}
//Setup
function setup (){
//Grab the user
if(isset($_GET['cid'])){
$confirm_id = $_GET['cid'];
}else{
header("HTTP/1.0 404 Not Found");
exit;
}
$user = new user();
if($user->load_from_confirm_id($confirm_id)){

//Update the confirmed flag
$user->confirmed = true;
//delete any other active alerts for this postcode
$user->remove_existing();

$user->save(false);

//Grab the postcode and area
$this->postcode = $user->postcode;
$this->alert_area_size = alert_size_to_meters($user->alert_area_size);
}else{
header("HTTP/1.0 404 Not Found");
exit;
}

}
//Bind
function bind() {

$form_action = $_SERVER['PHP_SELF'];
//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;

$smarty->assign("menu_item", "signup");
$smarty->assign("page_title","Confirmed");
$smarty->assign("form_action", $form_action);
$smarty->assign("postcode", $this->postcode);
$smarty->assign("alert_area_size", $this->alert_area_size);

//Render
$smarty->display('confirmed.tpl');
}
}



?>

+ 33
- 0
trunk/docs/cron.php Näytä tiedosto

@@ -0,0 +1,33 @@
<?php

//includes
require_once('config.php');
require_once('application_parser.php');
require_once('mailer.php');
if (!isset($_GET['action'])){
print "nothing to see here.";
}else{
echo "starting action " . $_GET['action'];
}
$action = $_GET['action'];
if($action == "scrape"){
//Launch the parser
$application_parser = new application_parser();
$application_parser->date = getdate(strtotime("-" . SCRAPE_DELAY . " days"));
$application_parser->run();

}
if ($action == "mail"){
//Launch the mailer
$mailer = new mailer();
$mailer->run();
}


?>

+ 81
- 0
trunk/docs/css/main.css Näytä tiedosto

@@ -0,0 +1,81 @@
body {font-family:georgia, serif; text-align:center;line-height:2em;margin:0;
color:#0f0f0f;}
#divPage {width:500px; margin:0 auto;background:white;text-align:left;}
h1 {font-weight:normal; font-size:2.7em;padding-left:115px;padding-bottom:0.2em;padding-top:0.1em;}
h1 a {color:#456FB1;text-decoration:none;}
h1 span {color:#96ca2f;}
h1 small {font-size:0.3em; text-transform:uppercase;position:absolute;
right:0.8em;top:2.1em;color:#456FB1}
h2 {font-weight:normal;font-size:1em;border-bottom:dotted 1px #808080;padding-left:115px;
padding-bottom:1.5em;color:#96ca2f;font-style:italic;font-size:1.15em;}
h2 em {text-decoration:underline}
h3, h4 {color:#96ca2f;font-style:italic;font-weight:normal}

#divHeader {margin-top:1.7em;padding-bottom:1em;position:relative;}
#divHeader img {position:absolute;top:-15px;}

/* Menu */
#divMenu {background:#6E84BD;height:2.3em;font-size:0.7em;}
#divMenu ul {width:500px;margin:0 auto;}
#divMenu ul li {float:right;text-align:center;}
#divMenu ul li a {margin-left:1em;margin-right:1em;display:block; color:white;
text-decoration:none;position:relative; top:-0.2em;}
#divMenu ul li.selected {background:#96ca2f;}

/* Beta note */
#pBeta {font-size:0.8em; text-align:center;padding:0;margin:0;position:relative; top:-0.4em;
color:#666;}
#pBeta span {background:#fdd9ea;}

/* Warnings & errors*/
#divWarning {background:#fdd9ea;font-size:0.9em;text-align:center; margin-bottom:1em;}
input.error {background:#fdd9ea;}

/* Signup form */
span.number {font-size:2em;float:left;display:block;
text-align:center;padding-bottom:0.6em;margin-right:0.7em;margin-left:0.4em;
color:#456FB1;}
#liAlertArea span.number {margin-bottom:2em;}
#ulSignup label {width:250px;}
#ulSignup input.textbox {position:relative; top:0.4em;}
#ulSignup fieldset label {display:inline;float:none;}
#liEmail, #liPostcode, #liAlertArea {background:#ffffaa;}
#liEmail {height:2.3em;margin-bottom:1em;}
#liEmail input.textbox {width:230px;}
#liPostcode {height:2.3em;}
#liPostcode input.textbox {width:80px;}
#liPostcode small {position:relative; top:0.6em;padding-left:0.3em;}
#pAlertArea {margin-bottom:0;}
#ulAlertArea {font-size:0.9em;line-height:1.3em;}
#ulAlertArea li {}
#liSignup input.button {font-size:1.5em;margin-top:0.5em;margin-bottom:0.5em;}

/* Attention grabbers */
div.attention {text-align:center; padding-top:1em;}
div.attention h3 {font-size:2em;padding-bottom:0.3em;font-style:normal; color:#456FB1;}

/* Faqs */
dl.faq dt {color:#96ca2f;font-style:italic;}
dl.faq dd {padding-left:0;margin-left:0;}

/* infobox */
.infobox {background:#fdd9ea; font-size:0.9em;}

/* highlight */
span.highlight {background:#ffffaa;}

/* Index footer */
#divSiteUpdates {border-top:dotted 1px #808080;padding-top:0.5em;}
#divSiteUpdates ul {font-size:0.9em;margin:0;}
#divSiteUpdates em {padding-right:0.5em;color:#456FB1;}

/* Links */
a {color:#22579C;}

/* Footer */
#divFooter {text-align:center;font-size:0.9em;
padding-top:1.5em;}
#divFooter ul {border-top:dotted 1px #808080;}

/* Buttons */
input.button {font-family:georgia, serif;}

+ 59
- 0
trunk/docs/css/memespring.css Näytä tiedosto

@@ -0,0 +1,59 @@
/*
This file is for usefull reusable css
*/

/* lists */
ul.form label {display:block; float:left; width:170px; padding-top:4px;}
ul.form label.radiolabel {display:inline; float: none;}
ul.form span.fauxlabel {display:block; float:left; width:160px;}
ul.form li {margin:5px 0;padding-bottom: 6px!important;}
ul.form input.textbox {width:165px;}
ul.form select {width:175px;}
ul.form input.textbox.small, ul.form select.small {width:80px;}
ul.form input.textbox.verysmall {width:30px;}
ul.form select.verysmall {width:45px;}
ul.form input.textbox.right {text-align:right;padding-right:0.2em;}

ul.collapse, ol.collapse {margin:0;padding:0;}
ul.collapse li, ol.collapse li {margin:0;padding:0;float:left;}
ul.collapse li, ol.collapse {list-style-type:none;}

ul.inline {margin:0;padding:0;}
ul.inline li {display:inline;margin:0;padding:0;}

ul.nobullets {list-style-type:none;margin:0;padding:0;}
ul.nobullets li {margin:0;padding:0;}

/* image replacement */
.hide {display:none;}

/* clear */
br.clear {clear:both}

/* controls */
fieldset {border:none; padding:0; margin:0;}

/* links */
a img {border:none;}

/* headings */
h1, h2, h3, h4, h5, h6 {margin:0;padding:0;}

/* form elements */
input.textbox.autopostback {background: white url(../images/return.png) no-repeat right 50%;}
input select, textarea {background:white}
input.textbox {width:180px;}
input.textbox.small {width:80px;}
input.textbox.verysmall {width:80px;}
input.textbox.right {text-align:right;padding-right:0.2em;}

/* alignment */
.alignright {text-align:right;}

/* tables */
table {border-collapse: collapse;}

/* buttons */
div.buttons {text-align:right; padding:1em;}



+ 34
- 0
trunk/docs/faq.php Näytä tiedosto

@@ -0,0 +1,34 @@
<?php
require_once ("config.php");
$faq_page = new faq_page;

class faq_page {

//Constructor
function faq_page() {
$this->bind();
}
//Bind
function bind() {
//page vars
$form_action = $_SERVER['PHP_SELF'];
//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;

$smarty->assign("page_title","Frequently asked questions");
$smarty->assign("menu_item", "faq");
//Render
$smarty->display('faq.tpl');
}

}



?>

BIN
trunk/docs/favicon.ico Näytä tiedosto

Before After

+ 35
- 0
trunk/docs/getinvolved.php Näytä tiedosto

@@ -0,0 +1,35 @@
<?php
require_once ("config.php");
$getinvolved_page = new getinvolved_page();

class getinvolved_page {

//Constructor
function getinvolved_page() {
$this->bind();
}
//Bind
function bind() {
//page vars
$form_action = $_SERVER['PHP_SELF'];
//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;

$smarty->assign("page_title","Get involved");
$smarty->assign("menu_item", "getinvolved");
//Render
$smarty->display('getinvolved.tpl');
}

}



?>

BIN
trunk/docs/images/background.png Näytä tiedosto

Before After
Leveys: 4  |  Korkeus: 4  |  Koko: 150 B

BIN
trunk/docs/images/logo.png Näytä tiedosto

Before After
Leveys: 100  |  Korkeus: 105  |  Koko: 5.3 KiB

+ 1388
- 0
trunk/docs/include/PEAR/DB.php
File diff suppressed because it is too large
Näytä tiedosto


+ 2157
- 0
trunk/docs/include/PEAR/DB/common.php
File diff suppressed because it is too large
Näytä tiedosto


+ 1034
- 0
trunk/docs/include/PEAR/DB/mysql.php
File diff suppressed because it is too large
Näytä tiedosto


+ 1097
- 0
trunk/docs/include/PEAR/DB/pgsql.php
File diff suppressed because it is too large
Näytä tiedosto


+ 504
- 0
trunk/docs/include/PEAR/DB/storage.php Näytä tiedosto

@@ -0,0 +1,504 @@
<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
* Provides an object interface to a table row
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category Database
* @package DB
* @author Stig Bakken <stig@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: storage.php,v 1.1 2005/08/01 06:21:02 dancoulter Exp $
* @link http://pear.php.net/package/DB
*/

/**
* Obtain the DB class so it can be extended from
*/
require_once 'DB.php';

/**
* Provides an object interface to a table row
*
* It lets you add, delete and change rows using objects rather than SQL
* statements.
*
* @category Database
* @package DB
* @author Stig Bakken <stig@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: @package_version@
* @link http://pear.php.net/package/DB
*/
class DB_storage extends PEAR
{
// {{{ properties

/** the name of the table (or view, if the backend database supports
updates in views) we hold data from */
var $_table = null;

/** which column(s) in the table contains primary keys, can be a
string for single-column primary keys, or an array of strings
for multiple-column primary keys */
var $_keycolumn = null;

/** DB connection handle used for all transactions */
var $_dbh = null;

/** an assoc with the names of database fields stored as properties
in this object */
var $_properties = array();

/** an assoc with the names of the properties in this object that
have been changed since they were fetched from the database */
var $_changes = array();

/** flag that decides if data in this object can be changed.
objects that don't have their table's key column in their
property lists will be flagged as read-only. */
var $_readonly = false;

/** function or method that implements a validator for fields that
are set, this validator function returns true if the field is
valid, false if not */
var $_validator = null;

// }}}
// {{{ constructor

/**
* Constructor
*
* @param $table string the name of the database table
*
* @param $keycolumn mixed string with name of key column, or array of
* strings if the table has a primary key of more than one column
*
* @param $dbh object database connection object
*
* @param $validator mixed function or method used to validate
* each new value, called with three parameters: the name of the
* field/column that is changing, a reference to the new value and
* a reference to this object
*
*/
function DB_storage($table, $keycolumn, &$dbh, $validator = null)
{
$this->PEAR('DB_Error');
$this->_table = $table;
$this->_keycolumn = $keycolumn;
$this->_dbh = $dbh;
$this->_readonly = false;
$this->_validator = $validator;
}

// }}}
// {{{ _makeWhere()

/**
* Utility method to build a "WHERE" clause to locate ourselves in
* the table.
*
* XXX future improvement: use rowids?
*
* @access private
*/
function _makeWhere($keyval = null)
{
if (is_array($this->_keycolumn)) {
if ($keyval === null) {
for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
$keyval[] = $this->{$this->_keycolumn[$i]};
}
}
$whereclause = '';
for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
if ($i > 0) {
$whereclause .= ' AND ';
}
$whereclause .= $this->_keycolumn[$i];
if (is_null($keyval[$i])) {
// there's not much point in having a NULL key,
// but we support it anyway
$whereclause .= ' IS NULL';
} else {
$whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
}
}
} else {
if ($keyval === null) {
$keyval = @$this->{$this->_keycolumn};
}
$whereclause = $this->_keycolumn;
if (is_null($keyval)) {
// there's not much point in having a NULL key,
// but we support it anyway
$whereclause .= ' IS NULL';
} else {
$whereclause .= ' = ' . $this->_dbh->quote($keyval);
}
}
return $whereclause;
}

// }}}
// {{{ setup()

/**
* Method used to initialize a DB_storage object from the
* configured table.
*
* @param $keyval mixed the key[s] of the row to fetch (string or array)
*
* @return int DB_OK on success, a DB error if not
*/
function setup($keyval)
{
$whereclause = $this->_makeWhere($keyval);
$query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause;
$sth = $this->_dbh->query($query);
if (DB::isError($sth)) {
return $sth;
}
$row = $sth->fetchRow(DB_FETCHMODE_ASSOC);
if (DB::isError($row)) {
return $row;
}
if (!$row) {
return $this->raiseError(null, DB_ERROR_NOT_FOUND, null, null,
$query, null, true);
}
foreach ($row as $key => $value) {
$this->_properties[$key] = true;
$this->$key = $value;
}
return DB_OK;
}

// }}}
// {{{ insert()

/**
* Create a new (empty) row in the configured table for this
* object.
*/
function insert($newpk)
{
if (is_array($this->_keycolumn)) {
$primarykey = $this->_keycolumn;
} else {
$primarykey = array($this->_keycolumn);
}
settype($newpk, "array");
for ($i = 0; $i < sizeof($primarykey); $i++) {
$pkvals[] = $this->_dbh->quote($newpk[$i]);
}

$sth = $this->_dbh->query("INSERT INTO $this->_table (" .
implode(",", $primarykey) . ") VALUES(" .
implode(",", $pkvals) . ")");
if (DB::isError($sth)) {
return $sth;
}
if (sizeof($newpk) == 1) {
$newpk = $newpk[0];
}
$this->setup($newpk);
}

// }}}
// {{{ toString()

/**
* Output a simple description of this DB_storage object.
* @return string object description
*/
function toString()
{
$info = strtolower(get_class($this));
$info .= " (table=";
$info .= $this->_table;
$info .= ", keycolumn=";
if (is_array($this->_keycolumn)) {
$info .= "(" . implode(",", $this->_keycolumn) . ")";
} else {
$info .= $this->_keycolumn;
}
$info .= ", dbh=";
if (is_object($this->_dbh)) {
$info .= $this->_dbh->toString();
} else {
$info .= "null";
}
$info .= ")";
if (sizeof($this->_properties)) {
$info .= " [loaded, key=";
$keyname = $this->_keycolumn;
if (is_array($keyname)) {
$info .= "(";
for ($i = 0; $i < sizeof($keyname); $i++) {
if ($i > 0) {
$info .= ",";
}
$info .= $this->$keyname[$i];
}
$info .= ")";
} else {
$info .= $this->$keyname;
}
$info .= "]";
}
if (sizeof($this->_changes)) {
$info .= " [modified]";
}
return $info;
}

// }}}
// {{{ dump()

/**
* Dump the contents of this object to "standard output".
*/
function dump()
{
foreach ($this->_properties as $prop => $foo) {
print "$prop = ";
print htmlentities($this->$prop);
print "<br />\n";
}
}

// }}}
// {{{ &create()

/**
* Static method used to create new DB storage objects.
* @param $data assoc. array where the keys are the names
* of properties/columns
* @return object a new instance of DB_storage or a subclass of it
*/
function &create($table, &$data)
{
$classname = strtolower(get_class($this));
$obj =& new $classname($table);
foreach ($data as $name => $value) {
$obj->_properties[$name] = true;
$obj->$name = &$value;
}
return $obj;
}

// }}}
// {{{ loadFromQuery()

/**
* Loads data into this object from the given query. If this
* object already contains table data, changes will be saved and
* the object re-initialized first.
*
* @param $query SQL query
*
* @param $params parameter list in case you want to use
* prepare/execute mode
*
* @return int DB_OK on success, DB_WARNING_READ_ONLY if the
* returned object is read-only (because the object's specified
* key column was not found among the columns returned by $query),
* or another DB error code in case of errors.
*/
// XXX commented out for now
/*
function loadFromQuery($query, $params = null)
{
if (sizeof($this->_properties)) {
if (sizeof($this->_changes)) {
$this->store();
$this->_changes = array();
}
$this->_properties = array();
}
$rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params);
if (DB::isError($rowdata)) {
return $rowdata;
}
reset($rowdata);
$found_keycolumn = false;
while (list($key, $value) = each($rowdata)) {
if ($key == $this->_keycolumn) {
$found_keycolumn = true;
}
$this->_properties[$key] = true;
$this->$key = &$value;
unset($value); // have to unset, or all properties will
// refer to the same value
}
if (!$found_keycolumn) {
$this->_readonly = true;
return DB_WARNING_READ_ONLY;
}
return DB_OK;
}
*/

// }}}
// {{{ set()

/**
* Modify an attriute value.
*/
function set($property, $newvalue)
{
// only change if $property is known and object is not
// read-only
if ($this->_readonly) {
return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
null, null, null, true);
}
if (@isset($this->_properties[$property])) {
if (empty($this->_validator)) {
$valid = true;
} else {
$valid = @call_user_func($this->_validator,
$this->_table,
$property,
$newvalue,
$this->$property,
$this);
}
if ($valid) {
$this->$property = $newvalue;
if (empty($this->_changes[$property])) {
$this->_changes[$property] = 0;
} else {
$this->_changes[$property]++;
}
} else {
return $this->raiseError(null, DB_ERROR_INVALID, null,
null, "invalid field: $property",
null, true);
}
return true;
}
return $this->raiseError(null, DB_ERROR_NOSUCHFIELD, null,
null, "unknown field: $property",
null, true);
}

// }}}
// {{{ &get()

/**
* Fetch an attribute value.
*
* @param string attribute name
*
* @return attribute contents, or null if the attribute name is
* unknown
*/
function &get($property)
{
// only return if $property is known
if (isset($this->_properties[$property])) {
return $this->$property;
}
$tmp = null;
return $tmp;
}

// }}}
// {{{ _DB_storage()

/**
* Destructor, calls DB_storage::store() if there are changes
* that are to be kept.
*/
function _DB_storage()
{
if (sizeof($this->_changes)) {
$this->store();
}
$this->_properties = array();
$this->_changes = array();
$this->_table = null;
}

// }}}
// {{{ store()

/**
* Stores changes to this object in the database.
*
* @return DB_OK or a DB error
*/
function store()
{
foreach ($this->_changes as $name => $foo) {
$params[] = &$this->$name;
$vars[] = $name . ' = ?';
}
if ($vars) {
$query = 'UPDATE ' . $this->_table . ' SET ' .
implode(', ', $vars) . ' WHERE ' .
$this->_makeWhere();
$stmt = $this->_dbh->prepare($query);
$res = $this->_dbh->execute($stmt, $params);
if (DB::isError($res)) {
return $res;
}
$this->_changes = array();
}
return DB_OK;
}

// }}}
// {{{ remove()

/**
* Remove the row represented by this object from the database.
*
* @return mixed DB_OK or a DB error
*/
function remove()
{
if ($this->_readonly) {
return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
null, null, null, true);
}
$query = 'DELETE FROM ' . $this->_table .' WHERE '.
$this->_makeWhere();
$res = $this->_dbh->query($query);
if (DB::isError($res)) {
return $res;
}
foreach ($this->_properties as $prop => $foo) {
unset($this->$prop);
}
$this->_properties = array();
$this->_changes = array();
return DB_OK;
}

// }}}
}

/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/

?>

+ 1395
- 0
trunk/docs/include/PEAR/HTTP/Request.php
File diff suppressed because it is too large
Näytä tiedosto


+ 668
- 0
trunk/docs/include/PEAR/Log.php Näytä tiedosto

@@ -0,0 +1,668 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log.php,v 1.1 2006/02/19 08:22:40 dennis Exp $
* $Horde: horde/lib/Log.php,v 1.15 2000/06/29 23:39:45 jon Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

define('PEAR_LOG_EMERG', 0); /** System is unusable */
define('PEAR_LOG_ALERT', 1); /** Immediate action required */
define('PEAR_LOG_CRIT', 2); /** Critical conditions */
define('PEAR_LOG_ERR', 3); /** Error conditions */
define('PEAR_LOG_WARNING', 4); /** Warning conditions */
define('PEAR_LOG_NOTICE', 5); /** Normal but significant */
define('PEAR_LOG_INFO', 6); /** Informational */
define('PEAR_LOG_DEBUG', 7); /** Debug-level messages */

define('PEAR_LOG_ALL', bindec('11111111')); /** All messages */
define('PEAR_LOG_NONE', bindec('00000000')); /** No message */

/* Log types for PHP's native error_log() function. */
define('PEAR_LOG_TYPE_SYSTEM', 0); /** Use PHP's system logger */
define('PEAR_LOG_TYPE_MAIL', 1); /** Use PHP's mail() function */
define('PEAR_LOG_TYPE_DEBUG', 2); /** Use PHP's debugging connection */
define('PEAR_LOG_TYPE_FILE', 3); /** Append to a file */

/**
* The Log:: class implements both an abstraction for various logging
* mechanisms and the Subject end of a Subject-Observer pattern.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Jon Parise <jon@php.net>
* @since Horde 1.3
* @package Log
*/
class Log
{
/**
* Indicates whether or not the log can been opened / connected.
*
* @var boolean
* @access private
*/
var $_opened = false;

/**
* Instance-specific unique identification number.
*
* @var integer
* @access private
*/
var $_id = 0;

/**
* The label that uniquely identifies this set of log messages.
*
* @var string
* @access private
*/
var $_ident = '';

/**
* The default priority to use when logging an event.
*
* @var integer
* @access private
*/
var $_priority = PEAR_LOG_INFO;

/**
* The bitmask of allowed log levels.
* @var integer
* @access private
*/
var $_mask = PEAR_LOG_ALL;

/**
* Holds all Log_observer objects that wish to be notified of new messages.
*
* @var array
* @access private
*/
var $_listeners = array();


/**
* Attempts to return a concrete Log instance of type $handler.
*
* @param string $handler The type of concrete Log subclass to return.
* Attempt to dynamically include the code for
* this subclass. Currently, valid values are
* 'console', 'syslog', 'sql', 'file', and 'mcal'.
*
* @param string $name The name of the actually log file, table, or
* other specific store to use. Defaults to an
* empty string, with which the subclass will
* attempt to do something intelligent.
*
* @param string $ident The identity reported to the log system.
*
* @param array $conf A hash containing any additional configuration
* information that a subclass might need.
*
* @param int $level Log messages up to and including this level.
*
* @return object Log The newly created concrete Log instance, or
* null on an error.
* @access public
* @since Log 1.0
*/
function &factory($handler, $name = '', $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$handler = strtolower($handler);
$class = 'Log_' . $handler;
$classfile = 'Log/' . $handler . '.php';

/*
* Attempt to include our version of the named class, but don't treat
* a failure as fatal. The caller may have already included their own
* version of the named class.
*/
if (!class_exists($class)) {
@include_once $classfile;
}

/* If the class exists, return a new instance of it. */
if (class_exists($class)) {
$obj = new $class($name, $ident, $conf, $level);
return $obj;
}

return null;
}

/**
* Attempts to return a reference to a concrete Log instance of type
* $handler, only creating a new instance if no log instance with the same
* parameters currently exists.
*
* You should use this if there are multiple places you might create a
* logger, you don't want to create multiple loggers, and you don't want to
* check for the existance of one each time. The singleton pattern does all
* the checking work for you.
*
* <b>You MUST call this method with the $var = &Log::singleton() syntax.
* Without the ampersand (&) in front of the method name, you will not get
* a reference, you will get a copy.</b>
*
* @param string $handler The type of concrete Log subclass to return.
* Attempt to dynamically include the code for
* this subclass. Currently, valid values are
* 'console', 'syslog', 'sql', 'file', and 'mcal'.
*
* @param string $name The name of the actually log file, table, or
* other specific store to use. Defaults to an
* empty string, with which the subclass will
* attempt to do something intelligent.
*
* @param string $ident The identity reported to the log system.
*
* @param array $conf A hash containing any additional configuration
* information that a subclass might need.
*
* @param int $level Log messages up to and including this level.
*
* @return object Log The newly created concrete Log instance, or
* null on an error.
* @access public
* @since Log 1.0
*/
function &singleton($handler, $name = '', $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
static $instances;
if (!isset($instances)) $instances = array();

$signature = serialize(array($handler, $name, $ident, $conf, $level));
if (!isset($instances[$signature])) {
$instances[$signature] = &Log::factory($handler, $name, $ident,
$conf, $level);
}

return $instances[$signature];
}

/**
* Abstract implementation of the open() method.
* @since Log 1.0
*/
function open()
{
return false;
}

/**
* Abstract implementation of the close() method.
* @since Log 1.0
*/
function close()
{
return false;
}

/**
* Abstract implementation of the flush() method.
* @since Log 1.8.2
*/
function flush()
{
return false;
}

/**
* Abstract implementation of the log() method.
* @since Log 1.0
*/
function log($message, $priority = null)
{
return false;
}

/**
* A convenience function for logging a emergency event. It will log a
* message at the PEAR_LOG_EMERG log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function emerg($message)
{
return $this->log($message, PEAR_LOG_EMERG);
}

/**
* A convenience function for logging an alert event. It will log a
* message at the PEAR_LOG_ALERT log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function alert($message)
{
return $this->log($message, PEAR_LOG_ALERT);
}

/**
* A convenience function for logging a critical event. It will log a
* message at the PEAR_LOG_CRIT log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function crit($message)
{
return $this->log($message, PEAR_LOG_CRIT);
}

/**
* A convenience function for logging a error event. It will log a
* message at the PEAR_LOG_ERR log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function err($message)
{
return $this->log($message, PEAR_LOG_ERR);
}

/**
* A convenience function for logging a warning event. It will log a
* message at the PEAR_LOG_WARNING log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function warning($message)
{
return $this->log($message, PEAR_LOG_WARNING);
}

/**
* A convenience function for logging a notice event. It will log a
* message at the PEAR_LOG_NOTICE log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function notice($message)
{
return $this->log($message, PEAR_LOG_NOTICE);
}

/**
* A convenience function for logging a information event. It will log a
* message at the PEAR_LOG_INFO log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function info($message)
{
return $this->log($message, PEAR_LOG_INFO);
}

/**
* A convenience function for logging a debug event. It will log a
* message at the PEAR_LOG_DEBUG log level.
*
* @param mixed $message String or object containing the message
* to log.
*
* @return boolean True if the message was successfully logged.
*
* @access public
* @since Log 1.7.0
*/
function debug($message)
{
return $this->log($message, PEAR_LOG_DEBUG);
}

/**
* Returns the string representation of the message data.
*
* If $message is an object, _extractMessage() will attempt to extract
* the message text using a known method (such as a PEAR_Error object's
* getMessage() method). If a known method, cannot be found, the
* serialized representation of the object will be returned.
*
* If the message data is already a string, it will be returned unchanged.
*
* @param mixed $message The original message data. This may be a
* string or any object.
*
* @return string The string representation of the message.
*
* @access private
*/
function _extractMessage($message)
{
/*
* If we've been given an object, attempt to extract the message using
* a known method. If we can't find such a method, default to the
* "human-readable" version of the object.
*
* We also use the human-readable format for arrays.
*/
if (is_object($message)) {
if (method_exists($message, 'getmessage')) {
$message = $message->getMessage();
} else if (method_exists($message, 'tostring')) {
$message = $message->toString();
} else if (method_exists($message, '__tostring')) {
if (version_compare(PHP_VERSION, '5.0.0', 'ge')) {
$message = (string)$message;
} else {
$message = $message->__toString();
}
} else {
$message = print_r($message, true);
}
} else if (is_array($message)) {
if (isset($message['message'])) {
$message = $message['message'];
} else {
$message = print_r($message, true);
}
}

/* Otherwise, we assume the message is a string. */
return $message;
}

/**
* Returns the string representation of a PEAR_LOG_* integer constant.
*
* @param int $priority A PEAR_LOG_* integer constant.
*
* @return string The string representation of $level.
*
* @since Log 1.0
*/
function priorityToString($priority)
{
$levels = array(
PEAR_LOG_EMERG => 'emergency',
PEAR_LOG_ALERT => 'alert',
PEAR_LOG_CRIT => 'critical',
PEAR_LOG_ERR => 'error',
PEAR_LOG_WARNING => 'warning',
PEAR_LOG_NOTICE => 'notice',
PEAR_LOG_INFO => 'info',
PEAR_LOG_DEBUG => 'debug'
);

return $levels[$priority];
}

/**
* Returns the the PEAR_LOG_* integer constant for the given string
* representation of a priority name. This function performs a
* case-insensitive search.
*
* @param string $name String containing a priority name.
*
* @return string The PEAR_LOG_* integer contstant corresponding
* the the specified priority name.
*
* @since Log 1.9.0
*/
function stringToPriority($name)
{
$levels = array(
'emergency' => PEAR_LOG_EMERG,
'alert' => PEAR_LOG_ALERT,
'critical' => PEAR_LOG_CRIT,
'error' => PEAR_LOG_ERR,
'warning' => PEAR_LOG_WARNING,
'notice' => PEAR_LOG_NOTICE,
'info' => PEAR_LOG_INFO,
'debug' => PEAR_LOG_DEBUG
);

return $levels[strtolower($name)];
}

/**
* Calculate the log mask for the given priority.
*
* @param integer $priority The priority whose mask will be calculated.
*
* @return integer The calculated log mask.
*
* @access public
* @since Log 1.7.0
*/
function MASK($priority)
{
return (1 << $priority);
}

/**
* Calculate the log mask for all priorities up to the given priority.
*
* @param integer $priority The maximum priority covered by this mask.
*
* @return integer The calculated log mask.
*
* @access public
* @since Log 1.7.0
*/
function UPTO($priority)
{
return ((1 << ($priority + 1)) - 1);
}

/**
* Set and return the level mask for the current Log instance.
*
* @param integer $mask A bitwise mask of log levels.
*
* @return integer The current level mask.
*
* @access public
* @since Log 1.7.0
*/
function setMask($mask)
{
$this->_mask = $mask;

return $this->_mask;
}

/**
* Returns the current level mask.
*
* @return interger The current level mask.
*
* @access public
* @since Log 1.7.0
*/
function getMask()
{
return $this->_mask;
}

/**
* Check if the given priority is included in the current level mask.
*
* @param integer $priority The priority to check.
*
* @return boolean True if the given priority is included in the current
* log mask.
*
* @access private
* @since Log 1.7.0
*/
function _isMasked($priority)
{
return (Log::MASK($priority) & $this->_mask);
}

/**
* Returns the current default priority.
*
* @return integer The current default priority.
*
* @access public
* @since Log 1.8.4
*/
function getPriority()
{
return $this->_priority;
}

/**
* Sets the default priority to the specified value.
*
* @param integer $priority The new default priority.
*
* @access public
* @since Log 1.8.4
*/
function setPriority($priority)
{
$this->_priority = $priority;
}

/**
* Adds a Log_observer instance to the list of observers that are listening
* for messages emitted by this Log instance.
*
* @param object $observer The Log_observer instance to attach as a
* listener.
*
* @param boolean True if the observer is successfully attached.
*
* @access public
* @since Log 1.0
*/
function attach(&$observer)
{
if (!is_a($observer, 'Log_observer')) {
return false;
}

$this->_listeners[$observer->_id] = &$observer;

return true;
}

/**
* Removes a Log_observer instance from the list of observers.
*
* @param object $observer The Log_observer instance to detach from
* the list of listeners.
*
* @param boolean True if the observer is successfully detached.
*
* @access public
* @since Log 1.0
*/
function detach($observer)
{
if (!is_a($observer, 'Log_observer') ||
!isset($this->_listeners[$observer->_id])) {
return false;
}

unset($this->_listeners[$observer->_id]);

return true;
}

/**
* Informs each registered observer instance that a new message has been
* logged.
*
* @param array $event A hash describing the log event.
*
* @access private
*/
function _announce($event)
{
foreach ($this->_listeners as $id => $listener) {
if ($event['priority'] <= $this->_listeners[$id]->_priority) {
$this->_listeners[$id]->notify($event);
}
}
}

/**
* Indicates whether this is a composite class.
*
* @return boolean True if this is a composite class.
*
* @access public
* @since Log 1.0
*/
function isComposite()
{
return false;
}

/**
* Sets this Log instance's identification string.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.6.3
*/
function setIdent($ident)
{
$this->_ident = $ident;
}

/**
* Returns the current identification string.
*
* @return string The current Log instance's identification string.
*
* @access public
* @since Log 1.6.3
*/
function getIdent()
{
return $this->_ident;
}
}

+ 200
- 0
trunk/docs/include/PEAR/Log/composite.php Näytä tiedosto

@@ -0,0 +1,200 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/composite.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
* $Horde: horde/lib/Log/composite.php,v 1.2 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_composite:: class implements a Composite pattern which
* allows multiple Log implementations to receive the same events.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Jon Parise <jon@php.net>
*
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example composite.php Using the composite handler.
*/
class Log_composite extends Log
{
/**
* Array holding all of the Log instances to which log events should be
* sent.
*
* @var array
* @access private
*/
var $_children = array();


/**
* Constructs a new composite Log object.
*
* @param boolean $name This parameter is ignored.
* @param boolean $ident This parameter is ignored.
* @param boolean $conf This parameter is ignored.
* @param boolean $level This parameter is ignored.
*
* @access public
*/
function Log_composite($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_ident = $ident;
}

/**
* Opens the child connections.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
foreach ($this->_children as $id => $child) {
$this->_children[$id]->open();
}
$this->_opened = true;
}
}

/**
* Closes any child instances.
*
* @access public
*/
function close()
{
if ($this->_opened) {
foreach ($this->_children as $id => $child) {
$this->_children[$id]->close();
}
$this->_opened = false;
}
}

/**
* Flushes all open child instances.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
if ($this->_opened) {
foreach ($this->_children as $id => $child) {
$this->_children[$id]->flush();
}
}
}

/**
* Sends $message and $priority to each child of this composite.
*
* @param mixed $message String or object containing the message
* to log.
* @param string $priority (optional) The priority of the message.
* Valid values are: PEAR_LOG_EMERG,
* PEAR_LOG_ALERT, PEAR_LOG_CRIT,
* PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and
* PEAR_LOG_DEBUG.
*
* @return boolean True if the entry is successfully logged.
*
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

foreach ($this->_children as $id => $child) {
$this->_children[$id]->log($message, $priority);
}

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

/**
* Returns true if this is a composite.
*
* @return boolean True if this is a composite class.
*
* @access public
*/
function isComposite()
{
return true;
}

/**
* Sets this identification string for all of this composite's children.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.6.7
*/
function setIdent($ident)
{
/* Call our base class's setIdent() method. */
parent::setIdent($ident);

/* ... and then call setIdent() on all of our children. */
foreach ($this->_children as $id => $child) {
$this->_children[$id]->setIdent($ident);
}
}

/**
* Adds a Log instance to the list of children.
*
* @param object $child The Log instance to add.
*
* @return boolean True if the Log instance was successfully added.
*
* @access public
*/
function addChild(&$child)
{
/* Make sure this is a Log instance. */
if (!is_a($child, 'Log')) {
return false;
}

$this->_children[$child->_id] = &$child;

return true;
}

/**
* Removes a Log instance from the list of children.
*
* @param object $child The Log instance to remove.
*
* @return boolean True if the Log instance was successfully removed.
*
* @access public
*/
function removeChild($child)
{
if (!is_a($child, 'Log') || !isset($this->_children[$child->_id])) {
return false;
}

unset($this->_children[$child->_id]);

return true;
}

}

+ 202
- 0
trunk/docs/include/PEAR/Log/console.php Näytä tiedosto

@@ -0,0 +1,202 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/console.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_console class is a concrete implementation of the Log::
* abstract class which writes message to the text console.
*
* @author Jon Parise <jon@php.net>
* @since Log 1.1
* @package Log
*
* @example console.php Using the console handler.
*/
class Log_console extends Log
{
/**
* Handle to the current output stream.
* @var resource
* @access private
*/
var $_stream = STDOUT;

/**
* Should the output be buffered or displayed immediately?
* @var string
* @access private
*/
var $_buffering = false;

/**
* String holding the buffered output.
* @var string
* @access private
*/
var $_buffer = '';

/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%1$s %2$s [%3$s] %4$s';

/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';

/**
* Hash that maps canonical format keys to position arguments for the
* "line format" string.
* @var array
* @access private
*/
var $_formatMap = array('%{timestamp}' => '%1$s',
'%{ident}' => '%2$s',
'%{priority}' => '%3$s',
'%{message}' => '%4$s',
'%\{' => '%%{');

/**
* Constructs a new Log_console object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_console($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (!empty($conf['stream'])) {
$this->_stream = $conf['stream'];
}

if (isset($conf['buffering'])) {
$this->_buffering = $conf['buffering'];
}

if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}

if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}

/*
* If output buffering has been requested, we need to register a
* shutdown function that will dump the buffer upon termination.
*/
if ($this->_buffering) {
register_shutdown_function(array(&$this, '_Log_console'));
}
}

/**
* Destructor
*/
function _Log_console()
{
$this->close();
}

/**
* Closes the output stream.
*
* This results in a call to flush().
*
* @access public
* @since Log 1.9.0
*/
function close()
{
$this->flush();
}

/**
* Flushes all pending ("buffered") data to the output stream.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
/*
* If output buffering is enabled, dump the contents of the buffer to
* the output stream.
*/
if ($this->_buffering && (strlen($this->_buffer) > 0)) {
fwrite($this->_stream, $this->_buffer);
$this->_buffer = '';
}
return fflush($this->_stream);
}

/**
* Writes $message to the text console. Also, passes the message
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

/* Build the string containing the complete log line. */
$line = sprintf($this->_lineFormat, strftime($this->_timeFormat),
$this->_ident, $this->priorityToString($priority),
$message) . "\n";

/*
* If buffering is enabled, append this line to the output buffer.
* Otherwise, print the line to the output stream immediately.
*/
if ($this->_buffering) {
$this->_buffer .= $line;
} else {
fwrite($this->_stream, $line);
}

/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

}

+ 230
- 0
trunk/docs/include/PEAR/Log/daemon.php Näytä tiedosto

@@ -0,0 +1,230 @@
<?php
// $Id: daemon.php,v 1.1 2006/02/19 08:22:29 dennis Exp $

/**
* The Log_daemon class is a concrete implementation of the Log::
* abstract class which sends messages to syslog daemon on UNIX-like machines.
* This class uses the syslog protocol: http://www.ietf.org/rfc/rfc3164.txt
*
* @author Bart van der Schans <schans@dds.nl>
* @version $Revision: 1.1 $
* @package Log
*/
class Log_daemon extends Log
{
/**
* Integer holding the log facility to use.
* @var string
*/
var $_name = LOG_DAEMON;

/**
* Var holding the resource pointer to the socket
* @var resource
*/
var $_socket;

/**
* The ip address or servername
* @see http://www.php.net/manual/en/transports.php
* @var string
*/
var $_ip = '127.0.0.1';

/**
* Protocol to use (tcp, udp, etc.)
* @see http://www.php.net/manual/en/transports.php
* @var string
*/
var $_proto = 'udp';

/**
* Port to connect to
* @var int
*/
var $_port = 514;

/**
* Maximum message length in bytes
* @var int
*/
var $_maxsize = 4096;

/**
* Socket timeout in seconds
* @var int
*/
var $_timeout = 1;


/**
* Constructs a new syslog object.
*
* @param string $name The syslog facility.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $maxLevel Maximum level at which to log.
* @access public
*/
function Log_daemon($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
/* Ensure we have a valid integer value for $name. */
if (empty($name) || !is_int($name)) {
$name = LOG_SYSLOG;
}

$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (isset($conf['ip'])) {
$this->_ip = $conf['ip'];
}
if (isset($conf['proto'])) {
$this->_proto = $conf['proto'];
}
if (isset($conf['port'])) {
$this->_port = $conf['port'];
}
if (isset($conf['maxsize'])) {
$this->_maxsize = $conf['maxsize'];
}
if (isset($conf['timeout'])) {
$this->_timeout = $conf['timeout'];
}
$this->_proto = $this->_proto . '://';

register_shutdown_function(array(&$this, '_Log_daemon'));
}

/**
* Destructor.
*
* @access private
*/
function _Log_daemon()
{
$this->close();
}

/**
* Opens a connection to the system logger, if it has not already
* been opened. This is implicitly called by log(), if necessary.
* @access public
*/
function open()
{
if (!$this->_opened) {
$this->_opened = (bool)($this->_socket = @fsockopen(
$this->_proto . $this->_ip,
$this->_port,
$errno,
$errstr,
$this->_timeout));
}
return $this->_opened;
}

/**
* Closes the connection to the system logger, if it is open.
* @access public
*/
function close()
{
if ($this->_opened) {
$this->_opened = false;
return fclose($this->_socket);
}
return true;
}

/**
* Sends $message to the currently open syslog connection. Calls
* open() if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param string $message The textual message to be logged.
* @param int $priority (optional) The priority of the message. Valid
* values are: LOG_EMERG, LOG_ALERT, LOG_CRIT,
* LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO,
* and LOG_DEBUG. The default is LOG_INFO.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

/* Set the facility level. */
$facility_level = intval($this->_name) +
intval($this->_toSyslog($priority));

/* Prepend ident info. */
if (!empty($this->_ident)) {
$message = $this->_ident . ' ' . $message;
}

/* Check for message length. */
if (strlen($message) > $this->_maxsize) {
$message = substr($message, 0, ($this->_maxsize) - 10) . ' [...]';
}

/* Write to socket. */
fwrite($this->_socket, '<' . $facility_level . '>' . $message . "\n");

$this->_announce(array('priority' => $priority, 'message' => $message));
}

/**
* Converts a PEAR_LOG_* constant into a syslog LOG_* constant.
*
* This function exists because, under Windows, not all of the LOG_*
* constants have unique values. Instead, the PEAR_LOG_* were introduced
* for global use, with the conversion to the LOG_* constants kept local to
* to the syslog driver.
*
* @param int $priority PEAR_LOG_* value to convert to LOG_* value.
*
* @return The LOG_* representation of $priority.
*
* @access private
*/
function _toSyslog($priority)
{
static $priorities = array(
PEAR_LOG_EMERG => LOG_EMERG,
PEAR_LOG_ALERT => LOG_ALERT,
PEAR_LOG_CRIT => LOG_CRIT,
PEAR_LOG_ERR => LOG_ERR,
PEAR_LOG_WARNING => LOG_WARNING,
PEAR_LOG_NOTICE => LOG_NOTICE,
PEAR_LOG_INFO => LOG_INFO,
PEAR_LOG_DEBUG => LOG_DEBUG
);

/* If we're passed an unknown priority, default to LOG_INFO. */
if (!is_int($priority) || !in_array($priority, $priorities)) {
return LOG_INFO;
}

return $priorities[$priority];
}

}

+ 117
- 0
trunk/docs/include/PEAR/Log/display.php Näytä tiedosto

@@ -0,0 +1,117 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/display.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_display class is a concrete implementation of the Log::
* abstract class which writes message into browser in usual PHP maner.
* This may be useful because when you use PEAR::setErrorHandling in
* PEAR_ERROR_CALLBACK mode error messages are not displayed by
* PHP error handler.
*
* @author Paul Yanchenko <pusher@inaco.ru>
* @since Log 1.8.0
* @package Log
*
* @example display.php Using the display handler.
*/
class Log_display extends Log
{
/**
* String to output before an error message
* @var string
* @access private
*/
var $_error_prepend = '';

/**
* String to output after an error message
* @var string
* @access private
*/
var $_error_append = '';

/**
* String used to represent a line break.
* @var string
* @access private
*/
var $_linebreak = "<br />\n";

/**
* Constructs a new Log_display object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_display($name = '', $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (isset($conf['error_prepend'])) {
$this->_error_prepend = $conf['error_prepend'];
} else {
$this->_error_prepend = ini_get('error_prepend_string');
}

if (isset($conf['error_append'])) {
$this->_error_append = $conf['error_append'];
} else {
$this->_error_append = ini_get('error_append_string');
}

if (isset($conf['linebreak'])) {
$this->_linebreak = $conf['linebreak'];
}
}

/**
* Writes $message to the text browser. Also, passes the message
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

/* Build and output the complete log line. */
echo $this->_error_prepend .
'<b>' . ucfirst($this->priorityToString($priority)) . '</b>: '.
nl2br(htmlspecialchars($message)) .
$this->_error_append . $this->_linebreak;

/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

}

+ 103
- 0
trunk/docs/include/PEAR/Log/error_log.php Näytä tiedosto

@@ -0,0 +1,103 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/error_log.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_error_log class is a concrete implementation of the Log abstract
* class that logs messages using PHP's error_log() function.
*
* @author Jon Parise <jon@php.net>
* @since Log 1.7.0
* @package Log
*
* @example error_log.php Using the error_log handler.
*/
class Log_error_log extends Log
{
/**
* The error_log() log type.
* @var integer
* @access private
*/
var $_type = PEAR_LOG_TYPE_SYSTEM;

/**
* The type-specific destination value.
* @var string
* @access private
*/
var $_destination = '';

/**
* Additional headers to pass to the mail() function when the
* PEAR_LOG_TYPE_MAIL type is used.
* @var string
* @access private
*/
var $_extra_headers = '';

/**
* Constructs a new Log_error_log object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_error_log($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_type = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (!empty($conf['destination'])) {
$this->_destination = $conf['destination'];
}
if (!empty($conf['extra_headers'])) {
$this->_extra_headers = $conf['extra_headers'];
}
}

/**
* Logs $message using PHP's error_log() function. The message is also
* passed along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

$success = error_log($this->_ident . ': ' . $message, $this->_type,
$this->_destination, $this->_extra_headers);

$this->_announce(array('priority' => $priority, 'message' => $message));

return $success;
}

}

+ 324
- 0
trunk/docs/include/PEAR/Log/file.php Näytä tiedosto

@@ -0,0 +1,324 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/file.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_file class is a concrete implementation of the Log abstract
* class that logs messages to a text file.
*
* @author Jon Parise <jon@php.net>
* @author Roman Neuhauser <neuhauser@bellavista.cz>
* @since Log 1.0
* @package Log
*
* @example file.php Using the file handler.
*/
class Log_file extends Log
{
/**
* String containing the name of the log file.
* @var string
* @access private
*/
var $_filename = 'php.log';

/**
* Handle to the log file.
* @var resource
* @access private
*/
var $_fp = false;

/**
* Should new log entries be append to an existing log file, or should the
* a new log file overwrite an existing one?
* @var boolean
* @access private
*/
var $_append = true;

/**
* Should advisory file locking (i.e., flock()) be used?
* @var boolean
* @access private
*/
var $_locking = false;

/**
* Integer (in octal) containing the log file's permissions mode.
* @var integer
* @access private
*/
var $_mode = 0644;

/**
* Integer (in octal) specifying the file permission mode that will be
* used when creating directories that do not already exist.
* @var integer
* @access private
*/
var $_dirmode = 0755;

/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%1$s %2$s [%3$s] %4$s';

/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';

/**
* Hash that maps canonical format keys to position arguments for the
* "line format" string.
* @var array
* @access private
*/
var $_formatMap = array('%{timestamp}' => '%1$s',
'%{ident}' => '%2$s',
'%{priority}' => '%3$s',
'%{message}' => '%4$s',
'%\{' => '%%{');

/**
* String containing the end-on-line character sequence.
* @var string
* @access private
*/
var $_eol = "\n";

/**
* Constructs a new Log_file object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_file($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_filename = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (isset($conf['append'])) {
$this->_append = $conf['append'];
}

if (isset($conf['locking'])) {
$this->_locking = $conf['locking'];
}

if (!empty($conf['mode'])) {
if (is_string($conf['mode'])) {
$this->_mode = octdec($conf['mode']);
} else {
$this->_mode = $conf['mode'];
}
}

if (!empty($conf['dirmode'])) {
if (is_string($conf['dirmode'])) {
$this->_dirmode = octdec($conf['dirmode']);
} else {
$this->_dirmode = $conf['dirmode'];
}
}

if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}

if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}

if (!empty($conf['eol'])) {
$this->_eol = $conf['eol'];
} else {
$this->_eol = (strstr(PHP_OS, 'WIN')) ? "\r\n" : "\n";
}

register_shutdown_function(array(&$this, '_Log_file'));
}

/**
* Destructor
*/
function _Log_file()
{
if ($this->_opened) {
$this->close();
}
}

/**
* Creates the given directory path. If the parent directories don't
* already exist, they will be created, too.
*
* This implementation is inspired by Python's os.makedirs function.
*
* @param string $path The full directory path to create.
* @param integer $mode The permissions mode with which the
* directories will be created.
*
* @return True if the full path is successfully created or already
* exists.
*
* @access private
*/
function _mkpath($path, $mode = 0700)
{
/* Separate the last pathname component from the rest of the path. */
$head = dirname($path);
$tail = basename($path);

/* Make sure we've split the path into two complete components. */
if (empty($tail)) {
$head = dirname($path);
$tail = basename($path);
}

/* Recurse up the path if our current segment does not exist. */
if (!empty($head) && !empty($tail) && !is_dir($head)) {
$this->_mkpath($head, $mode);
}

/* Create this segment of the path. */
return @mkdir($head, $mode);
}

/**
* Opens the log file for output. If the specified log file does not
* already exist, it will be created. By default, new log entries are
* appended to the end of the log file.
*
* This is implicitly called by log(), if necessary.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
/* If the log file's directory doesn't exist, create it. */
if (!is_dir(dirname($this->_filename))) {
$this->_mkpath($this->_filename, $this->_dirmode);
}

/* Determine whether the log file needs to be created. */
$creating = !file_exists($this->_filename);

/* Obtain a handle to the log file. */
$this->_fp = fopen($this->_filename, ($this->_append) ? 'a' : 'w');

/* We consider the file "opened" if we have a valid file pointer. */
$this->_opened = ($this->_fp !== false);

/* Attempt to set the file's permissions if we just created it. */
if ($creating && $this->_opened) {
chmod($this->_filename, $this->_mode);
}
}

return $this->_opened;
}

/**
* Closes the log file if it is open.
*
* @access public
*/
function close()
{
/* If the log file is open, close it. */
if ($this->_opened && fclose($this->_fp)) {
$this->_opened = false;
}

return ($this->_opened === false);
}

/**
* Flushes all pending data to the file handle.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
return fflush($this->_fp);
}

/**
* Logs $message to the output window. The message is also passed along
* to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the log file isn't already open, open it now. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

/* Build the string containing the complete log line. */
$line = sprintf($this->_lineFormat, strftime($this->_timeFormat),
$this->_ident, $this->priorityToString($priority),
$message) . $this->_eol;

/* If locking is enabled, acquire an exclusive lock on the file. */
if ($this->_locking) {
flock($this->_fp, LOCK_EX);
}

/* Write the log line to the log file. */
$success = (fwrite($this->_fp, $line) !== false);

/* Unlock the file now that we're finished writing to it. */
if ($this->_locking) {
flock($this->_fp, LOCK_UN);
}

/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));

return $success;
}

}

+ 220
- 0
trunk/docs/include/PEAR/Log/mail.php Näytä tiedosto

@@ -0,0 +1,220 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/mail.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_mail class is a concrete implementation of the Log:: abstract class
* which sends log messages to a mailbox.
* The mail is actually sent when you close() the logger, or when the destructor
* is called (when the script is terminated).
*
* PLEASE NOTE that you must create a Log_mail object using =&, like this :
* $logger =& Log::factory("mail", "recipient@example.com", ...)
*
* This is a PEAR requirement for destructors to work properly.
* See http://pear.php.net/manual/en/class.pear.php
*
* @author Ronnie Garcia <ronnie@mk2.net>
* @author Jon Parise <jon@php.net>
* @since Log 1.3
* @package Log
*
* @example mail.php Using the mail handler.
*/
class Log_mail extends Log
{
/**
* String holding the recipient's email address.
* @var string
* @access private
*/
var $_recipient = '';

/**
* String holding the sender's email address.
* @var string
* @access private
*/
var $_from = '';

/**
* String holding the email's subject.
* @var string
* @access private
*/
var $_subject = '[Log_mail] Log message';

/**
* String holding an optional preamble for the log messages.
* @var string
* @access private
*/
var $_preamble = '';

/**
* String holding the mail message body.
* @var string
* @access private
*/
var $_message = '';


/**
* Constructs a new Log_mail object.
*
* Here is how you can customize the mail driver with the conf[] hash :
* $conf['from'] : the mail's "From" header line,
* $conf['subject'] : the mail's "Subject" line.
*
* @param string $name The filename of the logfile.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_mail($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_recipient = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (!empty($conf['from'])) {
$this->_from = $conf['from'];
} else {
$this->_from = ini_get('sendmail_from');
}

if (!empty($conf['subject'])) {
$this->_subject = $conf['subject'];
}

if (!empty($conf['preamble'])) {
$this->_preamble = $conf['preamble'];
}

/* register the destructor */
register_shutdown_function(array(&$this, '_Log_mail'));
}

/**
* Destructor. Calls close().
*
* @access private
*/
function _Log_mail()
{
$this->close();
}

/**
* Starts a new mail message.
* This is implicitly called by log(), if necessary.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
if (!empty($this->_preamble)) {
$this->_message = $this->_preamble . "\r\n\r\n";
}
$this->_opened = true;
}

return $this->_opened;
}

/**
* Closes the message, if it is open, and sends the mail.
* This is implicitly called by the destructor, if necessary.
*
* @access public
*/
function close()
{
if ($this->_opened) {
if (!empty($this->_message)) {
$headers = "From: $this->_from\r\n";
$headers .= "User-Agent: Log_mail";

if (mail($this->_recipient, $this->_subject, $this->_message,
$headers) == false) {
error_log("Log_mail: Failure executing mail()", 0);
return false;
}

/* Clear the message string now that the email has been sent. */
$this->_message = '';
}
$this->_opened = false;
}

return ($this->_opened === false);
}

/**
* Flushes the log output by forcing the email message to be sent now.
* Events that are logged after flush() is called will be appended to a
* new email message.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
/*
* It's sufficient to simply call close() to flush the output.
* The next call to log() will cause the handler to be reopened.
*/
return $this->close();
}

/**
* Writes $message to the currently open mail message.
* Calls open(), if necessary.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the message isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

$entry = sprintf("%s %s [%s] %s\r\n", strftime('%b %d %H:%M:%S'),
$this->_ident, Log::priorityToString($priority),
$message);

$this->_message .= $entry;

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}
}

+ 170
- 0
trunk/docs/include/PEAR/Log/mcal.php Näytä tiedosto

@@ -0,0 +1,170 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/mcal.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
* $Horde: horde/lib/Log/mcal.php,v 1.2 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_mcal class is a concrete implementation of the Log::
* abstract class which sends messages to a local or remote calendar
* store accessed through MCAL.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*/
class Log_mcal extends Log
{
/**
* holding the calendar specification to connect to.
* @var string
* @access private
*/
var $_calendar = '{localhost/mstore}';

/**
* holding the username to use.
* @var string
* @access private
*/
var $_username = '';

/**
* holding the password to use.
* @var string
* @access private
*/
var $_password = '';

/**
* holding the options to pass to the calendar stream.
* @var integer
* @access private
*/
var $_options = 0;

/**
* ResourceID of the MCAL stream.
* @var string
* @access private
*/
var $_stream = '';

/**
* Integer holding the log facility to use.
* @var string
* @access private
*/
var $_name = LOG_SYSLOG;


/**
* Constructs a new Log_mcal object.
*
* @param string $name The category to use for our events.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_mcal($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
$this->_calendar = $conf['calendar'];
$this->_username = $conf['username'];
$this->_password = $conf['password'];
$this->_options = $conf['options'];
}

/**
* Opens a calendar stream, if it has not already been
* opened. This is implicitly called by log(), if necessary.
* @access public
*/
function open()
{
if (!$this->_opened) {
$this->_stream = mcal_open($this->_calendar, $this->_username,
$this->_password, $this->_options);
$this->_opened = true;
}

return $this->_opened;
}

/**
* Closes the calendar stream, if it is open.
* @access public
*/
function close()
{
if ($this->_opened) {
mcal_close($this->_stream);
$this->_opened = false;
}

return ($this->_opened === false);
}

/**
* Logs $message and associated information to the currently open
* calendar stream. Calls open() if necessary. Also passes the
* message along to any Log_observer instances that are observing
* this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

$date_str = date('Y:n:j:G:i:s');
$dates = explode(':', $date_str);

mcal_event_init($this->_stream);
mcal_event_set_title($this->_stream, $this->_ident);
mcal_event_set_category($this->_stream, $this->_name);
mcal_event_set_description($this->_stream, $message);
mcal_event_add_attribute($this->_stream, 'priority', $priority);
mcal_event_set_start($this->_stream, $dates[0], $dates[1], $dates[2],
$dates[3], $dates[4], $dates[5]);
mcal_event_set_end($this->_stream, $dates[0], $dates[1], $dates[2],
$dates[3], $dates[4], $dates[5]);
mcal_append_event($this->_stream);

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

}

+ 358
- 0
trunk/docs/include/PEAR/Log/mdb2.php Näytä tiedosto

@@ -0,0 +1,358 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/mdb2.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/** PEAR's MDB2 package */
require_once 'MDB2.php';
MDB2::loadFile('Date');

/**
* The Log_mdb2 class is a concrete implementation of the Log:: abstract class
* which sends messages to an SQL server. Each entry occupies a separate row
* in the database.
*
* This implementation uses PEAR's MDB2 database abstraction layer.
*
* CREATE TABLE log_table (
* id INT NOT NULL,
* logtime TIMESTAMP NOT NULL,
* ident CHAR(16) NOT NULL,
* priority INT NOT NULL,
* message VARCHAR(200),
* PRIMARY KEY (id)
* );
*
* @author Lukas Smith <smith@backendmedia.com>
* @author Jon Parise <jon@php.net>
* @since Log 1.9.0
* @package Log
*/
class Log_mdb2 extends Log
{
/**
* Variable containing the DSN information.
* @var mixed
* @access private
*/
var $_dsn = '';

/**
* Array containing our set of DB configuration options.
* @var array
* @access private
*/
var $_options = array('persistent' => true);

/**
* Object holding the database handle.
* @var object
* @access private
*/
var $_db = null;

/**
* Resource holding the prepared statement handle.
* @var resource
* @access private
*/
var $_statement = null;

/**
* Flag indicating that we're using an existing database connection.
* @var boolean
* @access private
*/
var $_existingConnection = false;

/**
* String holding the database table to use.
* @var string
* @access private
*/
var $_table = 'log_table';

/**
* String holding the name of the ID sequence.
* @var string
* @access private
*/
var $_sequence = 'log_id';

/**
* Maximum length of the $ident string. This corresponds to the size of
* the 'ident' column in the SQL table.
* @var integer
* @access private
*/
var $_identLimit = 16;

/**
* Set of field types used in the database table.
* @var array
* @access private
*/
var $_types = array(
'id' => 'integer',
'logtime' => 'timestamp',
'ident' => 'text',
'priority' => 'text',
'message' => 'clob'
);

/**
* Constructs a new sql logging object.
*
* @param string $name The target SQL table.
* @param string $ident The identification field.
* @param array $conf The connection configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_mdb2($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_table = $name;
$this->_mask = Log::UPTO($level);

/* If an options array was provided, use it. */
if (isset($conf['options']) && is_array($conf['options'])) {
$this->_options = $conf['options'];
}

/* If a specific sequence name was provided, use it. */
if (!empty($conf['sequence'])) {
$this->_sequence = $conf['sequence'];
}

/* If a specific sequence name was provided, use it. */
if (isset($conf['identLimit'])) {
$this->_identLimit = $conf['identLimit'];
}

/* Now that the ident limit is confirmed, set the ident string. */
$this->setIdent($ident);

/* If an existing database connection was provided, use it. */
if (isset($conf['db'])) {
$this->_db = &$conf['db'];
$this->_existingConnection = true;
$this->_opened = true;
} elseif (isset($conf['singleton'])) {
$this->_db = &MDB2::singleton($conf['singleton'], $this->_options);
$this->_existingConnection = true;
$this->_opened = true;
} else {
$this->_dsn = $conf['dsn'];
}
}

/**
* Opens a connection to the database, if it has not already
* been opened. This is implicitly called by log(), if necessary.
*
* @return boolean True on success, false on failure.
* @access public
*/
function open()
{
if (!$this->_opened) {
/* Use the DSN and options to create a database connection. */
$this->_db = &MDB2::connect($this->_dsn, $this->_options);
if (PEAR::isError($this->_db)) {
return false;
}

/* Create a prepared statement for repeated use in log(). */
if (!$this->_prepareStatement()) {
return false;
}

/* We now consider out connection open. */
$this->_opened = true;
}

return $this->_opened;
}

/**
* Closes the connection to the database if it is still open and we were
* the ones that opened it. It is the caller's responsible to close an
* existing connection that was passed to us via $conf['db'].
*
* @return boolean True on success, false on failure.
* @access public
*/
function close()
{
/* If we have a statement object, free it. */
if (is_object($this->_statement)) {
$this->_statement->free();
$this->_statement = null;
}

/* If we opened the database connection, disconnect it. */
if ($this->_opened && !$this->_existingConnection) {
$this->_opened = false;
return $this->_db->disconnect();
}

return ($this->_opened === false);
}

/**
* Sets this Log instance's identification string. Note that this
* SQL-specific implementation will limit the length of the $ident string
* to sixteen (16) characters.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.8.5
*/
function setIdent($ident)
{
$this->_ident = substr($ident, 0, $this->_identLimit);
}

/**
* Inserts $message to the currently open database. Calls open(),
* if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* If we don't already have a statement object, create one. */
if (!is_object($this->_statement) && !$this->_prepareStatement()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

/* Build our set of values for this log entry. */
$values = array(
'id' => $this->_db->nextId($this->_sequence),
'logtime' => MDB2_Date::mdbNow(),
'ident' => $this->_ident,
'priority' => $priority,
'message' => $message
);

/* Execute the SQL query for this log entry insertion. */
$this->_db->expectError(MDB2_ERROR_NOSUCHTABLE);
$result = &$this->_statement->execute($values);
$this->_db->popExpect();

/* Attempt to handle any errors. */
if (PEAR::isError($result)) {
/* We can only handle MDB2_ERROR_NOSUCHTABLE errors. */
if ($result->getCode() != MDB2_ERROR_NOSUCHTABLE) {
return false;
}

/* Attempt to create the target table. */
if (!$this->_createTable()) {
return false;
}

/* Recreate our prepared statement resource. */
$this->_statement->free();
if (!$this->_prepareStatement()) {
return false;
}

/* Attempt to re-execute the insertion query. */
$result = $this->_statement->execute($values);
if (PEAR::isError($result)) {
return false;
}
}

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

/**
* Create the log table in the database.
*
* @return boolean True on success or false on failure.
* @access private
*/
function _createTable()
{
$this->_db->loadModule('Manager');
$result = $this->_db->manager->createTable(
$this->_table,
array(
'id' => array('type' => $this->_types['id']),
'logtime' => array('type' => $this->_types['logtime']),
'ident' => array('type' => $this->_types['ident']),
'priority' => array('type' => $this->_types['priority']),
'message' => array('type' => $this->_types['message'])
)
);
if (PEAR::isError($result)) {
return false;
}

$result = $this->_db->manager->createIndex(
$this->_table,
'unique_id',
array('fields' => array('id' => true), 'unique' => true)
);
if (PEAR::isError($result)) {
return false;
}

return true;
}

/**
* Prepare the SQL insertion statement.
*
* @return boolean True if the statement was successfully created.
*
* @access private
* @since Log 1.9.0
*/
function _prepareStatement()
{
$this->_statement = &$this->_db->prepare(
'INSERT INTO ' . $this->_table .
' (id, logtime, ident, priority, message)' .
' VALUES(:id, :logtime, :ident, :priority, :message)',
$this->_types);

/* Return success if we didn't generate an error. */
return (PEAR::isError($this->_statement) === false);
}
}

+ 67
- 0
trunk/docs/include/PEAR/Log/null.php Näytä tiedosto

@@ -0,0 +1,67 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/null.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_null class is a concrete implementation of the Log:: abstract
* class. It simply consumes log events.
*
* @author Jon Parise <jon@php.net>
* @since Log 1.8.2
* @package Log
*
* @example null.php Using the null handler.
*/
class Log_null extends Log
{
/**
* Constructs a new Log_null object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_null($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
}

/**
* Simply consumes the log event. The message will still be passed
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

}

+ 125
- 0
trunk/docs/include/PEAR/Log/observer.php Näytä tiedosto

@@ -0,0 +1,125 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/observer.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
* $Horde: horde/lib/Log/observer.php,v 1.5 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_observer:: class implements the Observer end of a Subject-Observer
* pattern for watching log activity and taking actions on exceptional events.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example observer_mail.php An example Log_observer implementation.
*/
class Log_observer
{
/**
* Instance-specific unique identification number.
*
* @var integer
* @access private
*/
var $_id = 0;

/**
* The minimum priority level of message that we want to hear about.
* PEAR_LOG_EMERG is the highest priority, so we will only hear messages
* with an integer priority value less than or equal to ours. It defaults
* to PEAR_LOG_INFO, which listens to everything except PEAR_LOG_DEBUG.
*
* @var string
* @access private
*/
var $_priority = PEAR_LOG_INFO;

/**
* Creates a new basic Log_observer instance.
*
* @param integer $priority The highest priority at which to receive
* log event notifications.
*
* @access public
*/
function Log_observer($priority = PEAR_LOG_INFO)
{
$this->_id = md5(microtime());
$this->_priority = $priority;
}

/**
* Attempts to return a new concrete Log_observer instance of the requested
* type.
*
* @param string $type The type of concreate Log_observer subclass
* to return.
* @param integer $priority The highest priority at which to receive
* log event notifications.
* @param array $conf Optional associative array of additional
* configuration values.
*
* @return object The newly created concrete Log_observer
* instance, or null on an error.
*/
function &factory($type, $priority = PEAR_LOG_INFO, $conf = array())
{
$type = strtolower($type);
$class = 'Log_observer_' . $type;

/* Support both the new-style and old-style file naming conventions. */
if (file_exists(dirname(__FILE__) . '/observer_' . $type . '.php')) {
$classfile = 'Log/observer_' . $type . '.php';
$newstyle = true;
} else {
$classfile = 'Log/' . $type . '.php';
$newstyle = false;
}

/* Issue a warning if the old-style conventions are being used. */
if (!$newstyle)
{
trigger_error('Using old-style Log_observer conventions',
E_USER_WARNING);
}

/*
* Attempt to include our version of the named class, but don't treat
* a failure as fatal. The caller may have already included their own
* version of the named class.
*/
@include_once $classfile;

/* If the class exists, return a new instance of it. */
if (class_exists($class)) {
/* Support both new-style and old-style construction. */
if ($newstyle) {
$object =& new $class($priority, $conf);
} else {
$object =& new $class($priority);
}
return $object;
}

return null;
}

/**
* This is a stub method to make sure that Log_Observer classes do
* something when they are notified of a message. The default behavior
* is to just print the message, which is obviously not desireable in
* practically any situation - which is why you need to override this
* method. :)
*
* @param array $event A hash describing the log event.
*/
function notify($event)
{
print_r($event);
}
}

+ 287
- 0
trunk/docs/include/PEAR/Log/sql.php Näytä tiedosto

@@ -0,0 +1,287 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/sql.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
* $Horde: horde/lib/Log/sql.php,v 1.12 2000/08/16 20:27:34 chuck Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/** PEAR's DB package */
require_once 'DB.php';

/**
* The Log_sql class is a concrete implementation of the Log::
* abstract class which sends messages to an SQL server. Each entry
* occupies a separate row in the database.
*
* This implementation uses PHP's PEAR database abstraction layer.
*
* CREATE TABLE log_table (
* id INT NOT NULL,
* logtime TIMESTAMP NOT NULL,
* ident CHAR(16) NOT NULL,
* priority INT NOT NULL,
* message VARCHAR(200),
* PRIMARY KEY (id)
* );
*
* @author Jon Parise <jon@php.net>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example sql.php Using the SQL handler.
*/
class Log_sql extends Log
{
/**
* Variable containing the DSN information.
* @var mixed
* @access private
*/
var $_dsn = '';

/**
* String containing the SQL insertion statement.
*
* @var string
* @access private
*/
var $_sql = '';

/**
* Array containing our set of DB configuration options.
* @var array
* @access private
*/
var $_options = array('persistent' => true);

/**
* Object holding the database handle.
* @var object
* @access private
*/
var $_db = null;

/**
* Resource holding the prepared statement handle.
* @var resource
* @access private
*/
var $_statement = null;

/**
* Flag indicating that we're using an existing database connection.
* @var boolean
* @access private
*/
var $_existingConnection = false;

/**
* String holding the database table to use.
* @var string
* @access private
*/
var $_table = 'log_table';

/**
* String holding the name of the ID sequence.
* @var string
* @access private
*/
var $_sequence = 'log_id';

/**
* Maximum length of the $ident string. This corresponds to the size of
* the 'ident' column in the SQL table.
* @var integer
* @access private
*/
var $_identLimit = 16;


/**
* Constructs a new sql logging object.
*
* @param string $name The target SQL table.
* @param string $ident The identification field.
* @param array $conf The connection configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_sql($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_table = $name;
$this->_mask = Log::UPTO($level);

/* Now that we have a table name, assign our SQL statement. */
if (!empty($this->_sql)) {
$this->_sql = $conf['sql'];
} else {
$this->_sql = 'INSERT INTO ' . $this->_table .
' (id, logtime, ident, priority, message)' .
' VALUES(?, CURRENT_TIMESTAMP, ?, ?, ?)';
}

/* If an options array was provided, use it. */
if (isset($conf['options']) && is_array($conf['options'])) {
$this->_options = $conf['options'];
}

/* If a specific sequence name was provided, use it. */
if (!empty($conf['sequence'])) {
$this->_sequence = $conf['sequence'];
}

/* If a specific sequence name was provided, use it. */
if (isset($conf['identLimit'])) {
$this->_identLimit = $conf['identLimit'];
}

/* Now that the ident limit is confirmed, set the ident string. */
$this->setIdent($ident);

/* If an existing database connection was provided, use it. */
if (isset($conf['db'])) {
$this->_db = &$conf['db'];
$this->_existingConnection = true;
$this->_opened = true;
} else {
$this->_dsn = $conf['dsn'];
}
}

/**
* Opens a connection to the database, if it has not already
* been opened. This is implicitly called by log(), if necessary.
*
* @return boolean True on success, false on failure.
* @access public
*/
function open()
{
if (!$this->_opened) {
/* Use the DSN and options to create a database connection. */
$this->_db = &DB::connect($this->_dsn, $this->_options);
if (DB::isError($this->_db)) {
return false;
}

/* Create a prepared statement for repeated use in log(). */
if (!$this->_prepareStatement()) {
return false;
}

/* We now consider out connection open. */
$this->_opened = true;
}

return $this->_opened;
}

/**
* Closes the connection to the database if it is still open and we were
* the ones that opened it. It is the caller's responsible to close an
* existing connection that was passed to us via $conf['db'].
*
* @return boolean True on success, false on failure.
* @access public
*/
function close()
{
if ($this->_opened && !$this->_existingConnection) {
$this->_opened = false;
$this->_db->freePrepared($this->_statement);
return $this->_db->disconnect();
}

return ($this->_opened === false);
}

/**
* Sets this Log instance's identification string. Note that this
* SQL-specific implementation will limit the length of the $ident string
* to sixteen (16) characters.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.8.5
*/
function setIdent($ident)
{
$this->_ident = substr($ident, 0, $this->_identLimit);
}

/**
* Inserts $message to the currently open database. Calls open(),
* if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* If we don't already have our statement object yet, create it. */
if (!is_object($this->_statement) && !$this->_prepareStatement()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

/* Build our set of values for this log entry. */
$id = $this->_db->nextId($this->_sequence);
$values = array($id, $this->_ident, $priority, $message);

/* Execute the SQL query for this log entry insertion. */
$result =& $this->_db->execute($this->_statement, $values);
if (DB::isError($result)) {
return false;
}

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

/**
* Prepare the SQL insertion statement.
*
* @return boolean True if the statement was successfully created.
*
* @access private
* @since Log 1.9.1
*/
function _prepareStatement()
{
$this->_statement = $this->_db->prepare($this->_sql);

/* Return success if we didn't generate an error. */
return (DB::isError($this->_statement) === false);
}
}

+ 225
- 0
trunk/docs/include/PEAR/Log/sqlite.php Näytä tiedosto

@@ -0,0 +1,225 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/sqlite.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_sqlite class is a concrete implementation of the Log::
* abstract class which sends messages to an Sqlite database.
* Each entry occupies a separate row in the database.
*
* This implementation uses PHP native Sqlite functions.
*
* CREATE TABLE log_table (
* id INTEGER PRIMARY KEY NOT NULL,
* logtime NOT NULL,
* ident CHAR(16) NOT NULL,
* priority INT NOT NULL,
* message
* );
*
* @author Bertrand Mansion <bmansion@mamasam.com>
* @author Jon Parise <jon@php.net>
* @since Log 1.8.3
* @package Log
*
* @example sqlite.php Using the Sqlite handler.
*/
class Log_sqlite extends Log
{
/**
* Array containing the connection defaults
* @var array
* @access private
*/
var $_options = array('mode' => 0666,
'persistent' => false);

/**
* Object holding the database handle.
* @var object
* @access private
*/
var $_db = null;

/**
* Flag indicating that we're using an existing database connection.
* @var boolean
* @access private
*/
var $_existingConnection = false;

/**
* String holding the database table to use.
* @var string
* @access private
*/
var $_table = 'log_table';


/**
* Constructs a new sql logging object.
*
* @param string $name The target SQL table.
* @param string $ident The identification field.
* @param mixed $conf Can be an array of configuration options used
* to open a new database connection
* or an already opened sqlite connection.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_sqlite($name, $ident = '', &$conf, $level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_table = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (is_array($conf)) {
foreach ($conf as $k => $opt) {
$this->_options[$k] = $opt;
}
} else {
// If an existing database connection was provided, use it.
$this->_db =& $conf;
$this->_existingConnection = true;
}
}

/**
* Opens a connection to the database, if it has not already
* been opened. This is implicitly called by log(), if necessary.
*
* @return boolean True on success, false on failure.
* @access public
*/
function open()
{
if (is_resource($this->_db)) {
$this->_opened = true;
return $this->_createTable();
} else {
/* Set the connection function based on the 'persistent' option. */
if (empty($this->_options['persistent'])) {
$connectFunction = 'sqlite_open';
} else {
$connectFunction = 'sqlite_popen';
}

/* Attempt to connect to the database. */
if ($this->_db = $connectFunction($this->_options['filename'],
(int)$this->_options['mode'],
$error)) {
$this->_opened = true;
return $this->_createTable();
}
}

return $this->_opened;
}

/**
* Closes the connection to the database if it is still open and we were
* the ones that opened it. It is the caller's responsible to close an
* existing connection that was passed to us via $conf['db'].
*
* @return boolean True on success, false on failure.
* @access public
*/
function close()
{
/* We never close existing connections. */
if ($this->_existingConnection) {
return false;
}

if ($this->_opened) {
$this->_opened = false;
sqlite_close($this->_db);
}

return ($this->_opened === false);
}

/**
* Inserts $message to the currently open database. Calls open(),
* if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

// Extract the string representation of the message.
$message = $this->_extractMessage($message);

// Build the SQL query for this log entry insertion.
$q = sprintf('INSERT INTO [%s] (logtime, ident, priority, message) ' .
"VALUES ('%s', '%s', %d, '%s')",
$this->_table,
strftime('%Y-%m-%d %H:%M:%S', time()),
sqlite_escape_string($this->_ident),
$priority,
sqlite_escape_string($message));
if (!($res = @sqlite_unbuffered_query($this->_db, $q))) {
return false;
}
$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

/**
* Checks whether the log table exists and creates it if necessary.
*
* @return boolean True on success or false on failure.
* @access private
*/
function _createTable()
{
$q = "SELECT name FROM sqlite_master WHERE name='" . $this->_table .
"' AND type='table'";

$res = sqlite_query($this->_db, $q);

if (sqlite_num_rows($res) == 0) {
$q = 'CREATE TABLE [' . $this->_table . '] (' .
'id INTEGER PRIMARY KEY NOT NULL, ' .
'logtime NOT NULL, ' .
'ident CHAR(16) NOT NULL, ' .
'priority INT NOT NULL, ' .
'message)';

if (!($res = sqlite_unbuffered_query($this->_db, $q))) {
return false;
}
}

return true;
}

}

+ 160
- 0
trunk/docs/include/PEAR/Log/syslog.php Näytä tiedosto

@@ -0,0 +1,160 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/syslog.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
* $Horde: horde/lib/Log/syslog.php,v 1.6 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_syslog class is a concrete implementation of the Log::
* abstract class which sends messages to syslog on UNIX-like machines
* (PHP emulates this with the Event Log on Windows machines).
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example syslog.php Using the syslog handler.
*/
class Log_syslog extends Log
{
/**
* Integer holding the log facility to use.
* @var string
* @access private
*/
var $_name = LOG_SYSLOG;

/**
* Constructs a new syslog object.
*
* @param string $name The syslog facility.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_syslog($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
/* Ensure we have a valid integer value for $name. */
if (empty($name) || !is_int($name)) {
$name = LOG_SYSLOG;
}

$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
}

/**
* Opens a connection to the system logger, if it has not already
* been opened. This is implicitly called by log(), if necessary.
* @access public
*/
function open()
{
if (!$this->_opened) {
openlog($this->_ident, LOG_PID, $this->_name);
$this->_opened = true;
}

return $this->_opened;
}

/**
* Closes the connection to the system logger, if it is open.
* @access public
*/
function close()
{
if ($this->_opened) {
closelog();
$this->_opened = false;
}

return ($this->_opened === false);
}

/**
* Sends $message to the currently open syslog connection. Calls
* open() if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param int $priority (optional) The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

if (!syslog($this->_toSyslog($priority), $message)) {
return false;
}

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

/**
* Converts a PEAR_LOG_* constant into a syslog LOG_* constant.
*
* This function exists because, under Windows, not all of the LOG_*
* constants have unique values. Instead, the PEAR_LOG_* were introduced
* for global use, with the conversion to the LOG_* constants kept local to
* to the syslog driver.
*
* @param int $priority PEAR_LOG_* value to convert to LOG_* value.
*
* @return The LOG_* representation of $priority.
*
* @access private
*/
function _toSyslog($priority)
{
static $priorities = array(
PEAR_LOG_EMERG => LOG_EMERG,
PEAR_LOG_ALERT => LOG_ALERT,
PEAR_LOG_CRIT => LOG_CRIT,
PEAR_LOG_ERR => LOG_ERR,
PEAR_LOG_WARNING => LOG_WARNING,
PEAR_LOG_NOTICE => LOG_NOTICE,
PEAR_LOG_INFO => LOG_INFO,
PEAR_LOG_DEBUG => LOG_DEBUG
);

/* If we're passed an unknown priority, default to LOG_INFO. */
if (!is_int($priority) || !in_array($priority, $priorities)) {
return LOG_INFO;
}

return $priorities[$priority];
}

}

+ 255
- 0
trunk/docs/include/PEAR/Log/win.php Näytä tiedosto

@@ -0,0 +1,255 @@
<?php
/**
* $Header: /home/ppcvs/paypal_php_sdk/Log/win.php,v 1.1 2006/02/19 08:22:29 dennis Exp $
*
* @version $Revision: 1.1 $
* @package Log
*/

/**
* The Log_win class is a concrete implementation of the Log abstract
* class that logs messages to a separate browser window.
*
* The concept for this log handler is based on part by Craig Davis' article
* entitled "JavaScript Power PHP Debugging:
*
* http://www.zend.com/zend/tut/tutorial-DebugLib.php
*
* @author Jon Parise <jon@php.net>
* @since Log 1.7.0
* @package Log
*
* @example win.php Using the window handler.
*/
class Log_win extends Log
{
/**
* The name of the output window.
* @var string
* @access private
*/
var $_name = 'LogWindow';

/**
* The title of the output window.
* @var string
* @access private
*/
var $_title = 'Log Output Window';

/**
* Mapping of log priorities to colors.
* @var array
* @access private
*/
var $_colors = array(
PEAR_LOG_EMERG => 'red',
PEAR_LOG_ALERT => 'orange',
PEAR_LOG_CRIT => 'yellow',
PEAR_LOG_ERR => 'green',
PEAR_LOG_WARNING => 'blue',
PEAR_LOG_NOTICE => 'indigo',
PEAR_LOG_INFO => 'violet',
PEAR_LOG_DEBUG => 'black'
);

/**
* String buffer that holds line that are pending output.
* @var array
* @access private
*/
var $_buffer = array();

/**
* Constructs a new Log_win object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_win($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);

if (isset($conf['title'])) {
$this->_title = $conf['title'];
}
if (isset($conf['colors']) && is_array($conf['colors'])) {
$this->_colors = $conf['colors'];
}

register_shutdown_function(array(&$this, '_Log_win'));
}

/**
* Destructor
*/
function _Log_win()
{
if ($this->_opened || (count($this->_buffer) > 0)) {
$this->close();
}
}

/**
* The first time open() is called, it will open a new browser window and
* prepare it for output.
*
* This is implicitly called by log(), if necessary.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
$win = $this->_name;

if (!empty($this->_ident)) {
$identHeader = "$win.document.writeln('<th>Ident</th>')";
} else {
$identHeader = '';
}

echo <<< END_OF_SCRIPT
<script language="JavaScript">
$win = window.open('', '{$this->_name}', 'toolbar=no,scrollbars,width=600,height=400');
$win.document.writeln('<html>');
$win.document.writeln('<head>');
$win.document.writeln('<title>{$this->_title}</title>');
$win.document.writeln('<style type="text/css">');
$win.document.writeln('body { font-family: monospace; font-size: 8pt; }');
$win.document.writeln('td,th { font-size: 8pt; }');
$win.document.writeln('td,th { border-bottom: #999999 solid 1px; }');
$win.document.writeln('td,th { border-right: #999999 solid 1px; }');
$win.document.writeln('</style>');
$win.document.writeln('</head>');
$win.document.writeln('<body>');
$win.document.writeln('<table border="0" cellpadding="2" cellspacing="0">');
$win.document.writeln('<tr><th>Time</th>');
$identHeader
$win.document.writeln('<th>Priority</th><th width="100%">Message</th></tr>');
</script>
END_OF_SCRIPT;
$this->_opened = true;
}

return $this->_opened;
}

/**
* Closes the output stream if it is open. If there are still pending
* lines in the output buffer, the output window will be opened so that
* the buffer can be drained.
*
* @access public
*/
function close()
{
/*
* If there are still lines waiting to be written, open the output
* window so that we can drain the buffer.
*/
if (!$this->_opened && (count($this->_buffer) > 0)) {
$this->open();
}

if ($this->_opened) {
$this->_writeln('</table>');
$this->_writeln('</body></html>');
$this->_opened = false;
}

return ($this->_opened === false);
}

/**
* Writes a single line of text to the output window.
*
* @param string $line The line of text to write.
*
* @access private
*/
function _writeln($line)
{
/* Add this line to our output buffer. */
$this->_buffer[] = $line;

/* Buffer the output until this page's headers have been sent. */
if (!headers_sent()) {
return;
}

/* If we haven't already opened the output window, do so now. */
if (!$this->_opened && !$this->open()) {
return false;
}

/* Drain the buffer to the output window. */
$win = $this->_name;
foreach ($this->_buffer as $line) {
echo "<script language='JavaScript'>\n";
echo "$win.document.writeln('" . addslashes($line) . "');\n";
echo "self.focus();\n";
echo "</script>\n";
}

/* Now that the buffer has been drained, clear it. */
$this->_buffer = array();
}

/**
* Logs $message to the output window. The message is also passed along
* to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}

/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}

/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);

list($usec, $sec) = explode(' ', microtime());

/* Build the output line that contains the log entry row. */
$line = '<tr align="left" valign="top">';
$line .= sprintf('<td>%s.%s</td>',
strftime('%T', $sec), substr($usec, 2, 2));
if (!empty($this->_ident)) {
$line .= '<td>' . $this->_ident . '</td>';
}
$line .= '<td>' . ucfirst($this->priorityToString($priority)) . '</td>';
$line .= sprintf('<td style="color: %s">%s</td>',
$this->_colors[$priority],
preg_replace('/\r\n|\n|\r/', '<br />', $message));
$line .= '</tr>';

$this->_writeln($line);

$this->_announce(array('priority' => $priority, 'message' => $message));

return true;
}

}

+ 4211
- 0
trunk/docs/include/PEAR/MDB2.php
File diff suppressed because it is too large
Näytä tiedosto


+ 183
- 0
trunk/docs/include/PEAR/MDB2/Date.php Näytä tiedosto

@@ -0,0 +1,183 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Date.php,v 1.10 2006/03/01 12:15:32 lsmith Exp $
//

/**
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/

/**
* 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 <smith@pooteeweet.org>
*/
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;
}
// }}}
}

?>

BIN
trunk/docs/include/PEAR/MDB2/Driver/Datatype/.Common.php.swp Näytä tiedosto


+ 1672
- 0
trunk/docs/include/PEAR/MDB2/Driver/Datatype/Common.php
File diff suppressed because it is too large
Näytä tiedosto


+ 426
- 0
trunk/docs/include/PEAR/MDB2/Driver/Datatype/mysql.php Näytä tiedosto

@@ -0,0 +1,426 @@
<?php
// vim: set et ts=4 sw=4 fdm=marker:
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.51 2006/08/12 15:58:19 lsmith Exp $
//

require_once 'MDB2/Driver/Datatype/Common.php';

/**
* MDB2 MySQL driver
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Driver_Datatype_mysql extends MDB2_Driver_Datatype_Common
{
// }}}
// {{{ 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':
if (empty($field['length']) && array_key_exists('default', $field)) {
$field['length'] = $db->varchar_max_length;
}
$length = !empty($field['length']) ? $field['length'] : false;
$fixed = !empty($field['fixed']) ? $field['fixed'] : false;
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
: ($length ? 'VARCHAR('.$length.')' : 'TEXT');
case 'clob':
if (!empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYTEXT';
} elseif ($length <= 65535) {
return 'TEXT';
} elseif ($length <= 16777215) {
return 'MEDIUMTEXT';
}
}
return 'LONGTEXT';
case 'blob':
if (!empty($field['length'])) {
$length = $field['length'];
if ($length <= 255) {
return 'TINYBLOB';
} elseif ($length <= 65535) {
return 'BLOB';
} elseif ($length <= 16777215) {
return 'MEDIUMBLOB';
}
}
return 'LONGBLOB';
case 'integer':
if (!empty($field['length'])) {
$length = $field['length'];
if ($length <= 1) {
return 'TINYINT';
} elseif ($length == 2) {
return 'SMALLINT';
} elseif ($length == 3) {
return 'MEDIUMINT';
} elseif ($length == 4) {
return 'INT';
} elseif ($length > 4) {
return 'BIGINT';
}
}
return 'INT';
case 'boolean':
return 'TINYINT(1)';
case 'date':
return 'DATE';
case 'time':
return 'TIME';
case 'timestamp':
return 'DATETIME';
case 'float':
return 'DOUBLE';
case 'decimal':
$length = !empty($field['length']) ? $field['length'] : 18;
return 'DECIMAL('.$length.','.$db->options['decimal_places'].')';
}
return '';
}

// }}}
// {{{ _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 string $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)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$default = $autoinc = '';;
if (!empty($field['autoincrement'])) {
$autoinc = ' AUTO_INCREMENT PRIMARY KEY';
} elseif (array_key_exists('default', $field)) {
if ($field['default'] === '') {
$field['default'] = empty($field['notnull']) ? null : 0;
}
$default = ' DEFAULT '.$this->quote($field['default'], 'integer');
} elseif (empty($field['notnull'])) {
$default = ' DEFAULT NULL';
}

$notnull = empty($field['notnull']) ? '' : ' NOT NULL';
$unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
$name = $db->quoteIdentifier($name, true);
return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
}

// }}}
// {{{ matchPattern()

/**
* build a pattern matching string
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental
*
* @access public
*
* @param array $pattern even keys are strings, odd are patterns (% and _)
* @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future)
* @param string $field optional field name that is being matched against
* (might be required when emulating ILIKE)
*
* @return string SQL pattern
*/
function matchPattern($pattern, $operator = null, $field = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$match = '';
if (!is_null($operator)) {
$field = is_null($field) ? '' : $field.' ';
$operator = strtoupper($operator);
switch ($operator) {
// case insensitive
case 'ILIKE':
$match = $field.'LIKE ';
break;
// case sensitive
case 'LIKE':
$match = $field.'LIKE BINARY ';
break;
default:
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'not a supported operator type:'. $operator, __FUNCTION__);
}
}
$match.= "'";
foreach ($pattern as $key => $value) {
if ($key % 2) {
$match.= $value;
} else {
$match.= $db->escapePattern($db->escape($value));
}
}
$match.= "'";
$match.= $this->patternEscapeString();
return $match;
}

// }}}
// {{{ mapNativeDatatype()

/**
* Maps a native array description of a field to a MDB2 datatype and length
*
* @param array $field native field description
* @return array containing the various possible types, length, sign, fixed
* @access public
*/
function mapNativeDatatype($field)
{
$db_type = strtolower($field['type']);
$db_type = strtok($db_type, '(), ');
if ($db_type == 'national') {
$db_type = strtok('(), ');
}
if (!empty($field['length'])) {
$length = $field['length'];
$decimal = '';
} else {
$length = strtok('(), ');
$decimal = strtok('(), ');
}
$type = array();
$unsigned = $fixed = null;
switch ($db_type) {
case 'tinyint':
$type[] = 'integer';
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 1;
break;
case 'smallint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 2;
break;
case 'mediumint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 3;
break;
case 'int':
case 'integer':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 4;
break;
case 'bigint':
$type[] = 'integer';
$unsigned = preg_match('/ unsigned/i', $field['type']);
$length = 8;
break;
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'text':
case 'varchar':
$fixed = false;
case 'string':
case 'char':
$type[] = 'text';
if ($length == '1') {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($db_type, 'text')) {
$type[] = 'clob';
if ($decimal == 'binary') {
$type[] = 'blob';
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'enum':
$type[] = 'text';
preg_match_all('/\'.+\'/U', $field['type'], $matches);
$length = 0;
$fixed = false;
if (is_array($matches)) {
foreach ($matches[0] as $value) {
$length = max($length, strlen($value)-2);
}
if ($length == '1' && count($matches[0]) == 2) {
$type[] = 'boolean';
if (preg_match('/^(is|has)/', $field['name'])) {
$type = array_reverse($type);
}
}
}
$type[] = 'integer';
case 'set':
$fixed = false;
$type[] = 'text';
$type[] = 'integer';
break;
case 'date':
$type[] = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type[] = 'timestamp';
$length = null;
break;
case 'time':
$type[] = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type[] = 'float';
$unsigned = preg_match('/ unsigned/i', $field['type']);
break;
case 'unknown':
case 'decimal':
case 'numeric':
$type[] = 'decimal';
$unsigned = preg_match('/ unsigned/i', $field['type']);
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
$type[] = 'blob';
$length = null;
break;
case 'year':
$type[] = 'integer';
$type[] = 'date';
$length = null;
break;
default:
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'unknown database attribute type: '.$db_type, __FUNCTION__);
}

return array($type, $length, $unsigned, $fixed);
}
}

?>

+ 210
- 0
trunk/docs/include/PEAR/MDB2/Driver/Function/Common.php Näytä tiedosto

@@ -0,0 +1,210 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.16 2006/08/07 20:15:21 lsmith Exp $
//

/**
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/

/**
* Base class for the function modules that is extended by each MDB2 driver
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
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,
'method not implemented', __FUNCTION__);
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 concatenate two strings
* @access public
*/
function concat($value1, $value2)
{
$args = func_get_args();
return "(".implode(' || ', $args).")";
}

// }}}
// {{{ random()

/**
* return string to call a function to get random value inside an SQL statement
*
* @return return string to generate float between 0 and 1
* @access public
*/
function random()
{
return 'RAND()';
}

// }}}
// {{{ lower()

/**
* return string to call a function to lower the case of an expression
*
* @param string $expression
* @return return string to lower case of an expression
* @access public
*/
function lower($expression)
{
return "LOWER($expression)";
}

// }}}
// {{{ upper()

/**
* return string to call a function to upper the case of an expression
*
* @param string $expression
* @return return string to upper case of an expression
* @access public
*/
function upper($expression)
{
return "UPPER($expression)";
}

// }}}
}
?>

+ 104
- 0
trunk/docs/include/PEAR/MDB2/Driver/Function/mysql.php Näytä tiedosto

@@ -0,0 +1,104 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.10 2006/06/12 21:48:43 lsmith Exp $
//

require_once 'MDB2/Driver/Function/Common.php';

/**
* MDB2 MySQL driver for the function modules
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Driver_Function_mysql extends MDB2_Driver_Function_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;
}

$query = 'CALL '.$name;
$query .= $params ? '('.implode(', ', $params).')' : '()';
return $db->query($query, $types, $result_class, $result_wrap_class);
}

// }}}
// {{{ concat()

/**
* Returns string to concatenate two or more string parameters
*
* @param string $value1
* @param string $value2
* @param string $values...
* @return string to concatenate two strings
* @access public
**/
function concat($value1, $value2)
{
$args = func_get_args();
return "CONCAT(".implode(', ', $args).")";
}
}
?>

+ 805
- 0
trunk/docs/include/PEAR/MDB2/Driver/Manager/Common.php Näytä tiedosto

@@ -0,0 +1,805 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.56 2006/08/21 16:18:10 nrf Exp $
//

/**
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/

/**
* Base class for the management modules that is extended by each MDB2 driver
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
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) || empty($fields)) {
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
'missing any fields', __FUNCTION__);
}

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);
}

// }}}
// {{{ _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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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.
* array(
* 'id' => array(
* 'type' => 'integer',
* 'unsigned' => 1
* 'notnull' => 1
* 'default' => 0
* ),
* 'name' => array(
* 'type' => 'text',
* 'length' => 12
* ),
* 'password' => array(
* 'type' => 'text',
* 'length' => 12
* )
* );
* @param array $options An associative array of table options:
*
* @return mixed MDB2_OK on success, a MDB2 error on failure
* @access public
*/
function createTable($name, $fields, $options = array())
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

if (!$name) {
return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
'no valid table name specified', __FUNCTION__);
}
if (empty($fields)) {
return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
'no fields specified for table "'.$name.'"', __FUNCTION__);
}
$query_fields = $this->getFieldDeclarationList($fields);
if (PEAR::isError($query_fields)) {
return $query_fields;
}
if (!empty($options['primary'])) {
$query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')';
}

$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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implementedd', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ listViews()

/**
* list all views in the current database
*
* @param string database, the current is default
* @return mixed data array on success, a MDB2 error on failure
* @access public
*/
function listViews($database = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ listTableViews()

/**
* list the views in the database that reference a given table
*
* @param string table for which all references views should be found
* @return mixed MDB2_OK on success, a MDB2 error on failure
* @access public
**/
function listTableViews($table)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ listTableTriggers()
/**
* This function will be called to get all triggers of the
* current database ($db->getDatabase())
*
* @access public
* @param string $table The name of the table from the
* previous database to query against.
* @return mixed Array on success or MDB2 error on failure
*/
function listTableTriggers($table = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}
// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}
// }}}
// {{{ listTables()

/**
* list all tables in the current database
*
* @param string database, the current is default
* @return mixed data array on success, a MDB2 error on failure
* @access public
*/
function listTables($database = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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 (!empty($definition['primary'])) {
$query.= ' PRIMARY KEY';
} elseif (!empty($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
* @param string $primary hint if the constraint is primary
* @return mixed MDB2_OK on success, a MDB2 error on failure
* @access public
*/
function dropConstraint($table, $name, $primary = false)
{
$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 constraints 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ listSequences()

/**
* list all sequences in the current database
*
* @param string database, the current is default
* @return mixed data array on success, a MDB2 error on failure
* @access public
*/
function listSequences($database = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}
}

?>

+ 915
- 0
trunk/docs/include/PEAR/MDB2/Driver/Manager/mysql.php Näytä tiedosto

@@ -0,0 +1,915 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.84 2006/08/21 16:39:37 lsmith Exp $
//

require_once 'MDB2/Driver/Manager/Common.php';

/**
* MDB2 MySQL driver for the management modules
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Driver_Manager_mysql extends MDB2_Driver_Manager_Common
{

// }}}
// {{{ 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($name)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$name = $db->quoteIdentifier($name, true);
$query = "CREATE DATABASE $name";
$result = $db->exec($query);
if (PEAR::isError($result)) {
return $result;
}
return MDB2_OK;
}

// }}}
// {{{ 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($name)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$name = $db->quoteIdentifier($name, true);
$query = "DROP DATABASE $name";
$result = $db->exec($query);
if (PEAR::isError($result)) {
return $result;
}
return MDB2_OK;
}

// }}}
// {{{ 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.
* array(
* 'id' => array(
* 'type' => 'integer',
* 'unsigned' => 1
* 'notnull' => 1
* 'default' => 0
* ),
* 'name' => array(
* 'type' => 'text',
* 'length' => 12
* ),
* 'password' => array(
* 'type' => 'text',
* 'length' => 12
* )
* );
* @param array $options An associative array of table options:
* array(
* 'comment' => 'Foo',
* 'character_set' => 'utf8',
* 'collate' => 'utf8_unicode_ci',
* 'collate' => 'utf8_unicode_ci',
* 'type' => 'innodb',
* );
*
* @return mixed MDB2_OK on success, a MDB2 error on failure
* @access public
*/
function createTable($name, $fields, $options = array())
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

if (!$name) {
return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
'no valid table name specified', __FUNCTION__);
}
if (empty($fields)) {
return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null,
'no fields specified for table "'.$name.'"', __FUNCTION__);
}
$query_fields = $this->getFieldDeclarationList($fields);
if (PEAR::isError($query_fields)) {
return $query_fields;
}
if (!empty($options['primary'])) {
$query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')';
}
$name = $db->quoteIdentifier($name, true);
$query = "CREATE TABLE $name ($query_fields)";

$options_strings = array();

if (!empty($options['comment'])) {
$options_strings['comment'] = 'COMMENT = '.$db->quote($options['comment'], 'text');
}

if (!empty($options['charset'])) {
$options_strings['charset'] = 'DEFAULT CHARACTER SET '.$options['charset'];
if (!empty($options['collate'])) {
$options_strings['charset'].= ' COLLATE '.$options['collate'];
}
}

$type = false;
if (!empty($options['type'])) {
$type = $options['type'];
} elseif ($db->options['default_table_type']) {
$type = $db->options['default_table_type'];
}
if ($type) {
$options_strings[] = "ENGINE = $type";
}

if (!empty($options_strings)) {
$query.= ' '.implode(' ', $options_strings);
}
return $db->exec($query);
}

// }}}
// {{{ 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;
}

foreach ($changes as $change_name => $change) {
switch ($change_name) {
case 'add':
case 'remove':
case 'change':
case 'rename':
case 'name':
break;
default:
return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
'change type "'.$change_name.'" not yet supported', __FUNCTION__);
}
}

if ($check) {
return MDB2_OK;
}

$query = '';
if (!empty($changes['name'])) {
$change_name = $db->quoteIdentifier($changes['name'], true);
$query .= 'RENAME TO ' . $change_name;
}

if (!empty($changes['add']) && is_array($changes['add'])) {
foreach ($changes['add'] as $field_name => $field) {
if ($query) {
$query.= ', ';
}
$query.= 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
}
}

if (!empty($changes['remove']) && is_array($changes['remove'])) {
foreach ($changes['remove'] as $field_name => $field) {
if ($query) {
$query.= ', ';
}
$field_name = $db->quoteIdentifier($field_name, true);
$query.= 'DROP ' . $field_name;
}
}

$rename = array();
if (!empty($changes['rename']) && is_array($changes['rename'])) {
foreach ($changes['rename'] as $field_name => $field) {
$rename[$field['name']] = $field_name;
}
}

if (!empty($changes['change']) && is_array($changes['change'])) {
foreach ($changes['change'] as $field_name => $field) {
if ($query) {
$query.= ', ';
}
if (isset($rename[$field_name])) {
$old_field_name = $rename[$field_name];
unset($rename[$field_name]);
} else {
$old_field_name = $field_name;
}
$old_field_name = $db->quoteIdentifier($old_field_name, true);
$query.= "CHANGE $old_field_name " . $db->getDeclaration($field['definition']['type'], $field_name, $field['definition']);
}
}

if (!empty($rename) && is_array($rename)) {
foreach ($rename as $rename_name => $renamed_field) {
if ($query) {
$query.= ', ';
}
$field = $changes['rename'][$renamed_field];
$renamed_field = $db->quoteIdentifier($renamed_field, true);
$query.= 'CHANGE ' . $renamed_field . ' ' . $db->getDeclaration($field['definition']['type'], $field['name'], $field['definition']);
}
}

if (!$query) {
return MDB2_OK;
}

$name = $db->quoteIdentifier($name, true);
return $db->exec("ALTER TABLE $name $query");
}

// }}}
// {{{ 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;
}

$result = $db->queryCol('SHOW DATABASES');
if (PEAR::isError($result)) {
return $result;
}
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
}
return $result;
}

// }}}
// {{{ 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->queryCol('SELECT DISTINCT USER FROM USER');
}

// }}}
// {{{ listTables()

/**
* list all tables in the current database
*
* @param string database, the current is default
* @return mixed data array on success, a MDB2 error on failure
* @access public
*/
function listTables($database = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$query = "SHOW /*!50002 FULL*/ TABLES";
if (!is_null($database)) {
$query .= " FROM $database";
}
$query.= "/*!50002 WHERE Table_type = 'BASE TABLE'*/";

$table_names = $db->queryAll($query, null, MDB2_FETCHMODE_ORDERED);
if (PEAR::isError($table_names)) {
return $table_names;
}

$result = array();
foreach ($table_names as $table) {
if (!$this->_fixSequenceName($table[0], true)) {
$result[] = $table[0];
}
}
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
}
return $result;
}

// }}}
// {{{ listViews()

/**
* list the views in the database
*
* @param string database, the current is default
* @return mixed MDB2_OK on success, a MDB2 error on failure
* @access public
**/
function listViews($database = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$query = 'SHOW FULL TABLES';
if (!is_null($database)) {
$query.= " FROM $database";
}
$query.= " WHERE Table_type = 'VIEW'";

$result = $db->queryCol($query);
if (PEAR::isError($result)) {
return $result;
}

if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
}
return $result;
}

// }}}
// {{{ 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;
}

$table = $db->quoteIdentifier($table, true);
$result = $db->queryCol("SHOW COLUMNS FROM $table");
if (PEAR::isError($result)) {
return $result;
}
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
}
return $result;
}

// }}}
// {{{ createIndex()

/**
* Get the stucture of a field into an array
*
* @author Leoncx
* @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'
* 'length' => 10
* ),
* '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 ($definition['fields'] as $field => $fieldinfo) {
if (!empty($fieldinfo['length'])) {
$fields[] = $db->quoteIdentifier($field, true) . '(' . $fieldinfo['length'] . ')';
} else {
$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;
}

$table = $db->quoteIdentifier($table, true);
$name = $db->quoteIdentifier($db->getIndexName($name), true);
return $db->exec("DROP INDEX $name ON $table");
}

// }}}
// {{{ 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;
}

$key_name = 'Key_name';
$non_unique = 'Non_unique';
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$key_name = strtolower($key_name);
$non_unique = strtolower($non_unique);
} else {
$key_name = strtoupper($key_name);
$non_unique = strtoupper($non_unique);
}
}

$table = $db->quoteIdentifier($table, true);
$query = "SHOW INDEX FROM $table";
$indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
if (PEAR::isError($indexes)) {
return $indexes;
}

$result = array();
foreach ($indexes as $index_data) {
if ($index_data[$non_unique] && ($index = $this->_fixIndexName($index_data[$key_name]))) {
$result[$index] = true;
}
}

if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_change_key_case($result, $db->options['field_case']);
}
return array_keys($result);
}

// }}}
// {{{ 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;
}

$type = '';
$name = $db->quoteIdentifier($db->getIndexName($name), true);
if (!empty($definition['primary'])) {
$type = 'PRIMARY';
$name = 'KEY';
} elseif (!empty($definition['unique'])) {
$type = 'UNIQUE';
}

$table = $db->quoteIdentifier($table, true);
$query = "ALTER TABLE $table ADD $type $name";
$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
* @param string $primary hint if the constraint is primary
* @return mixed MDB2_OK on success, a MDB2 error on failure
* @access public
*/
function dropConstraint($table, $name, $primary = false)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$table = $db->quoteIdentifier($table, true);
if ($primary || strtolower($name) == 'primary') {
$query = "ALTER TABLE $table DROP PRIMARY KEY";
} else {
$name = $db->quoteIdentifier($db->getIndexName($name), true);
$query = "ALTER TABLE $table DROP INDEX $name";
}
return $db->exec($query);
}

// }}}
// {{{ listTableConstraints()

/**
* list all constraints 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;
}

$key_name = 'Key_name';
$non_unique = 'Non_unique';
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$key_name = strtolower($key_name);
$non_unique = strtolower($non_unique);
} else {
$key_name = strtoupper($key_name);
$non_unique = strtoupper($non_unique);
}
}

$table = $db->quoteIdentifier($table, true);
$query = "SHOW INDEX FROM $table";
$indexes = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
if (PEAR::isError($indexes)) {
return $indexes;
}

$result = array();
foreach ($indexes as $index_data) {
if (!$index_data[$non_unique]) {
if ($index_data[$key_name] !== 'PRIMARY') {
$index = $this->_fixIndexName($index_data[$key_name]);
} else {
$index = 'PRIMARY';
}
if (!empty($index)) {
$result[$index] = true;
}
}
}

if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_change_key_case($result, $db->options['field_case']);
}
return array_keys($result);
}

// }}}
// {{{ 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;
}

$sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
$seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true);

$query = "CREATE TABLE $sequence_name ($seqcol_name INT NOT NULL AUTO_INCREMENT, PRIMARY KEY ($seqcol_name))";
$query.= strlen($db->options['default_table_type']) ? ' TYPE='.$db->options['default_table_type'] : '';
$res = $db->exec($query);

if (PEAR::isError($res)) {
return $res;
}

if ($start == 1) {
return MDB2_OK;
}

$query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')';
$res = $db->exec($query);
if (!PEAR::isError($res)) {
return MDB2_OK;
}

// Handle error
$result = $db->exec("DROP TABLE $sequence_name");
if (PEAR::isError($result)) {
return $db->raiseError($result, null, null,
'could not drop inconsistent sequence table', __FUNCTION__);
}

return $db->raiseError($res, null, null,
'could not create sequence table', __FUNCTION__);
}

// }}}
// {{{ 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($seq_name)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
return $db->exec("DROP TABLE $sequence_name");
}

// }}}
// {{{ listSequences()

/**
* list all sequences in the current database
*
* @param string database, the current is default
* @return mixed data array on success, a MDB2 error on failure
* @access public
*/
function listSequences($database = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$query = "SHOW TABLES";
if (!is_null($database)) {
$query .= " FROM $database";
}
$table_names = $db->queryCol($query);
if (PEAR::isError($table_names)) {
return $table_names;
}

$result = array();
foreach ($table_names as $table_name) {
if ($sqn = $this->_fixSequenceName($table_name, true)) {
$result[] = $sqn;
}
}
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
}
return $result;
}

// }}}
}
?>

+ 58
- 0
trunk/docs/include/PEAR/MDB2/Driver/Native/Common.php Näytä tiedosto

@@ -0,0 +1,58 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.1 2006/06/18 21:59:05 lsmith Exp $
//

/**
* Base class for the natuve modules that is extended by each MDB2 driver
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Driver_Native_Common extends MDB2_Module_Common
{
}
?>

+ 60
- 0
trunk/docs/include/PEAR/MDB2/Driver/Native/mysql.php Näytä tiedosto

@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.9 2006/06/18 21:59:05 lsmith Exp $
//

require_once 'MDB2/Driver/Native/Common.php';

/**
* MDB2 MySQL driver for the native module
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Driver_Native_mysql extends MDB2_Driver_Native_Common
{
}
?>

+ 423
- 0
trunk/docs/include/PEAR/MDB2/Driver/Reverse/Common.php Näytä tiedosto

@@ -0,0 +1,423 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Common.php,v 1.28 2006/08/15 11:24:51 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 <smith@pooteeweet.org>
*/
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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ 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;
}

// }}}
// {{{ getTriggerDefinition()

/**
* Get the stucture of an trigger into an array
*
* @param string $trigger name of trigger that should be used in method
* @return mixed data array on success, a MDB2 error on failure
* @access public
*/
function getTriggerDefinition($trigger)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}

// }}}
// {{{ tableInfo()

/**
* Returns information about a table or a result set
*
* The format of the resulting array depends on which <var>$mode</var>
* you select. The sample output below is based on this query:
* <pre>
* SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
* FROM tblFoo
* JOIN tblBar ON tblFoo.fldId = tblBar.fldId
* </pre>
*
* <ul>
* <li>
*
* <kbd>null</kbd> (default)
* <pre>
* [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
* )
* </pre>
*
* </li><li>
*
* <kbd>MDB2_TABLEINFO_ORDER</kbd>
*
* <p>In addition to the information found in the default output,
* a notation of the number of columns is provided by the
* <samp>num_fields</samp> element while the <samp>order</samp>
* 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.</p>
*
* <p>If a result set has identical field names, the last one is
* used.</p>
*
* <pre>
* [num_fields] => 3
* [order] => Array (
* [fldId] => 2
* [fldTrans] => 1
* )
* </pre>
*
* </li><li>
*
* <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>
*
* <p>Similar to <kbd>MDB2_TABLEINFO_ORDER</kbd> 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.</p>
*
* <pre>
* [num_fields] => 3
* [ordertable] => Array (
* [tblFoo] => Array (
* [fldId] => 0
* [fldPhone] => 1
* )
* [tblBar] => Array (
* [fldId] => 2
* )
* )
* </pre>
*
* </li>
* </ul>
*
* The <samp>flags</samp> 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.
* + <samp>primary_key</samp>
* + <samp>unique_key</samp>
* + <samp>multiple_key</samp>
* + <samp>not_null</samp>
*
* Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
* elements if <var>$result</var> is a table name. The following DBMS's
* provide full information from queries:
* + fbsql
* + mysql
*
* If the 'portability' option has <samp>MDB2_PORTABILITY_FIX_CASE</samp>
* 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:
* <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>,
* <kbd>MDB2_TABLEINFO_ORDER</kbd> or
* <kbd>MDB2_TABLEINFO_FULL</kbd> (which does both).
* These are bitwise, so the first two can be
* combined using <kbd>|</kbd>.
*
* @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;
}

if (!is_string($result)) {
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
'method not implemented', __FUNCTION__);
}

$db->loadModule('Manager', null, true);
$fields = $db->manager->listTableFields($result);
if (PEAR::isError($fields)) {
return $fields;
}

$flags = array();

$idxname_format = $db->getOption('idxname_format');
$db->setOption('idxname_format', '%s');

$indexes = $db->manager->listTableIndexes($result);
if (PEAR::isError($indexes)) {
$db->setOption('idxname_format', $idxname_format);
return $indexes;
}

foreach ($indexes as $index) {
$definition = $this->getTableIndexDefinition($result, $index);
if (PEAR::isError($definition)) {
$db->setOption('idxname_format', $idxname_format);
return $definition;
}
if (count($definition['fields']) > 1) {
foreach ($definition['fields'] as $field => $sort) {
$flags[$field] = 'multiple_key';
}
}
}

$constraints = $db->manager->listTableConstraints($result);
if (PEAR::isError($constraints)) {
return $constraints;
}

foreach ($constraints as $constraint) {
$definition = $this->getTableConstraintDefinition($result, $constraint);
if (PEAR::isError($definition)) {
$db->setOption('idxname_format', $idxname_format);
return $definition;
}
$flag = !empty($definition['primary'])
? 'primary_key' : (!empty($definition['unique'])
? 'unique_key' : false);
if ($flag) {
foreach ($definition['fields'] as $field => $sort) {
if (empty($flags[$field]) || $flags[$field] != 'primary_key') {
$flags[$field] = $flag;
}
}
}
}

if ($mode) {
$res['num_fields'] = count($fields);
}

foreach ($fields as $i => $field) {
$definition = $this->getTableFieldDefinition($result, $field);
if (PEAR::isError($definition)) {
$db->setOption('idxname_format', $idxname_format);
return $definition;
}
$res[$i] = $definition[0];
$res[$i]['name'] = $field;
$res[$i]['table'] = $result;
$res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype']));
// 'primary_key', 'unique_key', 'multiple_key'
$res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field];
// not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]'
if (!empty($res[$i]['notnull'])) {
$res[$i]['flags'].= ' not_null';
}
if (!empty($res[$i]['unsigned'])) {
$res[$i]['flags'].= ' unsigned';
}
if (!empty($res[$i]['auto_increment'])) {
$res[$i]['flags'].= ' autoincrement';
}
if (!empty($res[$i]['default'])) {
$res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']);
}

if ($mode & MDB2_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}

$db->setOption('idxname_format', $idxname_format);
return $res;
}
}
?>

+ 369
- 0
trunk/docs/include/PEAR/MDB2/Driver/Reverse/mysql.php Näytä tiedosto

@@ -0,0 +1,369 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: mysql.php,v 1.59 2006/08/12 15:44:03 lsmith Exp $
//

require_once 'MDB2/Driver/Reverse/Common.php';

/**
* MDB2 MySQL driver for the schema reverse engineering module
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Driver_Reverse_mysql extends MDB2_Driver_Reverse_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 $field_name 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_name)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$result = $db->loadModule('Datatype', null, true);
if (PEAR::isError($result)) {
return $result;
}
$table = $db->quoteIdentifier($table, true);
$query = "SHOW COLUMNS FROM $table LIKE ".$db->quote($field_name);
$columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
if (PEAR::isError($columns)) {
return $columns;
}
foreach ($columns as $column) {
$column = array_change_key_case($column, CASE_LOWER);
$column['name'] = $column['field'];
unset($column['field']);
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$column['name'] = strtolower($column['name']);
} else {
$column['name'] = strtoupper($column['name']);
}
} else {
$column = array_change_key_case($column, $db->options['field_case']);
}
if ($field_name == $column['name']) {
list($types, $length, $unsigned, $fixed) = $db->datatype->mapNativeDatatype($column);
$notnull = false;
if (empty($column['null']) || $column['null'] !== 'YES') {
$notnull = true;
}
$default = false;
if (array_key_exists('default', $column)) {
$default = $column['default'];
if (is_null($default) && $notnull) {
$default = '';
}
}
$autoincrement = false;
if (!empty($column['extra']) && $column['extra'] == 'auto_increment') {
$autoincrement = true;
}

$definition[0] = array(
'notnull' => $notnull,
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
);
if ($length > 0) {
$definition[0]['length'] = $length;
}
if (!is_null($unsigned)) {
$definition[0]['unsigned'] = $unsigned;
}
if (!is_null($fixed)) {
$definition[0]['fixed'] = $fixed;
}
if ($default !== false) {
$definition[0]['default'] = $default;
}
if ($autoincrement !== false) {
$definition[0]['autoincrement'] = $autoincrement;
}
foreach ($types as $key => $type) {
$definition[$key] = $definition[0];
if ($type == 'clob' || $type == 'blob') {
unset($definition[$key]['default']);
}
$definition[$key]['type'] = $type;
$definition[$key]['mdb2type'] = $type;
}
return $definition;
}
}

return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
'it was not specified an existing table column', __FUNCTION__);
}

// }}}
// {{{ 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 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_name)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$index_name = $db->getIndexName($index_name);
$table = $db->quoteIdentifier($table, true);
$query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = ".$db->quote($index_name)." */";
$result = $db->query($query);
if (PEAR::isError($result)) {
return $result;
}
$definition = array();
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
$row = array_change_key_case($row, CASE_LOWER);
$key_name = $row['key_name'];
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$key_name = strtolower($key_name);
} else {
$key_name = strtoupper($key_name);
}
}
if ($index_name == $key_name) {
if (!$row['non_unique']) {
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
'it was not specified an existing table index', __FUNCTION__);
}
$column_name = $row['column_name'];
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$column_name = strtolower($column_name);
} else {
$column_name = strtoupper($column_name);
}
}
$definition['fields'][$column_name] = array();
if (!empty($row['collation'])) {
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
? 'ascending' : 'descending');
}
}
}
$result->free();
if (empty($definition['fields'])) {
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
'it was not specified an existing table index', __FUNCTION__);
}
return $definition;
}

// }}}
// {{{ getTableConstraintDefinition()

/**
* Get the stucture of a constraint into an array
*
* @param string $table name of table that should be used in method
* @param string $index_name 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_name)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

if (strtolower($index_name) != 'primary') {
$index_name = $db->getIndexName($index_name);
}
$table = $db->quoteIdentifier($table, true);
$query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = ".$db->quote($index_name)." */";
$result = $db->query($query);
if (PEAR::isError($result)) {
return $result;
}
$definition = array();
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
$row = array_change_key_case($row, CASE_LOWER);
$key_name = $row['key_name'];
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$key_name = strtolower($key_name);
} else {
$key_name = strtoupper($key_name);
}
}
if ($index_name == $key_name) {
if ($row['non_unique']) {
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
'it was not specified an existing table constraint', __FUNCTION__);
}
if ($row['key_name'] == 'PRIMARY') {
$definition['primary'] = true;
} else {
$definition['unique'] = true;
}
$column_name = $row['column_name'];
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$column_name = strtolower($column_name);
} else {
$column_name = strtoupper($column_name);
}
}
$definition['fields'][$column_name] = array();
if (!empty($row['collation'])) {
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
? 'ascending' : 'descending');
}
}
}
$result->free();
if (empty($definition['fields'])) {
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
'it was not specified an existing table constraint', __FUNCTION__);
}
return $definition;
}

// }}}
// {{{ tableInfo()

/**
* Returns information about a table or a result set
*
* @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 a valid tableInfo mode
*
* @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)
{
if (is_string($result)) {
return parent::tableInfo($result, $mode);
}

$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$id = MDB2::isResultCommon($result) ? $result->getResource() : $result;
if (!is_resource($id)) {
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
'Could not generate result ressource', __FUNCTION__);
}

if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
if ($db->options['field_case'] == CASE_LOWER) {
$case_func = 'strtolower';
} else {
$case_func = 'strtoupper';
}
} else {
$case_func = 'strval';
}

$count = @mysql_num_fields($id);
$res = array();

if ($mode) {
$res['num_fields'] = $count;
}

$db->loadModule('Datatype', null, true);
for ($i = 0; $i < $count; $i++) {
$res[$i] = array(
'table' => $case_func(@mysql_field_table($id, $i)),
'name' => $case_func(@mysql_field_name($id, $i)),
'type' => @mysql_field_type($id, $i),
'length' => @mysql_field_len($id, $i),
'flags' => @mysql_field_flags($id, $i),
);
if ($res[$i]['type'] == 'string') {
$res[$i]['type'] = 'char';
} elseif ($res[$i]['type'] == 'unknown') {
$res[$i]['type'] = 'decimal';
}
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
if (PEAR::isError($mdb2type_info)) {
return $mdb2type_info;
}
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
if ($mode & MDB2_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & MDB2_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}

return $res;
}
}
?>

+ 1416
- 0
trunk/docs/include/PEAR/MDB2/Driver/mysql.php
File diff suppressed because it is too large
Näytä tiedosto


+ 704
- 0
trunk/docs/include/PEAR/MDB2/Extended.php Näytä tiedosto

@@ -0,0 +1,704 @@
<?php
// +----------------------------------------------------------------------+
// | PHP versions 4 and 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Extended.php,v 1.52 2006/08/18 21:53:43 lsmith Exp $

/**
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/

/**
* Used by autoPrepare()
*/
define('MDB2_AUTOQUERY_INSERT', 1);
define('MDB2_AUTOQUERY_UPDATE', 2);
define('MDB2_AUTOQUERY_DELETE', 3);
define('MDB2_AUTOQUERY_SELECT', 4);

/**
* MDB2_Extended: class which adds several high level methods to MDB2
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
class MDB2_Extended extends MDB2_Module_Common
{
// {{{ autoPrepare()

/**
* Generate an insert, update or delete query and call prepare() on it
*
* @param string table
* @param array the fields names
* @param int type of query to build
* MDB2_AUTOQUERY_INSERT
* MDB2_AUTOQUERY_UPDATE
* MDB2_AUTOQUERY_DELETE
* MDB2_AUTOQUERY_SELECT
* @param string (in case of update and delete queries, this string will be put after the sql WHERE statement)
* @param array that contains the types of the placeholders
* @param mixed array that contains the types of the columns in
* the result set or MDB2_PREPARE_RESULT, if set to
* MDB2_PREPARE_MANIP the query is handled as a manipulation query
*
* @return resource handle for the query
* @see buildManipSQL
* @access public
*/
function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT,
$where = false, $types = null, $result_types = MDB2_PREPARE_MANIP)
{
$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, $result_types);
}
// }}}

// {{{ autoExecute()

/**
* Generate an insert, update or delete query and call prepare() and execute() on 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 build
* MDB2_AUTOQUERY_INSERT
* MDB2_AUTOQUERY_UPDATE
* MDB2_AUTOQUERY_DELETE
* MDB2_AUTOQUERY_SELECT
* @param string (in case of update and delete 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
* @param mixed array that contains the types of the columns in
* the result set or MDB2_PREPARE_RESULT, if set to
* MDB2_PREPARE_MANIP the query is handled as a manipulation query
*
* @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, $result_types = MDB2_PREPARE_MANIP)
{
$fields_values = (array)$fields_values;
if ($mode == MDB2_AUTOQUERY_SELECT) {
if (is_array($result_types)) {
$keys = array_keys($result_types);
} else {
$keys = $result_types = array();
}
} else {
$keys = array_keys($fields_values);
}
$params = array_values($fields_values);
if (empty($params)) {
$query = $this->buildManipSQL($table, $keys, $mode, $where);

$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}
if ($mode == MDB2_AUTOQUERY_SELECT) {
$result =& $db->query($query, $result_types, $result_class);
} else {
$result =& $db->exec($query);
}
} else {
$stmt = $this->autoPrepare($table, $keys, $mode, $where, $types, $result_types);
if (PEAR::isError($stmt)) {
return $stmt;
}
$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/DELETE query, all
* the records of the table will be updated/deleted !
*
* @param string name of the table
* @param ordered array containing the fields names
* @param int type of query to build
* MDB2_AUTOQUERY_INSERT
* MDB2_AUTOQUERY_UPDATE
* MDB2_AUTOQUERY_DELETE
* MDB2_AUTOQUERY_SELECT
* @param string (in case of update and delete 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 (!empty($table_fields) && $db->options['quote_identifier']) {
foreach ($table_fields as $key => $field) {
$table_fields[$key] = $db->quoteIdentifier($field);
}
}

if ($where !== false && !is_null($where)) {
if (is_array($where)) {
$where = implode(' AND ', $where);
}
$where = ' WHERE '.$where;
}

switch ($mode) {
case MDB2_AUTOQUERY_INSERT:
if (empty($table_fields)) {
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
'Insert requires table fields', __FUNCTION__);
}
$cols = implode(', ', $table_fields);
$values = '?'.str_repeat(', ?', (count($table_fields) - 1));
return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')';
break;
case MDB2_AUTOQUERY_UPDATE:
if (empty($table_fields)) {
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
'Update requires table fields', __FUNCTION__);
}
$set = implode(' = ?, ', $table_fields).' = ?';
$sql = 'UPDATE '.$table.' SET '.$set.$where;
return $sql;
break;
case MDB2_AUTOQUERY_DELETE:
$sql = 'DELETE FROM '.$table.$where;
return $sql;
break;
case MDB2_AUTOQUERY_SELECT:
$cols = is_array($table_fields) ? implode(', ', $table_fields) : '*';
$sql = 'SELECT '.$cols.' FROM '.$table.$where;
return $sql;
break;
}
return $db->raiseError(MDB2_ERROR_SYNTAX, null, null,
'Non existant mode', __FUNCTION__);
}
// }}}

// {{{ limitQuery()

/**
* Generates a limited query
*
* @param string query
* @param array that contains the types of the columns in the result set
* @param integer the numbers of rows to fetch
* @param integer the row to start to fetching
* @param string which specifies which result class to use
* @param mixed string which specifies which class to wrap results in
*
* @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure
* @access public
*/
function &limitQuery($query, $types, $limit, $offset = 0, $result_class = true,
$result_wrap_class = false)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

$result = $db->setLimit($limit, $offset);
if (PEAR::isError($result)) {
return $result;
}
$result =& $db->query($query, $types, $result_class, $result_wrap_class);
return $result;
}
// }}}

// {{{ execParam()

/**
* Execute a parameterized DML statement.
*
* @param string the SQL query
* @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
*
* @return int|MDB2_Error affected rows on success, a MDB2 error on failure
* @access public
*/
function execParam($query, $params = array(), $param_types = null)
{
$db =& $this->getDBInstance();
if (PEAR::isError($db)) {
return $db;
}

settype($params, 'array');
if (empty($params)) {
return $db->exec($query);
}

$stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP);
if (PEAR::isError($stmt)) {
return $stmt;
}

$result = $stmt->execute($params);
if (PEAR::isError($result)) {
return $result;
}

$stmt->free();
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 (empty($params)) {
return $db->queryOne($query, $type, $colnum);
}

$stmt = $db->prepare($query, $param_types, $type);
if (PEAR::isError($stmt)) {
return $stmt;
}

$result = $stmt->execute($params);
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 (empty($params)) {
return $db->queryRow($query, $types, $fetchmode);
}

$stmt = $db->prepare($query, $param_types, $types);
if (PEAR::isError($stmt)) {
return $stmt;
}

$result = $stmt->execute($params);
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 (empty($params)) {
return $db->queryCol($query, $type, $colnum);
}

$stmt = $db->prepare($query, $param_types, $type);
if (PEAR::isError($stmt)) {
return $stmt;
}

$result = $stmt->execute($params);
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 (empty($params)) {
return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group);
}

$stmt = $db->prepare($query, $param_types, $types);
if (PEAR::isError($stmt)) {
return $stmt;
}

$result = $stmt->execute($params);
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 (empty($params)) {
return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group);
}

$stmt = $db->prepare($query, $param_types, $types);
if (PEAR::isError($stmt)) {
return $stmt;
}

$result = $stmt->execute($params);
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++) {
$result = $stmt->execute($params[$i]);
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
* @param bool if the returned value should be quoted
*
* @return int|MDB2_Error id on success, a MDB2 error on failure
* @access public
*/
function getBeforeID($table, $field = null, $ondemand = true, $quote = 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 (!$quote || PEAR::isError($id)) {
return $id;
}
return $db->quote($id, 'integer');
} elseif (!$quote) {
return null;
}
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);
}
// }}}
}
?>

+ 259
- 0
trunk/docs/include/PEAR/MDB2/Iterator.php Näytä tiedosto

@@ -0,0 +1,259 @@
<?php
// +----------------------------------------------------------------------+
// | PHP version 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: Iterator.php,v 1.22 2006/05/06 14:03:41 lsmith Exp $

/**
* PHP5 Iterator
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
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();
}
// }}}
}

/**
* PHP5 buffered Iterator
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
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);
}
// }}}
}

?>

+ 245
- 0
trunk/docs/include/PEAR/MDB2/LOB.php Näytä tiedosto

@@ -0,0 +1,245 @@
<?php
// +----------------------------------------------------------------------+
// | PHP version 5 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
// | Stig. S. Bakken, Lukas Smith |
// | All rights reserved. |
// +----------------------------------------------------------------------+
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB |
// | API as well as database abstraction for PHP applications. |
// | This LICENSE is in the BSD license style. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | |
// | Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, |
// | Lukas Smith nor the names of his contributors may be used to endorse |
// | or promote products derived from this software without specific prior|
// | written permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// | POSSIBILITY OF SUCH DAMAGE. |
// +----------------------------------------------------------------------+
// | Author: Lukas Smith <smith@pooteeweet.org> |
// +----------------------------------------------------------------------+
//
// $Id: LOB.php,v 1.33 2006/05/31 14:38:06 lsmith Exp $

/**
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/

require_once 'MDB2.php';

/**
* MDB2_LOB: user land stream wrapper implementation for LOB support
*
* @package MDB2
* @category Database
* @author Lukas Smith <smith@pooteeweet.org>
*/
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;

// {{{ 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 (empty($url['host'])) {
return false;
}
$this->db_index = (int)$url['host'];
if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
return false;
}
$db =& $GLOBALS['_MDB2_databases'][$this->db_index];
$this->lob_index = (int)$url['user'];
if (!isset($db->datatype->lobs[$this->lob_index])) {
return false;
}
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];
$db->datatype->_retrieveLOB($db->datatype->lobs[$this->lob_index]);

$data = $db->datatype->_readLOB($db->datatype->lobs[$this->lob_index], $count);
$length = strlen($data);
if ($length == 0) {
$db->datatype->lobs[$this->lob_index]['endOfLOB'] = true;
}
$db->datatype->lobs[$this->lob_index]['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()
{
if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) {
$db =& $GLOBALS['_MDB2_databases'][$this->db_index];
return $db->datatype->lobs[$this->lob_index]['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($db->datatype->lobs[$this->lob_index]);
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($db->datatype->lobs[$this->lob_index]);
unset($db->datatype->lobs[$this->lob_index]);
}
}
}
// }}}
}

// register streams wrapper
if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) {
MDB2::raiseError();
return false;
}

?>

+ 713
- 0
trunk/docs/include/PEAR/Mail/mime.php Näytä tiedosto

@@ -0,0 +1,713 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2003 Richard Heyes |
// | Copyright (c) 2003-2005 The PHP Group |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org> |
// | Tomas V.V.Cox <cox@idecnet.com> (port to PEAR) |
// +-----------------------------------------------------------------------+
//
// $Id: mime.php,v 1.39 2005/06/13 21:24:16 cipri Exp $

require_once('PEAR.php');
require_once('Mail/mimePart.php');

/**
* Mime mail composer class. Can handle: text and html bodies, embedded html
* images and attachments.
* Documentation and examples of this class are avaible here:
* http://pear.php.net/manual/
*
* @notes This class is based on HTML Mime Mail class from
* Richard Heyes <richard@phpguru.org> which was based also
* in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> and
* Sascha Schumann <sascha@schumann.cx>
*
* @author Richard Heyes <richard.heyes@heyes-computing.net>
* @author Tomas V.V.Cox <cox@idecnet.com>
* @package Mail
* @access public
*/
class Mail_mime
{
/**
* Contains the plain text part of the email
* @var string
*/
var $_txtbody;
/**
* Contains the html part of the email
* @var string
*/
var $_htmlbody;
/**
* contains the mime encoded text
* @var string
*/
var $_mime;
/**
* contains the multipart content
* @var string
*/
var $_multipart;
/**
* list of the attached images
* @var array
*/
var $_html_images = array();
/**
* list of the attachements
* @var array
*/
var $_parts = array();
/**
* Build parameters
* @var array
*/
var $_build_params = array();
/**
* Headers for the mail
* @var array
*/
var $_headers = array();
/**
* End Of Line sequence (for serialize)
* @var string
*/
var $_eol;


/**
* Constructor function
*
* @access public
*/
function Mail_mime($crlf = "\r\n")
{
$this->_setEOL($crlf);
$this->_build_params = array(
'text_encoding' => '7bit',
'html_encoding' => 'quoted-printable',
'7bit_wrap' => 998,
'html_charset' => 'ISO-8859-1',
'text_charset' => 'ISO-8859-1',
'head_charset' => 'ISO-8859-1'
);
}

/**
* Wakeup (unserialize) - re-sets EOL constant
*
* @access private
*/
function __wakeup()
{
$this->_setEOL($this->_eol);
}

/**
* Accessor function to set the body text. Body text is used if
* it's not an html mail being sent or else is used to fill the
* text/plain part that emails clients who don't support
* html should show.
*
* @param string $data Either a string or
* the file name with the contents
* @param bool $isfile If true the first param should be treated
* as a file name, else as a string (default)
* @param bool $append If true the text or file is appended to
* the existing body, else the old body is
* overwritten
* @return mixed true on success or PEAR_Error object
* @access public
*/
function setTXTBody($data, $isfile = false, $append = false)
{
if (!$isfile) {
if (!$append) {
$this->_txtbody = $data;
} else {
$this->_txtbody .= $data;
}
} else {
$cont = $this->_file2str($data);
if (PEAR::isError($cont)) {
return $cont;
}
if (!$append) {
$this->_txtbody = $cont;
} else {
$this->_txtbody .= $cont;
}
}
return true;
}

/**
* Adds a html part to the mail
*
* @param string $data Either a string or the file name with the
* contents
* @param bool $isfile If true the first param should be treated
* as a file name, else as a string (default)
* @return mixed true on success or PEAR_Error object
* @access public
*/
function setHTMLBody($data, $isfile = false)
{
if (!$isfile) {
$this->_htmlbody = $data;
} else {
$cont = $this->_file2str($data);
if (PEAR::isError($cont)) {
return $cont;
}
$this->_htmlbody = $cont;
}

return true;
}

/**
* Adds an image to the list of embedded images.
*
* @param string $file The image file name OR image data itself
* @param string $c_type The content type
* @param string $name The filename of the image.
* Only use if $file is the image data
* @param bool $isfilename Whether $file is a filename or not
* Defaults to true
* @return mixed true on success or PEAR_Error object
* @access public
*/
function addHTMLImage($file, $c_type='application/octet-stream',
$name = '', $isfilename = true)
{
$filedata = ($isfilename === true) ? $this->_file2str($file)
: $file;
if ($isfilename === true) {
$filename = ($name == '' ? basename($file) : basename($name));
} else {
$filename = basename($name);
}
if (PEAR::isError($filedata)) {
return $filedata;
}
$this->_html_images[] = array(
'body' => $filedata,
'name' => $filename,
'c_type' => $c_type,
'cid' => md5(uniqid(time()))
);
return true;
}

/**
* Adds a file to the list of attachments.
*
* @param string $file The file name of the file to attach
* OR the file data itself
* @param string $c_type The content type
* @param string $name The filename of the attachment
* Only use if $file is the file data
* @param bool $isFilename Whether $file is a filename or not
* Defaults to true
* @return mixed true on success or PEAR_Error object
* @access public
*/
function addAttachment($file, $c_type = 'application/octet-stream',
$name = '', $isfilename = true,
$encoding = 'base64')
{
$filedata = ($isfilename === true) ? $this->_file2str($file)
: $file;
if ($isfilename === true) {
// Force the name the user supplied, otherwise use $file
$filename = (!empty($name)) ? $name : $file;
} else {
$filename = $name;
}
if (empty($filename)) {
return PEAR::raiseError(
'The supplied filename for the attachment can\'t be empty'
);
}
$filename = basename($filename);
if (PEAR::isError($filedata)) {
return $filedata;
}

$this->_parts[] = array(
'body' => $filedata,
'name' => $filename,
'c_type' => $c_type,
'encoding' => $encoding
);
return true;
}

/**
* Get the contents of the given file name as string
*
* @param string $file_name path of file to process
* @return string contents of $file_name
* @access private
*/
function &_file2str($file_name)
{
if (!is_readable($file_name)) {
return PEAR::raiseError('File is not readable ' . $file_name);
}
if (!$fd = fopen($file_name, 'rb')) {
return PEAR::raiseError('Could not open ' . $file_name);
}
$filesize = filesize($file_name);
if ($filesize == 0){
$cont = "";
}else{
$cont = fread($fd, $filesize);
}
fclose($fd);
return $cont;
}

/**
* Adds a text subpart to the mimePart object and
* returns it during the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created.
* @param string The text to add.
* @return object The text mimePart object
* @access private
*/
function &_addTextPart(&$obj, $text)
{
$params['content_type'] = 'text/plain';
$params['encoding'] = $this->_build_params['text_encoding'];
$params['charset'] = $this->_build_params['text_charset'];
if (is_object($obj)) {
return $obj->addSubpart($text, $params);
} else {
return new Mail_mimePart($text, $params);
}
}

/**
* Adds a html subpart to the mimePart object and
* returns it during the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created.
* @return object The html mimePart object
* @access private
*/
function &_addHtmlPart(&$obj)
{
$params['content_type'] = 'text/html';
$params['encoding'] = $this->_build_params['html_encoding'];
$params['charset'] = $this->_build_params['html_charset'];
if (is_object($obj)) {
return $obj->addSubpart($this->_htmlbody, $params);
} else {
return new Mail_mimePart($this->_htmlbody, $params);
}
}

/**
* Creates a new mimePart object, using multipart/mixed as
* the initial content-type and returns it during the
* build process.
*
* @return object The multipart/mixed mimePart object
* @access private
*/
function &_addMixedPart()
{
$params['content_type'] = 'multipart/mixed';
return new Mail_mimePart('', $params);
}

/**
* Adds a multipart/alternative part to a mimePart
* object (or creates one), and returns it during
* the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created.
* @return object The multipart/mixed mimePart object
* @access private
*/
function &_addAlternativePart(&$obj)
{
$params['content_type'] = 'multipart/alternative';
if (is_object($obj)) {
return $obj->addSubpart('', $params);
} else {
return new Mail_mimePart('', $params);
}
}

/**
* Adds a multipart/related part to a mimePart
* object (or creates one), and returns it during
* the build process.
*
* @param mixed The object to add the part to, or
* null if a new object is to be created
* @return object The multipart/mixed mimePart object
* @access private
*/
function &_addRelatedPart(&$obj)
{
$params['content_type'] = 'multipart/related';
if (is_object($obj)) {
return $obj->addSubpart('', $params);
} else {
return new Mail_mimePart('', $params);
}
}

/**
* Adds an html image subpart to a mimePart object
* and returns it during the build process.
*
* @param object The mimePart to add the image to
* @param array The image information
* @return object The image mimePart object
* @access private
*/
function &_addHtmlImagePart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = 'base64';
$params['disposition'] = 'inline';
$params['dfilename'] = $value['name'];
$params['cid'] = $value['cid'];
$obj->addSubpart($value['body'], $params);
}

/**
* Adds an attachment subpart to a mimePart object
* and returns it during the build process.
*
* @param object The mimePart to add the image to
* @param array The attachment information
* @return object The image mimePart object
* @access private
*/
function &_addAttachmentPart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = $value['encoding'];
$params['disposition'] = 'attachment';
$params['dfilename'] = $value['name'];
$obj->addSubpart($value['body'], $params);
}

/**
* Builds the multipart message from the list ($this->_parts) and
* returns the mime content.
*
* @param array Build parameters that change the way the email
* is built. Should be associative. Can contain:
* text_encoding - What encoding to use for plain text
* Default is 7bit
* html_encoding - What encoding to use for html
* Default is quoted-printable
* 7bit_wrap - Number of characters before text is
* wrapped in 7bit encoding
* Default is 998
* html_charset - The character set to use for html.
* Default is iso-8859-1
* text_charset - The character set to use for text.
* Default is iso-8859-1
* head_charset - The character set to use for headers.
* Default is iso-8859-1
* @return string The mime content
* @access public
*/
function &get($build_params = null)
{
if (isset($build_params)) {
while (list($key, $value) = each($build_params)) {
$this->_build_params[$key] = $value;
}
}

if (!empty($this->_html_images) AND isset($this->_htmlbody)) {
foreach ($this->_html_images as $value) {
$regex = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . preg_quote($value['name'], '#') .
'\3#';
$rep = '\1\2=\3cid:' . $value['cid'] .'\3';
$this->_htmlbody = preg_replace($regex, $rep,
$this->_htmlbody
);
}
}

$null = null;
$attachments = !empty($this->_parts) ? true : false;
$html_images = !empty($this->_html_images) ? true : false;
$html = !empty($this->_htmlbody) ? true : false;
$text = (!$html AND !empty($this->_txtbody)) ? true : false;

switch (true) {
case $text AND !$attachments:
$message =& $this->_addTextPart($null, $this->_txtbody);
break;

case !$text AND !$html AND $attachments:
$message =& $this->_addMixedPart();
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;

case $text AND $attachments:
$message =& $this->_addMixedPart();
$this->_addTextPart($message, $this->_txtbody);
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;

case $html AND !$attachments AND !$html_images:
if (isset($this->_txtbody)) {
$message =& $this->_addAlternativePart($null);
$this->_addTextPart($message, $this->_txtbody);
$this->_addHtmlPart($message);
} else {
$message =& $this->_addHtmlPart($null);
}
break;

case $html AND !$attachments AND $html_images:
if (isset($this->_txtbody)) {
$message =& $this->_addAlternativePart($null);
$this->_addTextPart($message, $this->_txtbody);
$related =& $this->_addRelatedPart($message);
} else {
$message =& $this->_addRelatedPart($null);
$related =& $message;
}
$this->_addHtmlPart($related);
for ($i = 0; $i < count($this->_html_images); $i++) {
$this->_addHtmlImagePart($related, $this->_html_images[$i]);
}
break;

case $html AND $attachments AND !$html_images:
$message =& $this->_addMixedPart();
if (isset($this->_txtbody)) {
$alt =& $this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->_txtbody);
$this->_addHtmlPart($alt);
} else {
$this->_addHtmlPart($message);
}
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;

case $html AND $attachments AND $html_images:
$message =& $this->_addMixedPart();
if (isset($this->_txtbody)) {
$alt =& $this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->_txtbody);
$rel =& $this->_addRelatedPart($alt);
} else {
$rel =& $this->_addRelatedPart($message);
}
$this->_addHtmlPart($rel);
for ($i = 0; $i < count($this->_html_images); $i++) {
$this->_addHtmlImagePart($rel, $this->_html_images[$i]);
}
for ($i = 0; $i < count($this->_parts); $i++) {
$this->_addAttachmentPart($message, $this->_parts[$i]);
}
break;

}

if (isset($message)) {
$output = $message->encode();
$this->_headers = array_merge($this->_headers,
$output['headers']);
return $output['body'];

} else {
return false;
}
}

/**
* Returns an array with the headers needed to prepend to the email
* (MIME-Version and Content-Type). Format of argument is:
* $array['header-name'] = 'header-value';
*
* @param array $xtra_headers Assoc array with any extra headers.
* Optional.
* @return array Assoc array with the mime headers
* @access public
*/
function &headers($xtra_headers = null)
{
// Content-Type header should already be present,
// So just add mime version header
$headers['MIME-Version'] = '1.0';
if (isset($xtra_headers)) {
$headers = array_merge($headers, $xtra_headers);
}
$this->_headers = array_merge($headers, $this->_headers);

return $this->_encodeHeaders($this->_headers);
}

/**
* Get the text version of the headers
* (usefull if you want to use the PHP mail() function)
*
* @param array $xtra_headers Assoc array with any extra headers.
* Optional.
* @return string Plain text headers
* @access public
*/
function txtHeaders($xtra_headers = null)
{
$headers = $this->headers($xtra_headers);
$ret = '';
foreach ($headers as $key => $val) {
$ret .= "$key: $val" . MAIL_MIME_CRLF;
}
return $ret;
}

/**
* Sets the Subject header
*
* @param string $subject String to set the subject to
* access public
*/
function setSubject($subject)
{
$this->_headers['Subject'] = $subject;
}

/**
* Set an email to the From (the sender) header
*
* @param string $email The email direction to add
* @access public
*/
function setFrom($email)
{
$this->_headers['From'] = $email;
}

/**
* Add an email to the Cc (carbon copy) header
* (multiple calls to this method are allowed)
*
* @param string $email The email direction to add
* @access public
*/
function addCc($email)
{
if (isset($this->_headers['Cc'])) {
$this->_headers['Cc'] .= ", $email";
} else {
$this->_headers['Cc'] = $email;
}
}

/**
* Add an email to the Bcc (blank carbon copy) header
* (multiple calls to this method are allowed)
*
* @param string $email The email direction to add
* @access public
*/
function addBcc($email)
{
if (isset($this->_headers['Bcc'])) {
$this->_headers['Bcc'] .= ", $email";
} else {
$this->_headers['Bcc'] = $email;
}
}

/**
* Encodes a header as per RFC2047
*
* @param string $input The header data to encode
* @return string Encoded data
* @access private
*/
function _encodeHeaders($input)
{
foreach ($input as $hdr_name => $hdr_value) {
preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x80-\xFF])/e',
'"=" .
strtoupper(dechex(ord("\1")))',
$value);
$hdr_value = str_replace($value, '=?' .
$this->_build_params['head_charset'] .
'?Q?' . $replacement . '?=',
$hdr_value);
}
$input[$hdr_name] = $hdr_value;
}

return $input;
}

/**
* Set the object's end-of-line and define the constant if applicable
*
* @param string $eol End Of Line sequence
* @access private
*/
function _setEOL($eol)
{
$this->_eol = $eol;
if (!defined('MAIL_MIME_CRLF')) {
define('MAIL_MIME_CRLF', $this->_eol, true);
}
}


} // End of class
?>

+ 837
- 0
trunk/docs/include/PEAR/Mail/mimeDecode.php Näytä tiedosto

@@ -0,0 +1,837 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2003 Richard Heyes |
// | Copyright (c) 2003-2005 The PHP Group |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org> |
// +-----------------------------------------------------------------------+

require_once 'PEAR.php';

/**
* +----------------------------- IMPORTANT ------------------------------+
* | Usage of this class compared to native php extensions such as |
* | mailparse or imap, is slow and may be feature deficient. If available|
* | you are STRONGLY recommended to use the php extensions. |
* +----------------------------------------------------------------------+
*
* Mime Decoding class
*
* This class will parse a raw mime email and return
* the structure. Returned structure is similar to
* that returned by imap_fetchstructure().
*
* USAGE: (assume $input is your raw email)
*
* $decode = new Mail_mimeDecode($input, "\r\n");
* $structure = $decode->decode();
* print_r($structure);
*
* Or statically:
*
* $params['input'] = $input;
* $structure = Mail_mimeDecode::decode($params);
* print_r($structure);
*
* TODO:
* o Implement multipart/appledouble
* o UTF8: ???

> 4. We have also found a solution for decoding the UTF-8
> headers. Therefore I made the following function:
>
> function decode_utf8($txt) {
> $trans=array("Å&#8216;"=>"õ","ű"=>"û","Å�"=>"Ã&#8226;","Å°"
=>"Ã&#8250;");
> $txt=strtr($txt,$trans);
> return(utf8_decode($txt));
> }
>
> And I have inserted the following line to the class:
>
> if (strtolower($charset)=="utf-8") $text=decode_utf8($text);
>
> ... before the following one in the "_decodeHeader" function:
>
> $input = str_replace($encoded, $text, $input);
>
> This way from now on it can easily decode the UTF-8 headers too.

*
* @author Richard Heyes <richard@phpguru.org>
* @version $Revision: 1.46 $
* @package Mail
*/
class Mail_mimeDecode extends PEAR
{
/**
* The raw email to decode
* @var string
*/
var $_input;

/**
* The header part of the input
* @var string
*/
var $_header;

/**
* The body part of the input
* @var string
*/
var $_body;

/**
* If an error occurs, this is used to store the message
* @var string
*/
var $_error;

/**
* Flag to determine whether to include bodies in the
* returned object.
* @var boolean
*/
var $_include_bodies;

/**
* Flag to determine whether to decode bodies
* @var boolean
*/
var $_decode_bodies;

/**
* Flag to determine whether to decode headers
* @var boolean
*/
var $_decode_headers;

/**
* Constructor.
*
* Sets up the object, initialise the variables, and splits and
* stores the header and body of the input.
*
* @param string The input to decode
* @access public
*/
function Mail_mimeDecode($input)
{
list($header, $body) = $this->_splitBodyHeader($input);

$this->_input = $input;
$this->_header = $header;
$this->_body = $body;
$this->_decode_bodies = false;
$this->_include_bodies = true;
}

/**
* Begins the decoding process. If called statically
* it will create an object and call the decode() method
* of it.
*
* @param array An array of various parameters that determine
* various things:
* include_bodies - Whether to include the body in the returned
* object.
* decode_bodies - Whether to decode the bodies
* of the parts. (Transfer encoding)
* decode_headers - Whether to decode headers
* input - If called statically, this will be treated
* as the input
* @return object Decoded results
* @access public
*/
function decode($params = null)
{
// determine if this method has been called statically
$isStatic = !(isset($this) && get_class($this) == __CLASS__);

// Have we been called statically?
// If so, create an object and pass details to that.
if ($isStatic AND isset($params['input'])) {

$obj = new Mail_mimeDecode($params['input']);
$structure = $obj->decode($params);

// Called statically but no input
} elseif ($isStatic) {
return PEAR::raiseError('Called statically and no input given');

// Called via an object
} else {
$this->_include_bodies = isset($params['include_bodies']) ?
$params['include_bodies'] : false;
$this->_decode_bodies = isset($params['decode_bodies']) ?
$params['decode_bodies'] : false;
$this->_decode_headers = isset($params['decode_headers']) ?
$params['decode_headers'] : false;

$structure = $this->_decode($this->_header, $this->_body);
if ($structure === false) {
$structure = $this->raiseError($this->_error);
}
}

return $structure;
}

/**
* Performs the decoding. Decodes the body string passed to it
* If it finds certain content-types it will call itself in a
* recursive fashion
*
* @param string Header section
* @param string Body section
* @return object Results of decoding process
* @access private
*/
function _decode($headers, $body, $default_ctype = 'text/plain')
{
$return = new stdClass;
$return->headers = array();
$headers = $this->_parseHeaders($headers);

foreach ($headers as $value) {
if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) {
$return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]);
$return->headers[strtolower($value['name'])][] = $value['value'];

} elseif (isset($return->headers[strtolower($value['name'])])) {
$return->headers[strtolower($value['name'])][] = $value['value'];

} else {
$return->headers[strtolower($value['name'])] = $value['value'];
}
}

reset($headers);
while (list($key, $value) = each($headers)) {
$headers[$key]['name'] = strtolower($headers[$key]['name']);
switch ($headers[$key]['name']) {

case 'content-type':
$content_type = $this->_parseHeaderValue($headers[$key]['value']);

if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) {
$return->ctype_primary = $regs[1];
$return->ctype_secondary = $regs[2];
}

if (isset($content_type['other'])) {
while (list($p_name, $p_value) = each($content_type['other'])) {
$return->ctype_parameters[$p_name] = $p_value;
}
}
break;

case 'content-disposition':
$content_disposition = $this->_parseHeaderValue($headers[$key]['value']);
$return->disposition = $content_disposition['value'];
if (isset($content_disposition['other'])) {
while (list($p_name, $p_value) = each($content_disposition['other'])) {
$return->d_parameters[$p_name] = $p_value;
}
}
break;

case 'content-transfer-encoding':
$content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']);
break;
}
}

if (isset($content_type)) {
switch (strtolower($content_type['value'])) {
case 'text/plain':
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
break;

case 'text/html':
$encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null;
break;

case 'multipart/parallel':
case 'multipart/report': // RFC1892
case 'multipart/signed': // PGP
case 'multipart/digest':
case 'multipart/alternative':
case 'multipart/related':
case 'multipart/mixed':
if(!isset($content_type['other']['boundary'])){
$this->_error = 'No boundary found for ' . $content_type['value'] . ' part';
return false;
}

$default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';

$parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
for ($i = 0; $i < count($parts); $i++) {
list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
$part = $this->_decode($part_header, $part_body, $default_ctype);
if($part === false)
$part = $this->raiseError($this->_error);
$return->parts[] = $part;
}
break;

case 'message/rfc822':
$obj = &new Mail_mimeDecode($body);
$return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies,
'decode_bodies' => $this->_decode_bodies,
'decode_headers' => $this->_decode_headers));
unset($obj);
break;

default:
if(!isset($content_transfer_encoding['value']))
$content_transfer_encoding['value'] = '7bit';
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null;
break;
}

} else {
$ctype = explode('/', $default_ctype);
$return->ctype_primary = $ctype[0];
$return->ctype_secondary = $ctype[1];
$this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null;
}

return $return;
}

/**
* Given the output of the above function, this will return an
* array of references to the parts, indexed by mime number.
*
* @param object $structure The structure to go through
* @param string $mime_number Internal use only.
* @return array Mime numbers
*/
function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '')
{
$return = array();
if (!empty($structure->parts)) {
if ($mime_number != '') {
$structure->mime_id = $prepend . $mime_number;
$return[$prepend . $mime_number] = &$structure;
}
for ($i = 0; $i < count($structure->parts); $i++) {

if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') {
$prepend = $prepend . $mime_number . '.';
$_mime_number = '';
} else {
$_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1));
}

$arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend);
foreach ($arr as $key => $val) {
$no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key];
}
}
} else {
if ($mime_number == '') {
$mime_number = '1';
}
$structure->mime_id = $prepend . $mime_number;
$no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure;
}
return $return;
}

/**
* Given a string containing a header and body
* section, this function will split them (at the first
* blank line) and return them.
*
* @param string Input to split apart
* @return array Contains header and body section
* @access private
*/
function _splitBodyHeader($input)
{
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
return array($match[1], $match[2]);
}
$this->_error = 'Could not split header and body';
return false;
}

/**
* Parse headers given in $input and return
* as assoc array.
*
* @param string Headers to parse
* @return array Contains parsed headers
* @access private
*/
function _parseHeaders($input)
{

if ($input !== '') {
// Unfold the input
$input = preg_replace("/\r?\n/", "\r\n", $input);
$input = preg_replace("/\r\n(\t| )+/", ' ', $input);
$headers = explode("\r\n", trim($input));

foreach ($headers as $value) {
$hdr_name = substr($value, 0, $pos = strpos($value, ':'));
$hdr_value = substr($value, $pos+1);
if($hdr_value[0] == ' ')
$hdr_value = substr($hdr_value, 1);

$return[] = array(
'name' => $hdr_name,
'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value
);
}
} else {
$return = array();
}

return $return;
}

/**
* Function to parse a header value,
* extract first part, and any secondary
* parts (after ;) This function is not as
* robust as it could be. Eg. header comments
* in the wrong place will probably break it.
*
* @param string Header value to parse
* @return array Contains parsed result
* @access private
*/
function _parseHeaderValue($input)
{

if (($pos = strpos($input, ';')) !== false) {

$return['value'] = trim(substr($input, 0, $pos));
$input = trim(substr($input, $pos+1));

if (strlen($input) > 0) {

// This splits on a semi-colon, if there's no preceeding backslash
// Now works with quoted values; had to glue the \; breaks in PHP
// the regex is already bordering on incomprehensible
$splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/';
preg_match_all($splitRegex, $input, $matches);
$parameters = array();
for ($i=0; $i<count($matches[0]); $i++) {
$param = $matches[0][$i];
while (substr($param, -2) == '\;') {
$param .= $matches[0][++$i];
}
$parameters[] = $param;
}

for ($i = 0; $i < count($parameters); $i++) {
$param_name = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ ");
$param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ ");
if ($param_value[0] == '"') {
$param_value = substr($param_value, 1, -1);
}
$return['other'][$param_name] = $param_value;
$return['other'][strtolower($param_name)] = $param_value;
}
}
} else {
$return['value'] = trim($input);
}

return $return;
}

/**
* This function splits the input based
* on the given boundary
*
* @param string Input to parse
* @return array Contains array of resulting mime parts
* @access private
*/
function _boundarySplit($input, $boundary)
{
$parts = array();

$bs_possible = substr($boundary, 2, -2);
$bs_check = '\"' . $bs_possible . '\"';

if ($boundary == $bs_check) {
$boundary = $bs_possible;
}

$tmp = explode('--' . $boundary, $input);

for ($i = 1; $i < count($tmp) - 1; $i++) {
$parts[] = $tmp[$i];
}

return $parts;
}

/**
* Given a header, this function will decode it
* according to RFC2047. Probably not *exactly*
* conformant, but it does pass all the given
* examples (in RFC2047).
*
* @param string Input header value to decode
* @return string Decoded header value
* @access private
*/
function _decodeHeader($input)
{
// Remove white space between encoded-words
$input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);

// For each encoded-word...
while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {

$encoded = $matches[1];
$charset = $matches[2];
$encoding = $matches[3];
$text = $matches[4];

switch (strtolower($encoding)) {
case 'b':
$text = base64_decode($text);
break;

case 'q':
$text = str_replace('_', ' ', $text);
preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
foreach($matches[1] as $value)
$text = str_replace('='.$value, chr(hexdec($value)), $text);
break;
}

$input = str_replace($encoded, $text, $input);
}

return $input;
}

/**
* Given a body string and an encoding type,
* this function will decode and return it.
*
* @param string Input body to decode
* @param string Encoding type to use.
* @return string Decoded body
* @access private
*/
function _decodeBody($input, $encoding = '7bit')
{
switch (strtolower($encoding)) {
case '7bit':
return $input;
break;

case 'quoted-printable':
return $this->_quotedPrintableDecode($input);
break;

case 'base64':
return base64_decode($input);
break;

default:
return $input;
}
}

/**
* Given a quoted-printable string, this
* function will decode and return it.
*
* @param string Input body to decode
* @return string Decoded body
* @access private
*/
function _quotedPrintableDecode($input)
{
// Remove soft line breaks
$input = preg_replace("/=\r?\n/", '', $input);

// Replace encoded characters
$input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input);

return $input;
}

/**
* Checks the input for uuencoded files and returns
* an array of them. Can be called statically, eg:
*
* $files =& Mail_mimeDecode::uudecode($some_text);
*
* It will check for the begin 666 ... end syntax
* however and won't just blindly decode whatever you
* pass it.
*
* @param string Input body to look for attahcments in
* @return array Decoded bodies, filenames and permissions
* @access public
* @author Unknown
*/
function &uudecode($input)
{
// Find all uuencoded sections
preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches);

for ($j = 0; $j < count($matches[3]); $j++) {

$str = $matches[3][$j];
$filename = $matches[2][$j];
$fileperm = $matches[1][$j];

$file = '';
$str = preg_split("/\r?\n/", trim($str));
$strlen = count($str);

for ($i = 0; $i < $strlen; $i++) {
$pos = 1;
$d = 0;
$len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077);

while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) {
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
$c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20);
$file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));

$file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));

$file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077));

$pos += 4;
$d += 3;
}

if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) {
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20);
$file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));

$file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2));

$pos += 3;
$d += 2;
}

if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) {
$c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20);
$c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20);
$file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4));

}
}
$files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file);
}

return $files;
}

/**
* getSendArray() returns the arguments required for Mail::send()
* used to build the arguments for a mail::send() call
*
* Usage:
* $mailtext = Full email (for example generated by a template)
* $decoder = new Mail_mimeDecode($mailtext);
* $parts = $decoder->getSendArray();
* if (!PEAR::isError($parts) {
* list($recipents,$headers,$body) = $parts;
* $mail = Mail::factory('smtp');
* $mail->send($recipents,$headers,$body);
* } else {
* echo $parts->message;
* }
* @return mixed array of recipeint, headers,body or Pear_Error
* @access public
* @author Alan Knowles <alan@akbkhome.com>
*/
function getSendArray()
{
// prevent warning if this is not set
$this->_decode_headers = FALSE;
$headerlist =$this->_parseHeaders($this->_header);
$to = "";
if (!$headerlist) {
return $this->raiseError("Message did not contain headers");
}
foreach($headerlist as $item) {
$header[$item['name']] = $item['value'];
switch (strtolower($item['name'])) {
case "to":
case "cc":
case "bcc":
$to = ",".$item['value'];
default:
break;
}
}
if ($to == "") {
return $this->raiseError("Message did not contain any recipents");
}
$to = substr($to,1);
return array($to,$header,$this->_body);
}

/**
* Returns a xml copy of the output of
* Mail_mimeDecode::decode. Pass the output in as the
* argument. This function can be called statically. Eg:
*
* $output = $obj->decode();
* $xml = Mail_mimeDecode::getXML($output);
*
* The DTD used for this should have been in the package. Or
* alternatively you can get it from cvs, or here:
* http://www.phpguru.org/xmail/xmail.dtd.
*
* @param object Input to convert to xml. This should be the
* output of the Mail_mimeDecode::decode function
* @return string XML version of input
* @access public
*/
function getXML($input)
{
$crlf = "\r\n";
$output = '<?xml version=\'1.0\'?>' . $crlf .
'<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf .
'<email>' . $crlf .
Mail_mimeDecode::_getXML($input) .
'</email>';

return $output;
}

/**
* Function that does the actual conversion to xml. Does a single
* mimepart at a time.
*
* @param object Input to convert to xml. This is a mimepart object.
* It may or may not contain subparts.
* @param integer Number of tabs to indent
* @return string XML version of input
* @access private
*/
function _getXML($input, $indent = 1)
{
$htab = "\t";
$crlf = "\r\n";
$output = '';
$headers = @(array)$input->headers;

foreach ($headers as $hdr_name => $hdr_value) {

// Multiple headers with this name
if (is_array($headers[$hdr_name])) {
for ($i = 0; $i < count($hdr_value); $i++) {
$output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent);
}

// Only one header of this sort
} else {
$output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent);
}
}

if (!empty($input->parts)) {
for ($i = 0; $i < count($input->parts); $i++) {
$output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf .
Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) .
str_repeat($htab, $indent) . '</mimepart>' . $crlf;
}
} elseif (isset($input->body)) {
$output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' .
$input->body . ']]></body>' . $crlf;
}

return $output;
}

/**
* Helper function to _getXML(). Returns xml of a header.
*
* @param string Name of header
* @param string Value of header
* @param integer Number of tabs to indent
* @return string XML version of input
* @access private
*/
function _getXML_helper($hdr_name, $hdr_value, $indent)
{
$htab = "\t";
$crlf = "\r\n";
$return = '';

$new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value);
$new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name)));

// Sort out any parameters
if (!empty($new_hdr_value['other'])) {
foreach ($new_hdr_value['other'] as $paramname => $paramvalue) {
$params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf .
str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf .
str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf .
str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf;
}

$params = implode('', $params);
} else {
$params = '';
}

$return = str_repeat($htab, $indent) . '<header>' . $crlf .
str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf .
str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf .
$params .
str_repeat($htab, $indent) . '</header>' . $crlf;

return $return;
}

} // End of class
?>

+ 351
- 0
trunk/docs/include/PEAR/Mail/mimePart.php Näytä tiedosto

@@ -0,0 +1,351 @@
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2003 Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard@phpguru.org> |
// +-----------------------------------------------------------------------+

/**
*
* Raw mime encoding class
*
* What is it?
* This class enables you to manipulate and build
* a mime email from the ground up.
*
* Why use this instead of mime.php?
* mime.php is a userfriendly api to this class for
* people who aren't interested in the internals of
* mime mail. This class however allows full control
* over the email.
*
* Eg.
*
* // Since multipart/mixed has no real body, (the body is
* // the subpart), we set the body argument to blank.
*
* $params['content_type'] = 'multipart/mixed';
* $email = new Mail_mimePart('', $params);
*
* // Here we add a text part to the multipart we have
* // already. Assume $body contains plain text.
*
* $params['content_type'] = 'text/plain';
* $params['encoding'] = '7bit';
* $text = $email->addSubPart($body, $params);
*
* // Now add an attachment. Assume $attach is
* the contents of the attachment
*
* $params['content_type'] = 'application/zip';
* $params['encoding'] = 'base64';
* $params['disposition'] = 'attachment';
* $params['dfilename'] = 'example.zip';
* $attach =& $email->addSubPart($body, $params);
*
* // Now build the email. Note that the encode
* // function returns an associative array containing two
* // elements, body and headers. You will need to add extra
* // headers, (eg. Mime-Version) before sending.
*
* $email = $message->encode();
* $email['headers'][] = 'Mime-Version: 1.0';
*
*
* Further examples are available at http://www.phpguru.org
*
* TODO:
* - Set encode() to return the $obj->encoded if encode()
* has already been run. Unless a flag is passed to specifically
* re-build the message.
*
* @author Richard Heyes <richard@phpguru.org>
* @version $Revision: 1.13 $
* @package Mail
*/

class Mail_mimePart {

/**
* The encoding type of this part
* @var string
*/
var $_encoding;

/**
* An array of subparts
* @var array
*/
var $_subparts;

/**
* The output of this part after being built
* @var string
*/
var $_encoded;

/**
* Headers for this part
* @var array
*/
var $_headers;

/**
* The body of this part (not encoded)
* @var string
*/
var $_body;

/**
* Constructor.
*
* Sets up the object.
*
* @param $body - The body of the mime part if any.
* @param $params - An associative array of parameters:
* content_type - The content type for this part eg multipart/mixed
* encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable
* cid - Content ID to apply
* disposition - Content disposition, inline or attachment
* dfilename - Optional filename parameter for content disposition
* description - Content description
* charset - Character set to use
* @access public
*/
function Mail_mimePart($body = '', $params = array())
{
if (!defined('MAIL_MIMEPART_CRLF')) {
define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE);
}

foreach ($params as $key => $value) {
switch ($key) {
case 'content_type':
$headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : '');
break;

case 'encoding':
$this->_encoding = $value;
$headers['Content-Transfer-Encoding'] = $value;
break;

case 'cid':
$headers['Content-ID'] = '<' . $value . '>';
break;

case 'disposition':
$headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');
break;

case 'dfilename':
if (isset($headers['Content-Disposition'])) {
$headers['Content-Disposition'] .= '; filename="' . $value . '"';
} else {
$dfilename = $value;
}
break;

case 'description':
$headers['Content-Description'] = $value;
break;

case 'charset':
if (isset($headers['Content-Type'])) {
$headers['Content-Type'] .= '; charset="' . $value . '"';
} else {
$charset = $value;
}
break;
}
}

// Default content-type
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'text/plain';
}

//Default encoding
if (!isset($this->_encoding)) {
$this->_encoding = '7bit';
}

// Assign stuff to member variables
$this->_encoded = array();
$this->_headers = $headers;
$this->_body = $body;
}

/**
* encode()
*
* Encodes and returns the email. Also stores
* it in the encoded member variable
*
* @return An associative array containing two elements,
* body and headers. The headers element is itself
* an indexed array.
* @access public
*/
function encode()
{
$encoded =& $this->_encoded;

if (!empty($this->_subparts)) {
srand((double)microtime()*1000000);
$boundary = '=_' . md5(rand() . microtime());
$this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"';

// Add body parts to $subparts
for ($i = 0; $i < count($this->_subparts); $i++) {
$headers = array();
$tmp = $this->_subparts[$i]->encode();
foreach ($tmp['headers'] as $key => $value) {
$headers[] = $key . ': ' . $value;
}
$subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'];
}

$encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .
implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .
'--' . $boundary.'--' . MAIL_MIMEPART_CRLF;

} else {
$encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF;
}

// Add headers to $encoded
$encoded['headers'] =& $this->_headers;

return $encoded;
}

/**
* &addSubPart()
*
* Adds a subpart to current mime part and returns
* a reference to it
*
* @param $body The body of the subpart, if any.
* @param $params The parameters for the subpart, same
* as the $params argument for constructor.
* @return A reference to the part you just added. It is
* crucial if using multipart/* in your subparts that
* you use =& in your script when calling this function,
* otherwise you will not be able to add further subparts.
* @access public
*/
function &addSubPart($body, $params)
{
$this->_subparts[] = new Mail_mimePart($body, $params);
return $this->_subparts[count($this->_subparts) - 1];
}

/**
* _getEncodedData()
*
* Returns encoded data based upon encoding passed to it
*
* @param $data The data to encode.
* @param $encoding The encoding type to use, 7bit, base64,
* or quoted-printable.
* @access private
*/
function _getEncodedData($data, $encoding)
{
switch ($encoding) {
case '8bit':
case '7bit':
return $data;
break;

case 'quoted-printable':
return $this->_quotedPrintableEncode($data);
break;

case 'base64':
return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF));
break;

default:
return $data;
}
}

/**
* quoteadPrintableEncode()
*
* Encodes data to quoted-printable standard.
*
* @param $input The data to encode
* @param $line_max Optional max line length. Should
* not be more than 76 chars
*
* @access private
*/
function _quotedPrintableEncode($input , $line_max = 76)
{
$lines = preg_split("/\r?\n/", $input);
$eol = MAIL_MIMEPART_CRLF;
$escape = '=';
$output = '';

while(list(, $line) = each($lines)){

$linlen = strlen($line);
$newline = '';

for ($i = 0; $i < $linlen; $i++) {
$char = substr($line, $i, 1);
$dec = ord($char);

if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only
$char = '=20';

} elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only
$char = '=09';
} elseif($dec == 9) {
; // Do nothing if a tab.
} elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {
$char = $escape . strtoupper(sprintf('%02s', dechex($dec)));
}

if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted
$output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay
$newline = '';
}
$newline .= $char;
} // end of for
$output .= $newline . $eol;
}
$output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf
return $output;
}
} // End of class
?>

+ 19
- 0
trunk/docs/include/PEAR/Mail/xmail.dtd Näytä tiedosto

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="ISO-8859-1"?>

<!ENTITY lt "&#38;#60;">
<!ENTITY gt "&#62;">
<!ENTITY amp "&#38;#38;">
<!ENTITY apos "&#39;">
<!ENTITY quot "&#34;">
<!ENTITY crlf "&#13;&#10;">

<!ELEMENT email (header+, (body | mimepart+))>
<!ELEMENT mimepart (header+, (body | mimepart+))>
<!ELEMENT body (#PCDATA)>
<!ELEMENT header ((headername|headervalue|parameter)*)>
<!ELEMENT headername (#PCDATA)>
<!ELEMENT headervalue (#PCDATA)>
<!ELEMENT parameter ((paramname|paramvalue)+)>
<!ELEMENT paramvalue (#PCDATA)>
<!ELEMENT paramname (#PCDATA)>


+ 70
- 0
trunk/docs/include/PEAR/Mail/xmail.xsl Näytä tiedosto

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:preserve-space elements="headervalue paramvalue body"/>

<xsl:template name="mimepart">

<xsl:variable name="boundary">
<xsl:for-each select="./header">
<xsl:if test="string(./headername) = 'Content-Type'">
<xsl:for-each select="./parameter">
<xsl:if test="string(./paramname) = 'boundary'">
<xsl:value-of select="paramvalue"/>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:variable>

<xsl:for-each select="header">

<xsl:value-of select="headername"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="headervalue"/>

<xsl:if test="count(./parameter) = 0">
<xsl:text>&#13;&#10;</xsl:text>
</xsl:if>

<xsl:for-each select="parameter">
<xsl:text>;&#13;&#10;&#09;</xsl:text>
<xsl:value-of select="paramname"/>
<xsl:text>="</xsl:text>
<xsl:value-of select="paramvalue"/>
<xsl:text>"</xsl:text>
</xsl:for-each>

<xsl:if test="count(./parameter) > 0">
<xsl:text>&#13;&#10;</xsl:text>
</xsl:if>

</xsl:for-each>

<xsl:text>&#13;&#10;</xsl:text>

<!-- Which to do, print a body or process subparts? -->
<xsl:choose>
<xsl:when test="count(./mimepart) = 0">
<xsl:value-of select="body"/>
<xsl:text>&#13;&#10;</xsl:text>
</xsl:when>

<xsl:otherwise>
<xsl:for-each select="mimepart">
<xsl:text>--</xsl:text><xsl:value-of select="$boundary"/><xsl:text>&#13;&#10;</xsl:text>
<xsl:call-template name="mimepart"/>
</xsl:for-each>

<xsl:text>--</xsl:text><xsl:value-of select="$boundary"/><xsl:text>--&#13;&#10;</xsl:text>

</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!-- This is where the stylesheet really starts, matching the top level email element -->
<xsl:template match="email">
<xsl:call-template name="mimepart"/>
</xsl:template>

</xsl:stylesheet>

+ 629
- 0
trunk/docs/include/PEAR/Net/DIME.php Näytä tiedosto

@@ -0,0 +1,629 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Shane Caraveo <shane@caraveo.com> |
// | Ralf Hofmann <ralf.hofmann@verdisoft.com> |
// +----------------------------------------------------------------------+
//
// $Id: DIME.php,v 1.5 2002/09/29 01:55:16 shane Exp $
//

require_once 'PEAR.php';
/**
*
* DIME Encoding/Decoding
*
* What is it?
* This class enables you to manipulate and build
* a DIME encapsulated message.
*
* http://www.ietf.org/internet-drafts/draft-nielsen-dime-02.txt
*
* 09/18/02 Ralf - A huge number of changes to be compliant
* with the DIME Specification Release 17 June 2002
*
* TODO: lots of stuff needs to be tested.
* Definitily have to go through DIME spec and
* make things work right, most importantly, sec 3.3
* make examples, document
*
* see test/dime_mesage_test.php for example of usage
*
* @author Shane Caraveo <shane@caraveo.com>,
* Ralf Hofmann <ralf.hofmann@verdisoft.com>
* @version $Revision: 1.5 $
* @package Net_DIME
*/
define('NET_DIME_TYPE_UNCHANGED',0x00);
define('NET_DIME_TYPE_MEDIA',0x01);
define('NET_DIME_TYPE_URI',0x02);
define('NET_DIME_TYPE_UNKNOWN',0x03);
define('NET_DIME_TYPE_NONE',0x04);

define('NET_DIME_VERSION',0x0001);

define('NET_DIME_RECORD_HEADER',12);

define('NET_DIME_FLAGS', 0);
define('NET_DIME_OPTS_LEN', 1);
define('NET_DIME_ID_LEN', 2);
define('NET_DIME_TYPE_LEN', 3);
define('NET_DIME_DATA_LEN', 4);
define('NET_DIME_OPTS', 5);
define('NET_DIME_ID', 6);
define('NET_DIME_TYPE', 7);
define('NET_DIME_DATA', 8);

class Net_DIME_Record extends PEAR
{
// these are used to hold the padded length
var $OPTS_LENGTH = 0;
var $ID_LENGTH = 0;
var $TYPE_LENGTH = 0;
var $DATA_LENGTH = 0;
var $_haveOpts = FALSE;
var $_haveID = FALSE;
var $_haveType = FALSE;
var $_haveData = FALSE;
var $debug = FALSE;
var $padstr = "\0";
/**
* Elements
* [NET_DIME_FLAGS], 16 bits: VERSION:MB:ME:CF:TYPE_T
* [NET_DIME_OPTS_LEN], 16 bits: OPTIONS_LENGTH
* [NET_DIME_ID_LEN], 16 bits: ID_LENGTH
* [NET_DIME_TYPE_LEN], 16 bits: TYPE_LENGTH
* [NET_DIME_DATA_LEN], 32 bits: DATA_LENGTH
* [NET_DIME_OPTS] : OPTIONS
* [NET_DIME_ID] : ID
* [NET_DIME_TYPE] : TYPE
* [NET_DIME_DATA] : DATA
*/
var $Elements = array(NET_DIME_FLAGS => 0, NET_DIME_OPTS_LEN => 0,
NET_DIME_ID_LEN => 0, NET_DIME_TYPE_LEN => 0,
NET_DIME_DATA_LEN => 0,
NET_DIME_OPTS => '',
NET_DIME_ID => '',
NET_DIME_TYPE => '',
NET_DIME_DATA => '');
function Net_DIME_Record($debug = FALSE)
{
$this->debug = $debug;
if ($debug) $this->padstr = '*';
}

function setMB()
{
$this->Elements[NET_DIME_FLAGS] |= 0x0400;
}

function setME()
{
$this->Elements[NET_DIME_FLAGS] |= 0x0200;
}

function setCF()
{
$this->Elements[NET_DIME_FLAGS] |= 0x0100;
}

function isChunk()
{
return $this->Elements[NET_DIME_FLAGS] & 0x0100;
}

function isEnd()
{
return $this->Elements[NET_DIME_FLAGS] & 0x0200;
}
function isStart()
{
return $this->Elements[NET_DIME_FLAGS] & 0x0400;
}
function getID()
{
return $this->Elements[NET_DIME_ID];
}

function getType()
{
return $this->Elements[NET_DIME_TYPE];
}

function getData()
{
return $this->Elements[NET_DIME_DATA];
}
function getDataLength()
{
return $this->Elements[NET_DIME_DATA_LEN];
}
function setType($typestring, $type=NET_DIME_TYPE_UNKNOWN)
{
$typelen = strlen($typestring) & 0xFFFF;
$type = $type << 4;
$this->Elements[NET_DIME_FLAGS] = ($this->Elements[NET_DIME_FLAGS] & 0xFF0F) | $type;
$this->Elements[NET_DIME_TYPE_LEN] = $typelen;
$this->TYPE_LENGTH = $this->_getPadLength($typelen);
$this->Elements[NET_DIME_TYPE] = $typestring;
}
function generateID()
{
$id = md5(time());
$this->setID($id);
return $id;
}
function setID($id)
{
$idlen = strlen($id) & 0xFFFF;
$this->Elements[NET_DIME_ID_LEN] = $idlen;
$this->ID_LENGTH = $this->_getPadLength($idlen);
$this->Elements[NET_DIME_ID] = $id;
}
function setData($data, $size=0)
{
$datalen = $size?$size:strlen($data);
$this->Elements[NET_DIME_DATA_LEN] = $datalen;
$this->DATA_LENGTH = $this->_getPadLength($datalen);
$this->Elements[NET_DIME_DATA] = $data;
}
function encode()
{
// insert version
$this->Elements[NET_DIME_FLAGS] = ($this->Elements[NET_DIME_FLAGS] & 0x07FF) | (NET_DIME_VERSION << 11);

// the real dime encoding
$format = '%c%c%c%c%c%c%c%c%c%c%c%c'.
'%'.$this->OPTS_LENGTH.'s'.
'%'.$this->ID_LENGTH.'s'.
'%'.$this->TYPE_LENGTH.'s'.
'%'.$this->DATA_LENGTH.'s';
return sprintf($format,
($this->Elements[NET_DIME_FLAGS]&0x0000FF00)>>8,
($this->Elements[NET_DIME_FLAGS]&0x000000FF),
($this->Elements[NET_DIME_OPTS_LEN]&0x0000FF00)>>8,
($this->Elements[NET_DIME_OPTS_LEN]&0x000000FF),
($this->Elements[NET_DIME_ID_LEN]&0x0000FF00)>>8,
($this->Elements[NET_DIME_ID_LEN]&0x000000FF),
($this->Elements[NET_DIME_TYPE_LEN]&0x0000FF00)>>8,
($this->Elements[NET_DIME_TYPE_LEN]&0x000000FF),
($this->Elements[NET_DIME_DATA_LEN]&0xFF000000)>>24,
($this->Elements[NET_DIME_DATA_LEN]&0x00FF0000)>>16,
($this->Elements[NET_DIME_DATA_LEN]&0x0000FF00)>>8,
($this->Elements[NET_DIME_DATA_LEN]&0x000000FF),
str_pad($this->Elements[NET_DIME_OPTS], $this->OPTS_LENGTH, $this->padstr),
str_pad($this->Elements[NET_DIME_ID], $this->ID_LENGTH, $this->padstr),
str_pad($this->Elements[NET_DIME_TYPE], $this->TYPE_LENGTH, $this->padstr),
str_pad($this->Elements[NET_DIME_DATA], $this->DATA_LENGTH, $this->padstr));
}
function _getPadLength($len)
{
$pad = 0;
if ($len) {
$pad = $len % 4;
if ($pad) $pad = 4 - $pad;
}
return $len + $pad;
}
function decode(&$data)
{
// REAL DIME decoding
$this->Elements[NET_DIME_FLAGS] = (hexdec(bin2hex($data[0]))<<8) + hexdec(bin2hex($data[1]));
$this->Elements[NET_DIME_OPTS_LEN] = (hexdec(bin2hex($data[2]))<<8) + hexdec(bin2hex($data[3]));
$this->Elements[NET_DIME_ID_LEN] = (hexdec(bin2hex($data[4]))<<8) + hexdec(bin2hex($data[5]));
$this->Elements[NET_DIME_TYPE_LEN] = (hexdec(bin2hex($data[6]))<<8) + hexdec(bin2hex($data[7]));
$this->Elements[NET_DIME_DATA_LEN] = (hexdec(bin2hex($data[8]))<<24) +
(hexdec(bin2hex($data[9]))<<16) +
(hexdec(bin2hex($data[10]))<<8) +
hexdec(bin2hex($data[11]));
$p = 12;
$version = (($this->Elements[NET_DIME_FLAGS]>>11) & 0x001F);
if ($version == NET_DIME_VERSION)
{
$this->OPTS_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_OPTS_LEN]);
$this->ID_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_ID_LEN]);
$this->TYPE_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_TYPE_LEN]);
$this->DATA_LENGTH = $this->_getPadLength($this->Elements[NET_DIME_DATA_LEN]);
$datalen = strlen($data);
$this->Elements[NET_DIME_OPTS] = substr($data,$p,$this->Elements[NET_DIME_OPTS_LEN]);
$this->_haveOpts = (strlen($this->Elements[NET_DIME_OPTS]) == $this->Elements[NET_DIME_OPTS_LEN]);
if ($this->_haveOpts) {
$p += $this->OPTS_LENGTH;
$this->Elements[NET_DIME_ID] = substr($data,$p,$this->Elements[NET_DIME_ID_LEN]);
$this->_haveID = (strlen($this->Elements[NET_DIME_ID]) == $this->Elements[NET_DIME_ID_LEN]);
if ($this->_haveID) {
$p += $this->ID_LENGTH;
$this->Elements[NET_DIME_TYPE] = substr($data,$p,$this->Elements[NET_DIME_TYPE_LEN]);
$this->_haveType = (strlen($this->Elements[NET_DIME_TYPE]) == $this->Elements[NET_DIME_TYPE_LEN]);
if ($this->_haveType) {
$p += $this->TYPE_LENGTH;
$this->Elements[NET_DIME_DATA] = substr($data,$p,$this->Elements[NET_DIME_DATA_LEN]);
$this->_haveData = (strlen($this->Elements[NET_DIME_DATA]) == $this->Elements[NET_DIME_DATA_LEN]);
if ($this->_haveData) {
$p += $this->DATA_LENGTH;
} else {
$p += strlen($this->Elements[NET_DIME_DATA]);
}
} else {
$p += strlen($this->Elements[NET_DIME_TYPE]);
}
} else {
$p += strlen($this->Elements[NET_DIME_ID]);
}
} else {
$p += strlen($this->Elements[NET_DIME_OPTS]);
}
}
return substr($data, $p);
}
function addData(&$data)
{
$datalen = strlen($data);
$p = 0;
if (!$this->_haveOpts) {
$have = strlen($this->Elements[NET_DIME_OPTS]);
$this->Elements[NET_DIME_OPTS] .= substr($data,$p,$this->Elements[NET_DIME_OPTS_LEN]-$have);
$this->_haveOpts = (strlen($this->Elements[NET_DIME_OPTS]) == $this->Elements[DIME_OTPS_LEN]);
if (!$this->_haveOpts) return NULL;
$p += $this->OPTS_LENGTH-$have;
}
if (!$this->_haveID) {
$have = strlen($this->Elements[NET_DIME_ID]);
$this->Elements[NET_DIME_ID] .= substr($data,$p,$this->Elements[NET_DIME_ID_LEN]-$have);
$this->_haveID = (strlen($this->Elements[NET_DIME_ID]) == $this->Elements[NET_DIME_ID_LEN]);
if (!$this->_haveID) return NULL;
$p += $this->ID_LENGTH-$have;
}
if (!$this->_haveType && $p < $datalen) {
$have = strlen($this->Elements[NET_DIME_TYPE]);
$this->Elements[NET_DIME_TYPE] .= substr($data,$p,$this->Elements[NET_DIME_TYPE_LEN]-$have);
$this->_haveType = (strlen($this->Elements[NET_DIME_TYPE]) == $this->Elements[NET_DIME_TYPE_LEN]);
if (!$this->_haveType) return NULL;
$p += $this->TYPE_LENGTH-$have;
}
if (!$this->_haveData && $p < $datalen) {
$have = strlen($this->Elements[NET_DIME_DATA]);
$this->Elements[NET_DIME_DATA] .= substr($data,$p,$this->Elements[NET_DIME_DATA_LEN]-$have);
$this->_haveData = (strlen($this->Elements[NET_DIME_DATA]) == $this->Elements[NET_DIME_DATA_LEN]);
if (!$this->_haveData) return NULL;
$p += $this->DATA_LENGTH-$have;
}
return substr($data,$p);
}
}


class Net_DIME_Message extends PEAR
{

var $record_size = 4096;
#var $records =array();
var $parts = array();
var $currentPart = -1;
var $stream = NULL;
var $_currentRecord;
var $_proc = array();
var $type;
var $typestr;
var $mb = 1;
var $me = 0;
var $cf = 0;
var $id = NULL;
var $debug = FALSE;
/**
* constructor
*
* this currently takes a file pointer as provided
* by fopen
*
* TODO: integrate with the php streams stuff
*/
function Net_DIME_Message($stream=NULL, $record_size = 4096, $debug = FALSE)
{
$this->stream = $stream;
$this->record_size = $record_size;
$this->debug = $debug;
}
function _makeRecord(&$data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
{
$record = new Net_DIME_Record($this->debug);
if ($this->mb) {
$record->setMB();
// all subsequent records are not message begin!
$this->mb = 0;
}
if ($this->me) $record->setME();
if ($this->cf) $record->setCF();
$record->setData($data);
$record->setType($typestr,$type);
if ($id) $record->setID($id);
#if ($this->debug) {
# print str_replace('\0','*',$record->encode());
#}
return $record->encode();
}
function startChunk(&$data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
{
$this->me = 0;
$this->cf = 1;
$this->type = $type;
$this->typestr = $typestr;
if ($id) {
$this->id = $id;
} else {
$this->id = md5(time());
}
return $this->_makeRecord($data, $this->typestr, $this->id, $this->type);
}

function doChunk(&$data)
{
$this->me = 0;
$this->cf = 1;
return $this->_makeRecord($data, NULL, NULL, NET_DIME_TYPE_UNCHANGED);
}

function endChunk()
{
$this->cf = 0;
$data = NULL;
$rec = $this->_makeRecord($data, NULL, NULL, NET_DIME_TYPE_UNCHANGED);
$this->id = 0;
$this->cf = 0;
$this->id = 0;
$this->type = NET_DIME_TYPE_UNKNOWN;
$this->typestr = NULL;
return $rec;
}
function endMessage()
{
$this->me = 1;
$data = NULL;
$rec = $this->_makeRecord($data, NULL, NULL, NET_DIME_TYPE_NONE);
$this->me = 0;
$this->mb = 1;
$this->id = 0;
return $rec;
}
/**
* sendRecord
*
* given a chunk of data, it creates DIME records
* and writes them to the stream
*
*/
function sendData(&$data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
{
$len = strlen($data);
if ($len > $this->record_size) {
$chunk = substr($data, 0, $this->record_size);
$p = $this->record_size;
$rec = $this->startChunk($chunk,$typestr,$id,$type);
fwrite($this->stream, $rec);
while ($p < $len) {
$chunk = substr($data, $p, $this->record_size);
$p += $this->record_size;
$rec = $this->doChunk($chunk);
fwrite($this->stream, $rec);
}
$rec = $this->endChunk();
fwrite($this->stream, $rec);
return;
}
$rec = $this->_makeRecord($data, $typestr,$id,$type);
fwrite($this->stream, $rec);
}
function sendEndMessage()
{
$rec = $this->endMessage();
fwrite($this->stream, $rec);
}
/**
* sendFile
*
* given a filename, it reads the file,
* creates records and writes them to the stream
*
*/
function sendFile($filename, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
{
$f = fopen($filename, "rb");
if ($f) {
if ($data = fread($f, $this->record_size)) {
$this->startChunk($data,$typestr,$id,$type);
}
while ($data = fread($f, $this->record_size)) {
$this->doChunk($data,$typestr,$id,$type);
}
$this->endChunk();
fclose($f);
}
}

/**
* encodeData
*
* given data, encode it in DIME
*
*/
function encodeData($data, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
{
$len = strlen($data);
$resp = '';
if ($len > $this->record_size) {
$chunk = substr($data, 0, $this->record_size);
$p = $this->record_size;
$resp .= $this->startChunk($chunk,$typestr,$id,$type);
while ($p < $len) {
$chunk = substr($data, $p, $this->record_size);
$p += $this->record_size;
$resp .= $this->doChunk($chunk);
}
$resp .= $this->endChunk();
} else {
$resp .= $this->_makeRecord($data, $typestr,$id,$type);
}
return $resp;
}

/**
* sendFile
*
* given a filename, it reads the file,
* creates records and writes them to the stream
*
*/
function encodeFile($filename, $typestr='', $id=NULL, $type=NET_DIME_TYPE_UNKNOWN)
{
$f = fopen($filename, "rb");
if ($f) {
if ($data = fread($f, $this->record_size)) {
$resp = $this->startChunk($data,$typestr,$id,$type);
}
while ($data = fread($f, $this->record_size)) {
$resp = $this->doChunk($data,$typestr,$id,$type);
}
$resp = $this->endChunk();
fclose($f);
}
return $resp;
}
/**
* _processData
*
* creates Net_DIME_Records from provided data
*
*/
function _processData(&$data)
{
$leftover = NULL;
if (!$this->_currentRecord) {
$this->_currentRecord = new Net_DIME_Record($this->debug);
$data = $this->_currentRecord->decode($data);
} else {
$data = $this->_currentRecord->addData($data);
}
if ($this->_currentRecord->_haveData) {
if (count($this->parts)==0 && !$this->_currentRecord->isStart()) {
// raise an error!
return PEAR::raiseError('First Message is not a DIME begin record!');
}

if ($this->_currentRecord->isEnd() && $this->_currentRecord->getDataLength()==0) {
return NULL;
}
if ($this->currentPart < 0 && !$this->_currentRecord->isChunk()) {
$this->parts[] = array();
$this->currentPart = count($this->parts)-1;
$this->parts[$this->currentPart]['id'] = $this->_currentRecord->getID();
$this->parts[$this->currentPart]['type'] = $this->_currentRecord->getType();
$this->parts[$this->currentPart]['data'] = $this->_currentRecord->getData();
$this->currentPart = -1;
} else {
if ($this->currentPart < 0) {
$this->parts[] = array();
$this->currentPart = count($this->parts)-1;
$this->parts[$this->currentPart]['id'] = $this->_currentRecord->getID();
$this->parts[$this->currentPart]['type'] = $this->_currentRecord->getType();
$this->parts[$this->currentPart]['data'] = $this->_currentRecord->getData();
} else {
$this->parts[$this->currentPart]['data'] .= $this->_currentRecord->getData();
if (!$this->_currentRecord->isChunk()) {
// we reached the end of the chunk
$this->currentPart = -1;
}
}
}
#$this->records[] = $this->_currentRecord;
if (!$this->_currentRecord->isEnd()) $this->_currentRecord = NULL;
}
return NULL;
}
/**
* decodeData
*
* decodes a DIME encrypted string of data
*
*/
function decodeData(&$data) {
while (strlen($data) >= NET_DIME_RECORD_HEADER) {
$err = $this->_processData($data);
if (PEAR::isError($err)) {
return $err;
}
}
}
/**
* read
*
* reads the stream and creates
* an array of records
*
* it can accept the start of a previously read buffer
* this is usefull in situations where you need to read
* headers before discovering that the data is DIME encoded
* such as in the case of reading an HTTP response.
*/
function read($buf=NULL)
{
while ($data = fread($this->stream, 8192)) {
if ($buf) {
$data = $buf.$data;
$buf = NULL;
}
if ($this->debug)
echo "read: ".strlen($data)." bytes\n";
$err = $this->decodeData($data);
if (PEAR::isError($err)) {
return $err;
}
// store any leftover data to be used again
// should be < NET_DIME_RECORD_HEADER bytes
$buf = $data;
}
if (!$this->_currentRecord || !$this->_currentRecord->isEnd()) {
return PEAR::raiseError('reached stream end without end record');
}
return NULL;
}
}
?>

+ 554
- 0
trunk/docs/include/PEAR/Net/Socket.php Näytä tiedosto

@@ -0,0 +1,554 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Stig Bakken <ssb@php.net> |
// | Chuck Hagenbuch <chuck@horde.org> |
// +----------------------------------------------------------------------+
//
// $Id: Socket.php,v 1.28 2006/12/13 21:32:03 cweiske Exp $

require_once 'PEAR.php';

define('NET_SOCKET_READ', 1);
define('NET_SOCKET_WRITE', 2);
define('NET_SOCKET_ERROR', 4);

/**
* Generalized Socket class.
*
* @version 1.1
* @author Stig Bakken <ssb@php.net>
* @author Chuck Hagenbuch <chuck@horde.org>
*/
class Net_Socket extends PEAR {

/**
* Socket file pointer.
* @var resource $fp
*/
var $fp = null;

/**
* Whether the socket is blocking. Defaults to true.
* @var boolean $blocking
*/
var $blocking = true;

/**
* Whether the socket is persistent. Defaults to false.
* @var boolean $persistent
*/
var $persistent = false;

/**
* The IP address to connect to.
* @var string $addr
*/
var $addr = '';

/**
* The port number to connect to.
* @var integer $port
*/
var $port = 0;

/**
* Number of seconds to wait on socket connections before assuming
* there's no more data. Defaults to no timeout.
* @var integer $timeout
*/
var $timeout = false;

/**
* Number of bytes to read at a time in readLine() and
* readAll(). Defaults to 2048.
* @var integer $lineLength
*/
var $lineLength = 2048;

/**
* Connect to the specified port. If called when the socket is
* already connected, it disconnects and connects again.
*
* @param string $addr IP address or host name.
* @param integer $port TCP port number.
* @param boolean $persistent (optional) Whether the connection is
* persistent (kept open between requests
* by the web server).
* @param integer $timeout (optional) How long to wait for data.
* @param array $options See options for stream_context_create.
*
* @access public
*
* @return boolean | PEAR_Error True on success or a PEAR_Error on failure.
*/
function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null)
{
if (is_resource($this->fp)) {
@fclose($this->fp);
$this->fp = null;
}

if (!$addr) {
return $this->raiseError('$addr cannot be empty');
} elseif (strspn($addr, '.0123456789') == strlen($addr) ||
strstr($addr, '/') !== false) {
$this->addr = $addr;
} else {
$this->addr = @gethostbyname($addr);
}

$this->port = $port % 65536;

if ($persistent !== null) {
$this->persistent = $persistent;
}

if ($timeout !== null) {
$this->timeout = $timeout;
}

$openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
$errno = 0;
$errstr = '';
if ($options && function_exists('stream_context_create')) {
if ($this->timeout) {
$timeout = $this->timeout;
} else {
$timeout = 0;
}
$context = stream_context_create($options);
$fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
} else {
if ($this->timeout) {
$fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
} else {
$fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
}
}

if (!$fp) {
return $this->raiseError($errstr, $errno);
}

$this->fp = $fp;

return $this->setBlocking($this->blocking);
}

/**
* Disconnects from the peer, closes the socket.
*
* @access public
* @return mixed true on success or an error object otherwise
*/
function disconnect()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

@fclose($this->fp);
$this->fp = null;
return true;
}

/**
* Find out if the socket is in blocking mode.
*
* @access public
* @return boolean The current blocking mode.
*/
function isBlocking()
{
return $this->blocking;
}

/**
* Sets whether the socket connection should be blocking or
* not. A read call to a non-blocking socket will return immediately
* if there is no data available, whereas it will block until there
* is data for blocking sockets.
*
* @param boolean $mode True for blocking sockets, false for nonblocking.
* @access public
* @return mixed true on success or an error object otherwise
*/
function setBlocking($mode)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$this->blocking = $mode;
socket_set_blocking($this->fp, $this->blocking);
return true;
}

/**
* Sets the timeout value on socket descriptor,
* expressed in the sum of seconds and microseconds
*
* @param integer $seconds Seconds.
* @param integer $microseconds Microseconds.
* @access public
* @return mixed true on success or an error object otherwise
*/
function setTimeout($seconds, $microseconds)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

return socket_set_timeout($this->fp, $seconds, $microseconds);
}

/**
* Sets the file buffering size on the stream.
* See php's stream_set_write_buffer for more information.
*
* @param integer $size Write buffer size.
* @access public
* @return mixed on success or an PEAR_Error object otherwise
*/
function setWriteBuffer($size)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$returned = stream_set_write_buffer($this->fp, $code);
if ($returned == 0) {
return true;
}
return $this->raiseError('Cannot set write buffer.');
}

/**
* Returns information about an existing socket resource.
* Currently returns four entries in the result array:
*
* <p>
* timed_out (bool) - The socket timed out waiting for data<br>
* blocked (bool) - The socket was blocked<br>
* eof (bool) - Indicates EOF event<br>
* unread_bytes (int) - Number of bytes left in the socket buffer<br>
* </p>
*
* @access public
* @return mixed Array containing information about existing socket resource or an error object otherwise
*/
function getStatus()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

return socket_get_status($this->fp);
}

/**
* Get a specified line of data
*
* @access public
* @return $size bytes of data from the socket, or a PEAR_Error if
* not connected.
*/
function gets($size)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

return @fgets($this->fp, $size);
}

/**
* Read a specified amount of data. This is guaranteed to return,
* and has the added benefit of getting everything in one fread()
* chunk; if you know the size of the data you're getting
* beforehand, this is definitely the way to go.
*
* @param integer $size The number of bytes to read from the socket.
* @access public
* @return $size bytes of data from the socket, or a PEAR_Error if
* not connected.
*/
function read($size)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

return @fread($this->fp, $size);
}

/**
* Write a specified amount of data.
*
* @param string $data Data to write.
* @param integer $blocksize Amount of data to write at once.
* NULL means all at once.
*
* @access public
* @return mixed true on success or an error object otherwise
*/
function write($data, $blocksize = null)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

if (is_null($blocksize) && !OS_WINDOWS) {
return fwrite($this->fp, $data);
} else {
if (is_null($blocksize)) {
$blocksize = 1024;
}

$pos = 0;
$size = strlen($data);
while ($pos < $size) {
$written = @fwrite($this->fp, substr($data, $pos, $blocksize));
if ($written === false) {
return false;
}
$pos += $written;
}

return $pos;
}
}

/**
* Write a line of data to the socket, followed by a trailing "\r\n".
*
* @access public
* @return mixed fputs result, or an error
*/
function writeLine($data)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

return fwrite($this->fp, $data . "\r\n");
}

/**
* Tests for end-of-file on a socket descriptor.
*
* Also returns true if the socket is disconnected.
*
* @access public
* @return bool
*/
function eof()
{
return (!is_resource($this->fp) || feof($this->fp));
}

/**
* Reads a byte of data
*
* @access public
* @return 1 byte of data from the socket, or a PEAR_Error if
* not connected.
*/
function readByte()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

return ord(@fread($this->fp, 1));
}

/**
* Reads a word of data
*
* @access public
* @return 1 word of data from the socket, or a PEAR_Error if
* not connected.
*/
function readWord()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$buf = @fread($this->fp, 2);
return (ord($buf[0]) + (ord($buf[1]) << 8));
}

/**
* Reads an int of data
*
* @access public
* @return integer 1 int of data from the socket, or a PEAR_Error if
* not connected.
*/
function readInt()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$buf = @fread($this->fp, 4);
return (ord($buf[0]) + (ord($buf[1]) << 8) +
(ord($buf[2]) << 16) + (ord($buf[3]) << 24));
}

/**
* Reads a zero-terminated string of data
*
* @access public
* @return string, or a PEAR_Error if
* not connected.
*/
function readString()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$string = '';
while (($char = @fread($this->fp, 1)) != "\x00") {
$string .= $char;
}
return $string;
}

/**
* Reads an IP Address and returns it in a dot formated string
*
* @access public
* @return Dot formated string, or a PEAR_Error if
* not connected.
*/
function readIPAddress()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$buf = @fread($this->fp, 4);
return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
ord($buf[2]), ord($buf[3]));
}

/**
* Read until either the end of the socket or a newline, whichever
* comes first. Strips the trailing newline from the returned data.
*
* @access public
* @return All available data up to a newline, without that
* newline, or until the end of the socket, or a PEAR_Error if
* not connected.
*/
function readLine()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

ob_start();
$line = '';
$timeout = time() + $this->timeout;
while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
$line .= fgets($this->fp, $this->lineLength);
if (substr($line, -1) == "\n") {
ob_end_clean();
return rtrim($line, "\r\n");
}
}
ob_end_clean();
return $line;
}

/**
* Read until the socket closes, or until there is no more data in
* the inner PHP buffer. If the inner buffer is empty, in blocking
* mode we wait for at least 1 byte of data. Therefore, in
* blocking mode, if there is no data at all to be read, this
* function will never exit (unless the socket is closed on the
* remote end).
*
* @access public
*
* @return string All data until the socket closes, or a PEAR_Error if
* not connected.
*/
function readAll()
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$data = '';
while (!feof($this->fp)) {
$data .= @fread($this->fp, $this->lineLength);
}
return $data;
}

/**
* Runs the equivalent of the select() system call on the socket
* with a timeout specified by tv_sec and tv_usec.
*
* @param integer $state Which of read/write/error to check for.
* @param integer $tv_sec Number of seconds for timeout.
* @param integer $tv_usec Number of microseconds for timeout.
*
* @access public
* @return False if select fails, integer describing which of read/write/error
* are ready, or PEAR_Error if not connected.
*/
function select($state, $tv_sec, $tv_usec = 0)
{
if (!is_resource($this->fp)) {
return $this->raiseError('not connected');
}

$read = null;
$write = null;
$except = null;
if ($state & NET_SOCKET_READ) {
$read[] = $this->fp;
}
if ($state & NET_SOCKET_WRITE) {
$write[] = $this->fp;
}
if ($state & NET_SOCKET_ERROR) {
$except[] = $this->fp;
}
if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) {
return false;
}

$result = 0;
if (count($read)) {
$result |= NET_SOCKET_READ;
}
if (count($write)) {
$result |= NET_SOCKET_WRITE;
}
if (count($except)) {
$result |= NET_SOCKET_ERROR;
}
return $result;
}

}

+ 410
- 0
trunk/docs/include/PEAR/Net/URL.php Näytä tiedosto

@@ -0,0 +1,410 @@
<?php
// +-----------------------------------------------------------------------+
// | Copyright (c) 2002-2004, Richard Heyes |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution.|
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +-----------------------------------------------------------------------+
// | Author: Richard Heyes <richard at php net> |
// +-----------------------------------------------------------------------+
//
// $Id: URL.php,v 1.1 2005/08/01 06:20:45 dancoulter Exp $
//
// Net_URL Class

class Net_URL
{
/**
* Full url
* @var string
*/
var $url;

/**
* Protocol
* @var string
*/
var $protocol;

/**
* Username
* @var string
*/
var $username;

/**
* Password
* @var string
*/
var $password;

/**
* Host
* @var string
*/
var $host;

/**
* Port
* @var integer
*/
var $port;

/**
* Path
* @var string
*/
var $path;

/**
* Query string
* @var array
*/
var $querystring;

/**
* Anchor
* @var string
*/
var $anchor;

/**
* Whether to use []
* @var bool
*/
var $useBrackets;

/**
* PHP4 Constructor
*
* @see __construct()
*/
//function Net_URL($url = null, $useBrackets = true)
//{
// $this->__construct($url, $useBrackets);
//}

/**
* PHP5 Constructor
*
* Parses the given url and stores the various parts
* Defaults are used in certain cases
*
* @param string $url Optional URL
* @param bool $useBrackets Whether to use square brackets when
* multiple querystrings with the same name
* exist
*/
function __construct($url = null, $useBrackets = true)
{
$HTTP_SERVER_VARS = !empty($_SERVER) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];

$this->useBrackets = $useBrackets;
$this->url = $url;
$this->user = '';
$this->pass = '';
$this->host = '';
$this->port = 80;
$this->path = '';
$this->querystring = array();
$this->anchor = '';

// Only use defaults if not an absolute URL given
if (!preg_match('/^[a-z0-9]+:\/\//i', $url)) {

$this->protocol = (@$HTTP_SERVER_VARS['HTTPS'] == 'on' ? 'https' : 'http');

/**
* Figure out host/port
*/
if (!empty($HTTP_SERVER_VARS['HTTP_HOST']) AND preg_match('/^(.*)(:([0-9]+))?$/U', $HTTP_SERVER_VARS['HTTP_HOST'], $matches)) {
$host = $matches[1];
if (!empty($matches[3])) {
$port = $matches[3];
} else {
$port = $this->getStandardPort($this->protocol);
}
}

$this->user = '';
$this->pass = '';
$this->host = !empty($host) ? $host : (isset($HTTP_SERVER_VARS['SERVER_NAME']) ? $HTTP_SERVER_VARS['SERVER_NAME'] : 'localhost');
$this->port = !empty($port) ? $port : (isset($HTTP_SERVER_VARS['SERVER_PORT']) ? $HTTP_SERVER_VARS['SERVER_PORT'] : $this->getStandardPort($this->protocol));
$this->path = !empty($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : '/';
$this->querystring = isset($HTTP_SERVER_VARS['QUERY_STRING']) ? $this->_parseRawQuerystring($HTTP_SERVER_VARS['QUERY_STRING']) : null;
$this->anchor = '';
}

// Parse the url and store the various parts
if (!empty($url)) {
$urlinfo = parse_url($url);

// Default querystring
$this->querystring = array();

foreach ($urlinfo as $key => $value) {
switch ($key) {
case 'scheme':
$this->protocol = $value;
$this->port = $this->getStandardPort($value);
break;

case 'user':
case 'pass':
case 'host':
case 'port':
$this->$key = $value;
break;

case 'path':
if ($value{0} == '/') {
$this->path = $value;
} else {
$path = dirname($this->path) == DIRECTORY_SEPARATOR ? '' : dirname($this->path);
$this->path = sprintf('%s/%s', $path, $value);
}
break;

case 'query':
$this->querystring = $this->_parseRawQueryString($value);
break;

case 'fragment':
$this->anchor = $value;
break;
}
}
}
}

/**
* Returns full url
*
* @return string Full url
* @access public
*/
function getURL()
{
$querystring = $this->getQueryString();

$this->url = $this->protocol . '://'
. $this->user . (!empty($this->pass) ? ':' : '')
. $this->pass . (!empty($this->user) ? '@' : '')
. $this->host . ($this->port == $this->getStandardPort($this->protocol) ? '' : ':' . $this->port)
. $this->path
. (!empty($querystring) ? '?' . $querystring : '')
. (!empty($this->anchor) ? '#' . $this->anchor : '');

return $this->url;
}

/**
* Adds a querystring item
*
* @param string $name Name of item
* @param string $value Value of item
* @param bool $preencoded Whether value is urlencoded or not, default = not
* @access public
*/
function addQueryString($name, $value, $preencoded = false)
{
if ($preencoded) {
$this->querystring[$name] = $value;
} else {
$this->querystring[$name] = is_array($value) ? array_map('rawurlencode', $value): rawurlencode($value);
}
}

/**
* Removes a querystring item
*
* @param string $name Name of item
* @access public
*/
function removeQueryString($name)
{
if (isset($this->querystring[$name])) {
unset($this->querystring[$name]);
}
}

/**
* Sets the querystring to literally what you supply
*
* @param string $querystring The querystring data. Should be of the format foo=bar&x=y etc
* @access public
*/
function addRawQueryString($querystring)
{
$this->querystring = $this->_parseRawQueryString($querystring);
}

/**
* Returns flat querystring
*
* @return string Querystring
* @access public
*/
function getQueryString()
{
if (!empty($this->querystring)) {
foreach ($this->querystring as $name => $value) {
if (is_array($value)) {
foreach ($value as $k => $v) {
$querystring[] = $this->useBrackets ? sprintf('%s[%s]=%s', $name, $k, $v) : ($name . '=' . $v);
}
} elseif (!is_null($value)) {
$querystring[] = $name . '=' . $value;
} else {
$querystring[] = $name;
}
}
$querystring = implode(ini_get('arg_separator.output'), $querystring);
} else {
$querystring = '';
}

return $querystring;
}

/**
* Parses raw querystring and returns an array of it
*
* @param string $querystring The querystring to parse
* @return array An array of the querystring data
* @access private
*/
function _parseRawQuerystring($querystring)
{
$parts = preg_split('/[' . preg_quote(ini_get('arg_separator.input'), '/') . ']/', $querystring, -1, PREG_SPLIT_NO_EMPTY);
$return = array();

foreach ($parts as $part) {
if (strpos($part, '=') !== false) {
$value = substr($part, strpos($part, '=') + 1);
$key = substr($part, 0, strpos($part, '='));
} else {
$value = null;
$key = $part;
}
if (substr($key, -2) == '[]') {
$key = substr($key, 0, -2);
if (@!is_array($return[$key])) {
$return[$key] = array();
$return[$key][] = $value;
} else {
$return[$key][] = $value;
}
} elseif (!$this->useBrackets AND !empty($return[$key])) {
$return[$key] = (array)$return[$key];
$return[$key][] = $value;
} else {
$return[$key] = $value;
}
}

return $return;
}

/**
* Resolves //, ../ and ./ from a path and returns
* the result. Eg:
*
* /foo/bar/../boo.php => /foo/boo.php
* /foo/bar/../../boo.php => /boo.php
* /foo/bar/.././/boo.php => /foo/boo.php
*
* This method can also be called statically.
*
* @param string $url URL path to resolve
* @return string The result
*/
function resolvePath($path)
{
$path = explode('/', str_replace('//', '/', $path));

for ($i=0; $i<count($path); $i++) {
if ($path[$i] == '.') {
unset($path[$i]);
$path = array_values($path);
$i--;

} elseif ($path[$i] == '..' AND ($i > 1 OR ($i == 1 AND $path[0] != '') ) ) {
unset($path[$i]);
unset($path[$i-1]);
$path = array_values($path);
$i -= 2;

} elseif ($path[$i] == '..' AND $i == 1 AND $path[0] == '') {
unset($path[$i]);
$path = array_values($path);
$i--;

} else {
continue;
}
}

return implode('/', $path);
}

/**
* Returns the standard port number for a protocol
*
* @param string $scheme The protocol to lookup
* @return integer Port number or NULL if no scheme matches
*
* @author Philippe Jausions <Philippe.Jausions@11abacus.com>
*/
function getStandardPort($scheme)
{
switch (strtolower($scheme)) {
case 'http': return 80;
case 'https': return 443;
case 'ftp': return 21;
case 'imap': return 143;
case 'imaps': return 993;
case 'pop3': return 110;
case 'pop3s': return 995;
default: return null;
}
}

/**
* Forces the URL to a particular protocol
*
* @param string $protocol Protocol to force the URL to
* @param integer $port Optional port (standard port is used by default)
*/
function setProtocol($protocol, $port = null)
{
$this->protocol = $protocol;
$this->port = is_null($port) ? $this->getStandardPort() : $port;
}

}
?>

+ 1095
- 0
trunk/docs/include/PEAR/PEAR.php
File diff suppressed because it is too large
Näytä tiedosto


+ 146
- 0
trunk/docs/include/application.php Näytä tiedosto

@@ -0,0 +1,146 @@
<?php

require_once('config.php');
require_once('DB.php');

class Application{
var $authority_id = 0;
var $council_reference = "";
var $date_recieved = "";
var $date_scraped ="";
var $address = "";
var $postcode = "";
var $description = "";
var $status = "";
var $info_url = "";
var $info_tinyurl = "";
var $comment_url = "";
var $comment_tinyurl = "";
var $map_url = "";
var $x = 0;
var $y = 0;

#lat/lon used by rss.tpl, not yet in schema
var $lat = 0;
var $lon = 0;
#authority name in join'd table 'authority'
var $authority_name = "";
function exists(){
$db = DB::connect(DB_CONNECTION_STRING);
$exists = false;
$council_reference = $db->quote($this->council_reference);
$authority_id = $db->quote($this->authority_id);
$sql = "select application_id
from application
where council_reference = $council_reference
and authority_id = $authority_id";

if(sizeof($db->getAll($sql)) >0){
$exists = true;
}
return $exists;
}
//Save
function save(){
$db = DB::connect(DB_CONNECTION_STRING);
$council_reference = $db->quote($this->council_reference);
$address = $db->quote($this->address);
$postcode = $db->quote($this->postcode);
$description = $db->quote($this->description);
$info_url = $db->quote($this->info_url);
$info_tinyurl = $db->quote($this->info_tinyurl);
$comment_url = $db->quote($this->comment_url);
$comment_tinyurl = $db->quote($this->comment_tinyurl);
$authority_id = $db->quote($this->authority_id);
$x = $db->quote($this->x);
$y = $db->quote($this->y);
$date_scraped = $db->quote($this->date_scraped);
$map_url = $db->quote($this->map_url);

$sql ="insert into application
(
council_reference,
address,
postcode,
description,
info_url,
info_tinyurl,
comment_url,
comment_tinyurl,
authority_id,
x,
y,
date_scraped,
map_url
)
values(
$council_reference,
$address,
$postcode,
$description,
$info_url,
$info_tinyurl,
$comment_url,
$comment_tinyurl,
$authority_id,
$x,
$y,
$date_scraped,
$map_url
)";
$db->query($sql);

}

}
class Applications{

function query($x,$y,$d) {
$db = DB::connect(DB_CONNECTION_STRING);
$sql = "select council_reference, address, postcode, description, info_url, comment_url, map_url, x, y, full_name
from application
inner join authority on application.authority_id = authority.authority_id
where application.x > " . $db->quote($x - $d) . " and application.x < " . $db->quote($x + $d) .
" and application.y > " . $db->quote($y - $d) . " and application.y < " . $db->quote($y + $d) .
" order by date_scraped desc limit 100";

$application_results = $db->getAll($sql);

$applications = array();
if (sizeof($application_results) > 0) {
for ($i=0; $i < sizeof($application_results); $i++) {
$application = new application();
$application->council_reference = $application_results[$i][0];
$application->address = $application_results[$i][1];
$application->postcode = $application_results[$i][2];
$application->description = $application_results[$i][3];
$application->info_url = $application_results[$i][4];
$application->comment_url = $application_results[$i][5];
$application->map_url = $application_results[$i][6];
$application->x = $application_results[$i][7];
$application->y = $application_results[$i][8];
$application->authority_name = $application_results[$i][9];

$os = new OSRef($application->x, $application->y);
$latlng = $os->toLatLng();
$application->lat = $latlng->lat;
$application->lon = $latlng->lng;
array_push($applications, $application);
}
}

return $applications;
}
}

?>

+ 43
- 0
trunk/docs/include/config.php Näytä tiedosto

@@ -0,0 +1,43 @@
<?php

/* Includes for all pages*/
require_once ("smarty/Smarty.class.php");
require_once ("scraper_support.php");

/* Config vars */
//Database
define ("DB_CONNECTION_STRING", 'mysql://root:@localhost/planning');

//Smarty
define ("SMARTY_COMPILE_DIRECTORY", '/data/vhost/planning/data/');
define ("SMARTY_TEMPLATE_DIRECTORY", '/data/vhost/planning/docs/templates/');
define ("SMARTY_PATH", '');

//PEAR
define ("PEAR_LOCATION", 'PEAR');

//URL Stuff
define ("BASE_URL", 'http://localhost.planning');
define ("DOMAIN", 'planningalerts.com');

//Scrape method (Curl vs PEAR HTTP)
define ("SCRAPE_METHOD", 'PEAR');

//Size of alert areas
define ("SMALL_ZONE_SIZE", '200');
define ("MEDIUM_ZONE_SIZE", '800');
define ("LARGE_ZONE_SIZE", '2000');
define ("ZONE_BUFFER_PERCENTAGE", '5');

//Email setup
define ("EMAIL_FROM_ADDRESS", 'planningbot@planningalerts.com');
define ("EMAIL_FROM_NAME", 'PlanningAlerts.com');

//Scraper params
define ("SCRAPE_DELAY", '5');
define ("LOG_EMAIL", 'richard@memespring.co.uk');

//Google maps key
define ("GOOGLE_MAPS_KEY", 'ABQIAAAA74qlSxRXDySLggVC9lWIbBQeWac_qjVnPmH5iTpTixX1E2xfnBR9X0On0aXuFhRdSPx42Pz0LmJzhQ');

?>

+ 43
- 0
trunk/docs/include/config.php.live Näytä tiedosto

@@ -0,0 +1,43 @@
<?php

/* Includes for all pages*/
require_once ("smarty/Smarty.class.php");
require_once ("scraper_support.php");

/* Config vars */
//Database
define ("DB_CONNECTION_STRING", 'mysql://planningalerts:a03q9jdqowqj@localhost/planningalerts');

//Smarty
define ("SMARTY_COMPILE_DIRECTORY", '/data/vhost/www.planningalerts.com/data/');
define ("SMARTY_TEMPLATE_DIRECTORY", '/data/vhost/www.planningalerts.com/docs/templates/');
define ("SMARTY_PATH", '');

//Scrape method (Curl vs PEAR HTTP)
define ("SCRAPE_METHOD", 'PEAR');

//PEAR
define ("PEAR_LOCATION", 'PEAR');

//URL Stuff
define ("BASE_URL", 'http://www.planningalerts.com');
define ("DOMAIN", 'planningalerts.com');

//Size of alert areas
define ("SMALL_ZONE_SIZE", '200');
define ("MEDIUM_ZONE_SIZE", '800');
define ("LARGE_ZONE_SIZE", '2000');
define ("ZONE_BUFFER_PERCENTAGE", '5');

//Email setup
define ("EMAIL_FROM_ADDRESS", 'planningbot@planningalerts.com');
define ("EMAIL_FROM_NAME", 'PlanningAlerts.com');

//Scraper params
define ("SCRAPE_DELAY", '3');
define ("LOG_EMAIL", 'richard@memespring.co.uk');

//Google API
define ("GOOGLE_MAPS_KEY", 'ABQIAAAA74qlSxRXDySLggVC9lWIbBQMCRvdNqsWfhfsng03puZUBTaT9hQtyX51KB_R84bAOXtAJTIFKY8Cvw');

?>

+ 43
- 0
trunk/docs/include/config.php.svn Näytä tiedosto

@@ -0,0 +1,43 @@
<?php

/* Includes for all pages*/
require_once ("smarty/Smarty.class.php");
require_once ("scraper_support.php");

/* Config vars */
//Database
define ("DB_CONNECTION_STRING", 'mysql://root:@localhost/planning');

//Smarty
define ("SMARTY_COMPILE_DIRECTORY", '/data/vhost/planning/data/');
define ("SMARTY_TEMPLATE_DIRECTORY", 'templates');
define ("SMARTY_PATH", '');

//PEAR
define ("PEAR_LOCATION", 'PEAR');

//URL Stuff
define ("BASE_URL", 'http://localhost.planning');
define ("DOMAIN", 'planningalerts.com');

//Scrape method (Curl vs PEAR HTTP)
define ("SCRAPE_METHOD", 'PEAR');

//Size of alert areas
define ("SMALL_ZONE_SIZE", '200');
define ("MEDIUM_ZONE_SIZE", '800');
define ("LARGE_ZONE_SIZE", '2000');
define ("ZONE_BUFFER_PERCENTAGE", '5');

//Email setup
define ("EMAIL_FROM_ADDRESS", 'planningbot@planningalerts.com');
define ("EMAIL_FROM_NAME", 'PlanningAlerts.com');

//Scraper params
define ("SCRAPE_DELAY", '5');
define ("LOG_EMAIL", 'richard@memespring.co.uk');

//Google maps key
define ("GOOGLE_MAPS_KEY", 'ABQIAAAA74qlSxRXDySLggVC9lWIbBQeWac_qjVnPmH5iTpTixX1E2xfnBR9X0On0aXuFhRdSPx42Pz0LmJzhQ');

?>

+ 776
- 0
trunk/docs/include/phpcoord.php Näytä tiedosto

@@ -0,0 +1,776 @@
<?php

//--------------------------------------------------------------------------
// PHPcoord
// phpcoord.php
//
// (c) 2005 Jonathan Stott
//
// Created on 11-Aug-2005
//
// 2.2 - 11 Feb 2006
// - Used different algorithm for calculating distance between latitudes
// and longitudes - fixes a number of problems with distance calculations
// 2.1 - 22 Dec 2005
// - Added getOSRefFromSixFigureReference function
// 2.0 - 21 Dec 2005
// - Completely different object design - conversion functions now through
// objects rather than static functions
// - Updated comments and documentation
// 1.1 - 11 Sep 2005
// - Added OSGB36/WGS84 data conversions
// 1.0 - 11 Aug 2005
// - Initial version
//--------------------------------------------------------------------------


// ================================================================== LatLng

class LatLng {

var $lat;
var $lng;


/**
* Create a new LatLng object from the given latitude and longitude
*
* @param lat latitude
* @param lng longitude
*/
function LatLng($lat, $lng) {
$this->lat = $lat;
$this->lng = $lng;
}


/**
* Return a string representation of this LatLng object
*
* @return a string representation of this LatLng object
*/
function toString() {
return "(" . $this->lat . ", " . $this->lng . ")";
}
/**
* Calculate the surface distance between this LatLng object and the one
* passed in as a parameter.
*
* @param to a LatLng object to measure the surface distance to
* @return the surface distance
*/
function distance($to) {
$er = 6366.707;

$latFrom = deg2rad($this->lat);
$latTo = deg2rad($to->lat);
$lngFrom = deg2rad($this->lng);
$lngTo = deg2rad($to->lng);

$x1 = $er * cos($lngFrom) * sin($latFrom);
$y1 = $er * sin($lngFrom) * sin($latFrom);
$z1 = $er * cos($latFrom);

$x2 = $er * cos($lngTo) * sin($latTo);
$y2 = $er * sin($lngTo) * sin($latTo);
$z2 = $er * cos($latTo);

$d = acos(sin($latFrom)*sin($latTo) + cos($latFrom)*cos($latTo)*cos($lngTo-$lngFrom)) * $er;
return $d;
}

/**
* Convert this LatLng object from OSGB36 datum to WGS84 datum.
*/
function OSGB36ToWGS84() {
$airy1830 = new RefEll(6377563.396, 6356256.909);
$a = $airy1830->maj;
$b = $airy1830->min;
$eSquared = $airy1830->ecc;
$phi = deg2rad($this->lat);
$lambda = deg2rad($this->lng);
$v = $a / (sqrt(1 - $eSquared * sinSquared($phi)));
$H = 0; // height
$x = ($v + $H) * cos($phi) * cos($lambda);
$y = ($v + $H) * cos($phi) * sin($lambda);
$z = ((1 - $eSquared) * $v + $H) * sin($phi);

$tx = 446.448;
$ty = -124.157;
$tz = 542.060;
$s = -0.0000204894;
$rx = deg2rad( 0.00004172222);
$ry = deg2rad( 0.00006861111);
$rz = deg2rad( 0.00023391666);

$xB = $tx + ($x * (1 + $s)) + (-$rx * $y) + ($ry * $z);
$yB = $ty + ($rz * $x) + ($y * (1 + $s)) + (-$rx * $z);
$zB = $tz + (-$ry * $x) + ($rx * $y) + ($z * (1 + $s));

$wgs84 = new RefEll(6378137.000, 6356752.3141);
$a = $wgs84->maj;
$b = $wgs84->min;
$eSquared = $wgs84->ecc;

$lambdaB = rad2deg(atan($yB / $xB));
$p = sqrt(($xB * $xB) + ($yB * $yB));
$phiN = atan($zB / ($p * (1 - $eSquared)));
for ($i = 1; $i < 10; $i++) {
$v = $a / (sqrt(1 - $eSquared * sinSquared($phiN)));
$phiN1 = atan(($zB + ($eSquared * $v * sin($phiN))) / $p);
$phiN = $phiN1;
}

$phiB = rad2deg($phiN);
$this->lat = $phiB;
$this->lng = $lambdaB;
}
/**
* Convert this LatLng object from WGS84 datum to OSGB36 datum.
*/
function WGS84ToOSGB36() {
$wgs84 = new RefEll(6378137.000, 6356752.3141);
$a = $wgs84->maj;
$b = $wgs84->min;
$eSquared = $wgs84->ecc;
$phi = deg2rad($this->lat);
$lambda = deg2rad($this->lng);
$v = $a / (sqrt(1 - $eSquared * sinSquared($phi)));
$H = 0; // height
$x = ($v + $H) * cos($phi) * cos($lambda);
$y = ($v + $H) * cos($phi) * sin($lambda);
$z = ((1 - $eSquared) * $v + $H) * sin($phi);

$tx = -446.448;
$ty = 124.157;
$tz = -542.060;
$s = 0.0000204894;
$rx = deg2rad(-0.00004172222);
$ry = deg2rad(-0.00006861111);
$rz = deg2rad(-0.00023391666);

$xB = $tx + ($x * (1 + $s)) + (-$rx * $y) + ($ry * $z);
$yB = $ty + ($rz * $x) + ($y * (1 + $s)) + (-$rx * $z);
$zB = $tz + (-$ry * $x) + ($rx * $y) + ($z * (1 + $s));

$airy1830 = new RefEll(6377563.396, 6356256.909);
$a = $airy1830->maj;
$b = $airy1830->min;
$eSquared = $airy1830->ecc;

$lambdaB = rad2deg(atan($yB / $xB));
$p = sqrt(($xB * $xB) + ($yB * $yB));
$phiN = atan($zB / ($p * (1 - $eSquared)));
for ($i = 1; $i < 10; $i++) {
$v = $a / (sqrt(1 - $eSquared * sinSquared($phiN)));
$phiN1 = atan(($zB + ($eSquared * $v * sin($phiN))) / $p);
$phiN = $phiN1;
}
$phiB = rad2deg($phiN);
$this->lat = $phiB;
$this->lng = $lambdaB;
}
/**
* Convert this LatLng object into an OSGB grid reference. Note that this
* function does not take into account the bounds of the OSGB grid -
* beyond the bounds of the OSGB grid, the resulting OSRef object has no
* meaning
*
* @return the converted OSGB grid reference
*/
function toOSRef() {
$airy1830 = new RefEll(6377563.396, 6356256.909);
$OSGB_F0 = 0.9996012717;
$N0 = -100000.0;
$E0 = 400000.0;
$phi0 = deg2rad(49.0);
$lambda0 = deg2rad(-2.0);
$a = $airy1830->maj;
$b = $airy1830->min;
$eSquared = $airy1830->ecc;
$phi = deg2rad($this->lat);
$lambda = deg2rad($this->lng);
$E = 0.0;
$N = 0.0;
$n = ($a - $b) / ($a + $b);
$v = $a * $OSGB_F0 * pow(1.0 - $eSquared * sinSquared($phi), -0.5);
$rho =
$a * $OSGB_F0 * (1.0 - $eSquared) * pow(1.0 - $eSquared * sinSquared($phi), -1.5);
$etaSquared = ($v / $rho) - 1.0;
$M =
($b * $OSGB_F0)
* (((1 + $n + ((5.0 / 4.0) * $n * $n) + ((5.0 / 4.0) * $n * $n * $n))
* ($phi - $phi0))
- (((3 * $n) + (3 * $n * $n) + ((21.0 / 8.0) * $n * $n * $n))
* sin($phi - $phi0)
* cos($phi + $phi0))
+ ((((15.0 / 8.0) * $n * $n) + ((15.0 / 8.0) * $n * $n * $n))
* sin(2.0 * ($phi - $phi0))
* cos(2.0 * ($phi + $phi0)))
- (((35.0 / 24.0) * $n * $n * $n)
* sin(3.0 * ($phi - $phi0))
* cos(3.0 * ($phi + $phi0))));
$I = $M + $N0;
$II = ($v / 2.0) * sin($phi) * cos($phi);
$III =
($v / 24.0)
* sin($phi)
* pow(cos($phi), 3.0)
* (5.0 - tanSquared($phi) + (9.0 * $etaSquared));
$IIIA =
($v / 720.0)
* sin($phi)
* pow(cos($phi), 5.0)
* (61.0 - (58.0 * tanSquared($phi)) + pow(tan($phi), 4.0));
$IV = $v * cos($phi);
$V = ($v / 6.0) * pow(cos($phi), 3.0) * (($v / $rho) - tanSquared($phi));
$VI =
($v / 120.0)
* pow(cos($phi), 5.0)
* (5.0
- (18.0 * tanSquared($phi))
+ (pow(tan($phi), 4.0))
+ (14 * $etaSquared)
- (58 * tanSquared($phi) * $etaSquared));

$N =
$I
+ ($II * pow($lambda - $lambda0, 2.0))
+ ($III * pow($lambda - $lambda0, 4.0))
+ ($IIIA * pow($lambda - $lambda0, 6.0));
$E =
$E0
+ ($IV * ($lambda - $lambda0))
+ ($V * pow($lambda - $lambda0, 3.0))
+ ($VI * pow($lambda - $lambda0, 5.0));

return new OSRef($E, $N);
}
/**
* Convert a latitude and longitude to an UTM reference
*
* @return the converted UTM reference
*/
function toUTMRef() {
$wgs84 = new RefEll(6378137, 6356752.314);
$UTM_F0 = 0.9996;
$a = $wgs84->maj;
$eSquared = $wgs84->ecc;
$longitude = $this->lng;
$latitude = $this->lat;

$latitudeRad = $latitude * (pi() / 180.0);
$longitudeRad = $longitude * (pi() / 180.0);
$longitudeZone = (int) (($longitude + 180.0) / 6.0) + 1;

// Special zone for Norway
if ($latitude >= 56.0
&& $latitude < 64.0
&& $longitude >= 3.0
&& $longitude < 12.0) {
$longitudeZone = 32;
}

// Special zones for Svalbard
if ($latitude >= 72.0 && $latitude < 84.0) {
if ($longitude >= 0.0 && $longitude < 9.0) {
$longitudeZone = 31;
} else if ($longitude >= 9.0 && $longitude < 21.0) {
$longitudeZone = 33;
} else if ($longitude >= 21.0 && $longitude < 33.0) {
$longitudeZone = 35;
} else if ($longitude >= 33.0 && $longitude < 42.0) {
$longitudeZone = 37;
}
}

$longitudeOrigin = ($longitudeZone - 1) * 6 - 180 + 3;
$longitudeOriginRad = $longitudeOrigin * (pi() / 180.0);

$UTMZone = getUTMLatitudeZoneLetter($latitude);

$ePrimeSquared = ($eSquared) / (1 - $eSquared);

$n = $a / sqrt(1 - $eSquared * sin($latitudeRad) * sin($latitudeRad));
$t = tan($latitudeRad) * tan($latitudeRad);
$c = $ePrimeSquared * cos($latitudeRad) * cos($latitudeRad);
$A = cos($latitudeRad) * ($longitudeRad - $longitudeOriginRad);

$M =
$a
* ((1
- $eSquared / 4
- 3 * $eSquared * $eSquared / 64
- 5 * $eSquared * $eSquared * $eSquared / 256)
* $latitudeRad
- (3 * $eSquared / 8
+ 3 * $eSquared * $eSquared / 32
+ 45 * $eSquared * $eSquared * $eSquared / 1024)
* sin(2 * $latitudeRad)
+ (15 * $eSquared * $eSquared / 256
+ 45 * $eSquared * $eSquared * $eSquared / 1024)
* sin(4 * $latitudeRad)
- (35 * $eSquared * $eSquared * $eSquared / 3072)
* sin(6 * $latitudeRad));

$UTMEasting =
(double) ($UTM_F0
* $n
* ($A
+ (1 - $t + $c) * pow($A, 3.0) / 6
+ (5 - 18 * $t + $t * $t + 72 * $c - 58 * $ePrimeSquared)
* pow($A, 5.0)
/ 120)
+ 500000.0);

$UTMNorthing =
(double) ($UTM_F0
* ($M
+ $n
* tan($latitudeRad)
* ($A * $A / 2
+ (5 - $t + (9 * $c) + (4 * $c * $c)) * pow($A, 4.0) / 24
+ (61 - (58 * $t) + ($t * $t) + (600 * $c) - (330 * $ePrimeSquared))
* pow($A, 6.0)
/ 720)));

// Adjust for the southern hemisphere
if ($latitude < 0) {
$UTMNorthing += 10000000.0;
}

return new UTMRef($UTMEasting, $UTMNorthing, $UTMZone, $longitudeZone);
}
}


// =================================================================== OSRef

// References given with OSRef are accurate to 1m.
class OSRef {

var $easting;
var $northing;


/**
* Create a new OSRef object representing an OSGB grid reference. Note
* that the parameters for this constructor require eastings and
* northings with 1m accuracy and need to be absolute with respect to
* the whole of the British Grid. For example, to create an OSRef
* object from the six-figure grid reference TG514131, the easting would
* be 651400 and the northing would be 313100.
*
* Grid references with accuracy greater than 1m can be represented
* using floating point values for the easting and northing. For example,
* a value representing an easting or northing accurate to 1mm would be
* given as 651400.0001.
*
* @param easting the easting of the reference (with 1m accuracy)
* @param northing the northing of the reference (with 1m accuracy)
*/
function OSRef($easting, $northing) {
$this->easting = $easting;
$this->northing = $northing;
}


/**
* Convert this grid reference into a string showing the exact values
* of the easting and northing.
*
* @return
*/
function toString() {
return "(" . $this->easting . ", " . $this->northing . ")";
}


/**
* Convert this grid reference into a string using a standard six-figure
* grid reference including the two-character designation for the 100km
* square. e.g. TG514131.
*
* @return
*/
function toSixFigureString() {
$hundredkmE = floor($this->easting / 100000);
$hundredkmN = floor($this->northing / 100000);
$firstLetter = "";
if ($hundredkmN < 5) {
if ($hundredkmE < 5) {
$firstLetter = "S";
} else {
$firstLetter = "T";
}
} else if ($hundredkmN < 10) {
if ($hundredkmE < 5) {
$firstLetter = "N";
} else {
$firstLetter = "O";
}
} else {
$firstLetter = "H";
}

$secondLetter = "";
$index = 65 + ((4 - ($hundredkmN % 5)) * 5) + ($hundredkmE % 5);
$ti = $index;
if ($index >= 73) $index++;
$secondLetter = chr($index);

$e = floor(($this->easting - (100000 * $hundredkmE)) / 100);
$n = floor(($this->northing - (100000 * $hundredkmN)) / 100);
$es = $e;
if ($e < 100) $es = "0$es";
if ($e < 10) $es = "0$es";
$ns = $n;
if ($n < 100) $ns = "0$ns";
if ($n < 10) $ns = "0$ns";

return $firstLetter . $secondLetter . $es . $ns;
}


/**
* Convert this grid reference into a latitude and longitude
*
* @return
*/
function toLatLng() {
$airy1830 = new RefEll(6377563.396, 6356256.909);
$OSGB_F0 = 0.9996012717;
$N0 = -100000.0;
$E0 = 400000.0;
$phi0 = deg2rad(49.0);
$lambda0 = deg2rad(-2.0);
$a = $airy1830->maj;
$b = $airy1830->min;
$eSquared = $airy1830->ecc;
$phi = 0.0;
$lambda = 0.0;
$E = $this->easting;
$N = $this->northing;
$n = ($a - $b) / ($a + $b);
$M = 0.0;
$phiPrime = (($N - $N0) / ($a * $OSGB_F0)) + $phi0;
do {
$M =
($b * $OSGB_F0)
* (((1 + $n + ((5.0 / 4.0) * $n * $n) + ((5.0 / 4.0) * $n * $n * $n))
* ($phiPrime - $phi0))
- (((3 * $n) + (3 * $n * $n) + ((21.0 / 8.0) * $n * $n * $n))
* sin($phiPrime - $phi0)
* cos($phiPrime + $phi0))
+ ((((15.0 / 8.0) * $n * $n) + ((15.0 / 8.0) * $n * $n * $n))
* sin(2.0 * ($phiPrime - $phi0))
* cos(2.0 * ($phiPrime + $phi0)))
- (((35.0 / 24.0) * $n * $n * $n)
* sin(3.0 * ($phiPrime - $phi0))
* cos(3.0 * ($phiPrime + $phi0))));
$phiPrime += ($N - $N0 - $M) / ($a * $OSGB_F0);
} while (($N - $N0 - $M) >= 0.001);
$v = $a * $OSGB_F0 * pow(1.0 - $eSquared * sinSquared($phiPrime), -0.5);
$rho =
$a
* $OSGB_F0
* (1.0 - $eSquared)
* pow(1.0 - $eSquared * sinSquared($phiPrime), -1.5);
$etaSquared = ($v / $rho) - 1.0;
$VII = tan($phiPrime) / (2 * $rho * $v);
$VIII =
(tan($phiPrime) / (24.0 * $rho * pow($v, 3.0)))
* (5.0
+ (3.0 * tanSquared($phiPrime))
+ $etaSquared
- (9.0 * tanSquared($phiPrime) * $etaSquared));
$IX =
(tan($phiPrime) / (720.0 * $rho * pow($v, 5.0)))
* (61.0
+ (90.0 * tanSquared($phiPrime))
+ (45.0 * tanSquared($phiPrime) * tanSquared($phiPrime)));
$X = sec($phiPrime) / $v;
$XI =
(sec($phiPrime) / (6.0 * $v * $v * $v))
* (($v / $rho) + (2 * tanSquared($phiPrime)));
$XII =
(sec($phiPrime) / (120.0 * pow($v, 5.0)))
* (5.0
+ (28.0 * tanSquared($phiPrime))
+ (24.0 * tanSquared($phiPrime) * tanSquared($phiPrime)));
$XIIA =
(sec($phiPrime) / (5040.0 * pow($v, 7.0)))
* (61.0
+ (662.0 * tanSquared($phiPrime))
+ (1320.0 * tanSquared($phiPrime) * tanSquared($phiPrime))
+ (720.0
* tanSquared($phiPrime)
* tanSquared($phiPrime)
* tanSquared($phiPrime)));
$phi =
$phiPrime
- ($VII * pow($E - $E0, 2.0))
+ ($VIII * pow($E - $E0, 4.0))
- ($IX * pow($E - $E0, 6.0));
$lambda =
$lambda0
+ ($X * ($E - $E0))
- ($XI * pow($E - $E0, 3.0))
+ ($XII * pow($E - $E0, 5.0))
- ($XIIA * pow($E - $E0, 7.0));
return new LatLng(rad2deg($phi), rad2deg($lambda));
}
}


// ================================================================== UTMRef

class UTMRef {

var $easting;
var $northing;
var $latZone;
var $lngZone;


/**
* Create a new object representing a UTM reference.
*
* @param easting
* @param northing
* @param latZone
* @param lngZone
*/
function UTMRef($easting, $northing, $latZone, $lngZone) {
$this->easting = $easting;
$this->northing = $northing;
$this->latZone = $latZone;
$this->lngZone = $lngZone;
}


/**
* Return a string representation of this UTM reference
*
* @return
*/
function toString() {
return $this->lngZone . $this->latZone . " " .
$this->easting . " " . $this->northing;
}
/**
* Convert this UTM reference to a latitude and longitude
*
* @return the converted latitude and longitude
*/
function toLatLng() {
$wgs84 = new RefEll(6378137, 6356752.314);
$UTM_F0 = 0.9996;
$a = $wgs84->maj;
$eSquared = $wgs84->ecc;
$ePrimeSquared = $eSquared / (1.0 - $eSquared);
$e1 = (1 - sqrt(1 - $eSquared)) / (1 + sqrt(1 - $eSquared));
$x = $this->easting - 500000.0;;
$y = $this->northing;
$zoneNumber = $this->lngZone;
$zoneLetter = $this->latZone;

$longitudeOrigin = ($zoneNumber - 1.0) * 6.0 - 180.0 + 3.0;

// Correct y for southern hemisphere
if ((ord($zoneLetter) - ord("N")) < 0) {
$y -= 10000000.0;
}

$m = $y / $UTM_F0;
$mu =
$m
/ ($a
* (1.0
- $eSquared / 4.0
- 3.0 * $eSquared * $eSquared / 64.0
- 5.0
* pow($eSquared, 3.0)
/ 256.0));

$phi1Rad =
$mu
+ (3.0 * $e1 / 2.0 - 27.0 * pow($e1, 3.0) / 32.0) * sin(2.0 * $mu)
+ (21.0 * $e1 * $e1 / 16.0 - 55.0 * pow($e1, 4.0) / 32.0)
* sin(4.0 * $mu)
+ (151.0 * pow($e1, 3.0) / 96.0) * sin(6.0 * $mu);

$n =
$a
/ sqrt(1.0 - $eSquared * sin($phi1Rad) * sin($phi1Rad));
$t = tan($phi1Rad) * tan($phi1Rad);
$c = $ePrimeSquared * cos($phi1Rad) * cos($phi1Rad);
$r =
$a
* (1.0 - $eSquared)
/ pow(
1.0 - $eSquared * sin($phi1Rad) * sin($phi1Rad),
1.5);
$d = $x / ($n * $UTM_F0);

$latitude = (
$phi1Rad
- ($n * tan($phi1Rad) / $r)
* ($d * $d / 2.0
- (5.0
+ (3.0 * $t)
+ (10.0 * $c)
- (4.0 * $c * $c)
- (9.0 * $ePrimeSquared))
* pow($d, 4.0)
/ 24.0
+ (61.0
+ (90.0 * $t)
+ (298.0 * $c)
+ (45.0 * $t * $t)
- (252.0 * $ePrimeSquared)
- (3.0 * $c * $c))
* pow($d, 6.0)
/ 720.0)) * (180.0 / pi());

$longitude = $longitudeOrigin + (
($d
- (1.0 + 2.0 * $t + $c) * pow($d, 3.0) / 6.0
+ (5.0
- (2.0 * $c)
+ (28.0 * $t)
- (3.0 * $c * $c)
+ (8.0 * $ePrimeSquared)
+ (24.0 * $t * $t))
* pow($d, 5.0)
/ 120.0)
/ cos($phi1Rad)) * (180.0 / pi());

return new LatLng($latitude, $longitude);
}
}


// ================================================================== RefEll

class RefEll {

var $maj;
var $min;
var $ecc;


/**
* Create a new RefEll object to represent a reference ellipsoid
*
* @param maj the major axis
* @param min the minor axis
*/
function RefEll($maj, $min) {
$this->maj = $maj;
$this->min = $min;
$this->ecc = (($maj * $maj) - ($min * $min)) / ($maj * $maj);
}
}


// ================================================== Mathematical Functions

function sinSquared($x) {
return sin($x) * sin($x);
}

function cosSquared($x) {
return cos($x) * cos($x);
}

function tanSquared($x) {
return tan($x) * tan($x);
}

function sec($x) {
return 1.0 / cos($x);
}
/**
* Take a string formatted as a six-figure OS grid reference (e.g.
* "TG514131") and return a reference to an OSRef object that represents
* that grid reference. The first character must be H, N, S, O or T.
* The second character can be any uppercase character from A through Z
* excluding I.
*
* @param ref
* @return
* @since 2.1
*/
function getOSRefFromSixFigureReference($ref) {
$char1 = substr($ref, 0, 1);
$char2 = substr($ref, 1, 1);
$east = substr($ref, 2, 3) * 100;
$north = substr($ref, 5, 3) * 100;
if ($char1 == 'H') {
$north += 1000000;
} else if ($char1 == 'N') {
$north += 500000;
} else if ($char1 == 'O') {
$north += 500000;
$east += 500000;
} else if ($char1 == 'T') {
$east += 500000;
}
$char2ord = ord($char2);
if ($char2ord > 73) $char2ord--; // Adjust for no I
$nx = (($char2ord - 65) % 5) * 100000;
$ny = (4 - floor(($char2ord - 65) / 5)) * 100000;
return new OSRef($east + $nx, $north + $ny);
}
/**
* Work out the UTM latitude zone from the latitude
*
* @param latitude
* @return
*/
function getUTMLatitudeZoneLetter($latitude) {
if ((84 >= $latitude) && ($latitude >= 72)) return "X";
else if (( 72 > $latitude) && ($latitude >= 64)) return "W";
else if (( 64 > $latitude) && ($latitude >= 56)) return "V";
else if (( 56 > $latitude) && ($latitude >= 48)) return "U";
else if (( 48 > $latitude) && ($latitude >= 40)) return "T";
else if (( 40 > $latitude) && ($latitude >= 32)) return "S";
else if (( 32 > $latitude) && ($latitude >= 24)) return "R";
else if (( 24 > $latitude) && ($latitude >= 16)) return "Q";
else if (( 16 > $latitude) && ($latitude >= 8)) return "P";
else if (( 8 > $latitude) && ($latitude >= 0)) return "N";
else if (( 0 > $latitude) && ($latitude >= -8)) return "M";
else if (( -8 > $latitude) && ($latitude >= -16)) return "L";
else if ((-16 > $latitude) && ($latitude >= -24)) return "K";
else if ((-24 > $latitude) && ($latitude >= -32)) return "J";
else if ((-32 > $latitude) && ($latitude >= -40)) return "H";
else if ((-40 > $latitude) && ($latitude >= -48)) return "G";
else if ((-48 > $latitude) && ($latitude >= -56)) return "F";
else if ((-56 > $latitude) && ($latitude >= -64)) return "E";
else if ((-64 > $latitude) && ($latitude >= -72)) return "D";
else if ((-72 > $latitude) && ($latitude >= -80)) return "C";
else return 'Z';
}

?>

+ 413
- 0
trunk/docs/include/scraper_support.php Näytä tiedosto

@@ -0,0 +1,413 @@
<?php
//Includes
require_once('config.php');
require_once('application.php');
require_once ("PEAR/HTTP/Request.php");
require_once('phpcoord.php');

//Generic scrapers
function scrape_applications_publicaccess ($search_url, $info_url_base, $comment_url_base){

$applications = array();
$application_pattern = "/<tr><th>([0-9]*)<\/th>([^;]*)([^<]*)/";

//grab the page
$html = safe_scrape_page($search_url);

//clean html
$html = str_replace("\r\n","", $html);

preg_match_all($application_pattern, $html, $application_matches, PREG_PATTERN_ORDER);

foreach ($application_matches[0] as $application_match){

$detail_pattern = "/<td>([^<])*/";
preg_match_all($detail_pattern, $application_match, $detail_matches, PREG_PATTERN_ORDER);

$application = new Application();

//match the basic details
$application->council_reference = str_replace("<td>", "", $detail_matches[0][0]);
$application->date_received = str_replace("<td>", "", $detail_matches[0][1]);
$application->address = str_replace("<td>", "", $detail_matches[0][2]);
//$application->status = str_replace("<td>", "", $detail_matches[0][4]);
//match case number
$casenumber_pattern = "/caseno=([^&]*)/";
preg_match($casenumber_pattern, $application_match, $casenumber_matches);
$case_number ="";
if(sizeof($casenumber_matches)>0){
$case_number = str_replace("caseno=","", $casenumber_matches[0]);
}
//if weve found a caase number, then get the details
if($case_number !=""){
//Comment and info urls
$application->info_url = $info_url_base . $case_number;
$application->comment_url = $comment_url_base . $case_number;

//Get the postcode
$postcode_pattern = "/[A-Z][A-Z]?[0-9][A-Z0-9]? ?[0-9][ABDEFGHJLNPQRSTUWXYZ]{2}/";

preg_match($postcode_pattern, $application->address, $postcode_matches);
if(isset($postcode_matches[0])){
$application->postcode = $postcode_matches[0];
}

//get full details
$details_html = "";
$details_html = safe_scrape_page($info_url_base . $case_number);

//regular expresion and clean
$full_detail_pattern = '/id="desc" rows="[1-9]" cols="80" class="cDetailInput">([^<]*)/';
preg_match($full_detail_pattern, $details_html, $full_detail_matches);
if (isset($full_detail_matches[0])){
$application->description = substr($full_detail_matches[0], strpos($full_detail_matches[0], ">") + 1);
}

//only add it if we have a postcode (bit useless otherwise)
if(is_postcode($application->postcode)){
array_push($applications, $application);
}
}else{
error_log("Unable to find case number for an application at " . $search_url);
}
}

//return
return $applications;
}

function scrape_applications_wam ($search_url, $info_url_base, $comment_url_base){

$applications = array();
$application_pattern = '/<tr><td class=[^>]*>([^<]*)<\/td><td class=[^>]*><a href="[^"]*">([^<]*)<\/a><\/td><td class=[^>]*>([^<]*)<\/td><td class=[^>]*>([^<]*)<\/td>/';


//grab the page
$html = safe_scrape_page($search_url);

//clean html
$html = str_replace("\r\n","", $html);

preg_match_all($application_pattern, $html, $application_matches, PREG_SET_ORDER);

foreach ($application_matches as $application_match){
if ($application_match[4] != 'Current') { continue; }

$application = new Application();

//match the basic details
$application->council_reference = $application_match[2];
$case_number = $application_match[2];
$application->date_received = $application_match[1];
$application->address = $application_match[3];
//$application->status = $application_match[4];
//if weve found a caase number, then get the details
if($case_number !=""){
//Comment and info urls
$application->info_url = $info_url_base . $case_number;
$application->comment_url = $comment_url_base . $case_number;

//Get the postcode
$postcode_pattern = "/[A-Z][A-Z]?[0-9][A-Z0-9]? ?[0-9][ABDEFGHJLNPQRSTUWXYZ]{2}/";

preg_match($postcode_pattern, $application->address, $postcode_matches);
if(isset($postcode_matches[0])){
$application->postcode = $postcode_matches[0];
}

//get full details
$details_html = "";
$details_html = safe_scrape_page($info_url_base . $case_number);
$details_html = str_replace("\r\n","",$details_html);

//regular expresion and clean
$full_detail_pattern = '/Development:<.*<td colspan="3">([^<]*)<\/td>/';
preg_match($full_detail_pattern, $details_html, $full_detail_matches);
if (isset($full_detail_matches[1])){
$application->description = $full_detail_matches[1];
}

//only add it if we have a postcode (bit useless otherwise)
if(is_postcode($application->postcode)){
//removed the xy for the moment. It is slowing down the scrape and will be added when the app is parsed anyway (Richard)
/* $xy = postcode_to_location($application->postcode);
$application->x = $xy[0];
$application->y = $xy[1];
$os = new OSRef($xy[0],$xy[1]);
$latlon = $os->toLatLng();
$application->lat = $latlon->lat;
$application->lon = $latlon->lng;
*/
array_push($applications, $application);
}
}else{
error_log("Unable to find case number for an application at " . $search_url);
}

}

//return
return $applications;
}

// Council specific scapers
function scrape_applications_islington ($search_url, $info_url_base, $comment_url_base){

$applications = array();
$application_pattern = '/<TR>([^<]*)<TD class="lg" valign="top" >([^<]*)<a href([^<]*)<a href=wphappcriteria.display>Search Criteria(.*)([^<]*)<(.*)>([^<]*)<TD class="lg" >([^<]*)<\/TD>([^<]*)<TD class="lg" >([^<]*)<INPUT TYPE=HIDDEN NAME([^>]*)([^<]*)/';

//grab the page
$html = safe_scrape_page($search_url);


preg_match_all($application_pattern, $html, $application_matches, PREG_PATTERN_ORDER);

foreach ($application_matches[0] as $application_match){
$application_string = str_replace("\n","", $application_match);
$reference_pattern = '/Search Results<\/a>">([^<]*)/';
preg_match_all($reference_pattern, $application_string, $reference_matches, PREG_PATTERN_ORDER);

$application = new Application();

//match the applicaiton number
$application->council_reference = str_replace('Search Results</a>">', "", $reference_matches[0][0]);

//Comment and info urls
$application->info_url = $info_url_base . $application->council_reference;
//$application->comment_url = $comment_url_base . $case_number;

//get full details
$details_html = "";
$details_html = safe_scrape_page($info_url_base . $application->council_reference);
// $details_html = str_replace("\n","", $details_html);
// $details_html = str_replace("\t","", $details_html);


//Details
print $details_html;exit;

//Address
$address_pattern = '/Main location:<\/label><\/td>([^<]*)<td colspan="3">([^<]*)/';
$address = "";
preg_match($address_pattern, $details_html, $address_matches);
if(isset($address_matches[2])){
$application->address = $address_matches[2];
}
//postcode
$postcode_pattern = "/[A-Z][A-Z]?[0-9][A-Z0-9]? ?[0-9][ABDEFGHJLNPQRSTUWXYZ]{2}/";
preg_match($postcode_pattern, $application->address, $postcode_matches);
if(isset($postcode_matches[0])){
$application->postcode = $postcode_matches[0];
}

//only add it if we have a postcode (bit useless otherwise)
if(is_postcode($application->postcode)){
array_push($applications, $application);
}
}

//return
return $applications;
}
//validate postcode
function is_postcode ($postcode){
$valid = false;
$postcode=str_replace(" ","",$postcode);
if(ereg ('^[a-zA-Z]{1,2}[0-9]{1,2}[a-zA-Z]{0,1}[0-9]{1}[a-zA-Z]{2}$', $postcode)){
$valid = true;
}
return $valid;
}
//Tiny url
function tiny_url($url,$length=30){

// make nasty big url all small
if (strlen($url) >= $length){
$tinyurl = @file ("http://tinyurl.com/api-create.php?url=$url");
if (is_array($tinyurl)){
$tinyurl = join ('', $tinyurl);
} else {
$tinyurl = $url;
}
} else {
$tinyurl = $url;
}

return $tinyurl;
}
//Google maps url
function googlemap_url_from_postcode($postcode, $zoom = 15){
$postcode = strtolower(str_replace(" ", "+", $postcode));
return "http://maps.google.com/maps?q=$postcode&z=$zoom";
}
//postcode to location
function postcode_to_location($postcode){
$x = 0;
$y = 0;
$clean_postcode = strtolower($postcode);
$clean_postcode = str_replace(" ","+", $clean_postcode);
$url = "http://www.streetmap.co.uk/newsearch.srf?type=Postcode&name=" . $clean_postcode;

$html = file_get_contents($url);
$x_pattern = "/var _LocationX=\d*;/";
$y_pattern = "/var _LocationY=\d*;/";
//X
preg_match($x_pattern, $html, $matches);
if(sizeof($matches) >0){
$x = $matches[0];
$x = str_replace('var _LocationX=',"", $x);
$x = str_replace(";","", $x);
}
//Y
preg_match($y_pattern, $html, $matches);
if(sizeof($matches) >0){
$y = str_replace("var _LocationY=","", $matches[0]);
$y = str_replace(";","", $y);
}
$return = array();
$return[0] = $x;
$return[1] = $y;
return $return;
}
function valid_email ($string) {
$valid = false;
if (!ereg('^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.
'@'.
'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.
'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$', $string)) {
$valid = false;
} else {
$valid = true;
}
return $valid;
}
function alert_size_to_meters($alert_area_size){
$area_size_meters = 0;
if ($alert_area_size == "s"){
$area_size_meters = SMALL_ZONE_SIZE;
}elseif ($alert_area_size == "m"){
$area_size_meters = MEDIUM_ZONE_SIZE;
}elseif ($alert_area_size == "l"){
$area_size_meters = LARGE_ZONE_SIZE;
}
return $area_size_meters;
}
//Send a text email
function send_text_email($to, $from_name, $from_email, $subject, $body){
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/plain; charset=iso-8859-1' . "\r\n";
$headers .= 'From: ' . $from_name. ' <' . $from_email . ">\r\n";
mail($to, $subject, $body, $headers);

}
// Format a date to mysql format
function mysql_date($date){
return date("Y-m-d H::i:s", $date);
}
function safe_scrape_page($url, $method = "GET"){
error_log(print_r($url, true));
$page = "";
for ($i=0; $i < 3; $i++){
if($page == false){
if (SCRAPE_METHOD == "PEAR"){
$page = scrape_page_pear($url, $method);
}else{
$page = scrape_page_curl($url, $method);
}
}
}
return $page;
}
function scrape_page_pear($url, $method = "GET"){
$page = "";
$request = new HTTP_Request($url, array("method" => $method));
$request->sendRequest();
$page = $request->getResponseBody();
return $page;

}
function scrape_page_curl($url) {
$ch = curl_init($url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,TRUE);
return curl_exec($ch);
}
function display_applications($applications, $authority_name, $authority_short_name){
//smarty
$smarty = new Smarty;
$smarty->force_compile = true;
$smarty->compile_dir = SMARTY_COMPILE_DIRECTORY;
$smarty->template_dir = "../templates";
$smarty->assign("authority_name", $authority_name);
$smarty->assign("authority_short_name", $authority_short_name);

if (sizeof($applications) > 0){
$smarty->assign("applications", $applications);
}

$smarty->display("xml.tpl");
}
function get_time_from_get(){
//if any get params were passed, overwrite the default date
if (isset($_GET['day'])){
$day = $_GET['day'];
}else{
throw_error("No day set in get string");
}
if (isset($_GET['month'])){
$month = $_GET['month'];
}else{
throw_error("No year set in get string");
}

if (isset($_GET['year'])){
$year = $_GET['year'];
}else{
throw_error("No year set in get string");
}

return mktime(0,0,0,$month,$day,$year);

}
function throw_error($message){
throw new exception($message);
}

?>

+ 389
- 0
trunk/docs/include/smarty/Config_File.class.php Näytä tiedosto

@@ -0,0 +1,389 @@
<?php

/**
* Config_File class.
*
* 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
*
* @link http://smarty.php.net/
* @version 2.6.16
* @copyright Copyright: 2001-2005 New Digital Group, Inc.
* @author Andrei Zmievski <andrei@php.net>
* @access public
* @package Smarty
*/

/* $Id: Config_File.class.php,v 1.86 2006/11/30 17:01:28 mohrt Exp $ */

/**
* Config file reading class
* @package Smarty
*/
class Config_File {
/**#@+
* Options
* @var boolean
*/
/**
* Controls whether variables with the same name overwrite each other.
*/
var $overwrite = true;

/**
* Controls whether config values of on/true/yes and off/false/no get
* converted to boolean values automatically.
*/
var $booleanize = true;

/**
* Controls whether hidden config sections/vars are read from the file.
*/
var $read_hidden = true;

/**
* Controls whether or not to fix mac or dos formatted newlines.
* If set to true, \r or \r\n will be changed to \n.
*/
var $fix_newlines = true;
/**#@-*/

/** @access private */
var $_config_path = "";
var $_config_data = array();
/**#@-*/

/**
* Constructs a new config file class.
*
* @param string $config_path (optional) path to the config files
*/
function Config_File($config_path = NULL)
{
if (isset($config_path))
$this->set_path($config_path);
}


/**
* Set the path where configuration files can be found.
*
* @param string $config_path path to the config files
*/
function set_path($config_path)
{
if (!empty($config_path)) {
if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) {
$this->_trigger_error_msg("Bad config file path '$config_path'");
return;
}
if(substr($config_path, -1) != DIRECTORY_SEPARATOR) {
$config_path .= DIRECTORY_SEPARATOR;
}

$this->_config_path = $config_path;
}
}


/**
* Retrieves config info based on the file, section, and variable name.
*
* @param string $file_name config file to get info for
* @param string $section_name (optional) section to get info for
* @param string $var_name (optional) variable to get info for
* @return string|array a value or array of values
*/
function get($file_name, $section_name = NULL, $var_name = NULL)
{
if (empty($file_name)) {
$this->_trigger_error_msg('Empty config file name');
return;
} else {
$file_name = $this->_config_path . $file_name;
if (!isset($this->_config_data[$file_name]))
$this->load_file($file_name, false);
}

if (!empty($var_name)) {
if (empty($section_name)) {
return $this->_config_data[$file_name]["vars"][$var_name];
} else {
if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]))
return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name];
else
return array();
}
} else {
if (empty($section_name)) {
return (array)$this->_config_data[$file_name]["vars"];
} else {
if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"]))
return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"];
else
return array();
}
}
}


/**
* Retrieves config info based on the key.
*
* @param $file_name string config key (filename/section/var)
* @return string|array same as get()
* @uses get() retrieves information from config file and returns it
*/
function &get_key($config_key)
{
list($file_name, $section_name, $var_name) = explode('/', $config_key, 3);
$result = &$this->get($file_name, $section_name, $var_name);
return $result;
}

/**
* Get all loaded config file names.
*
* @return array an array of loaded config file names
*/
function get_file_names()
{
return array_keys($this->_config_data);
}


/**
* Get all section names from a loaded file.
*
* @param string $file_name config file to get section names from
* @return array an array of section names from the specified file
*/
function get_section_names($file_name)
{
$file_name = $this->_config_path . $file_name;
if (!isset($this->_config_data[$file_name])) {
$this->_trigger_error_msg("Unknown config file '$file_name'");
return;
}

return array_keys($this->_config_data[$file_name]["sections"]);
}


/**
* Get all global or section variable names.
*
* @param string $file_name config file to get info for
* @param string $section_name (optional) section to get info for
* @return array an array of variables names from the specified file/section
*/
function get_var_names($file_name, $section = NULL)
{
if (empty($file_name)) {
$this->_trigger_error_msg('Empty config file name');
return;
} else if (!isset($this->_config_data[$file_name])) {
$this->_trigger_error_msg("Unknown config file '$file_name'");
return;
}

if (empty($section))
return array_keys($this->_config_data[$file_name]["vars"]);
else
return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]);
}


/**
* Clear loaded config data for a certain file or all files.
*
* @param string $file_name file to clear config data for
*/
function clear($file_name = NULL)
{
if ($file_name === NULL)
$this->_config_data = array();
else if (isset($this->_config_data[$file_name]))
$this->_config_data[$file_name] = array();
}


/**
* Load a configuration file manually.
*
* @param string $file_name file name to load
* @param boolean $prepend_path whether current config path should be
* prepended to the filename
*/
function load_file($file_name, $prepend_path = true)
{
if ($prepend_path && $this->_config_path != "")
$config_file = $this->_config_path . $file_name;
else
$config_file = $file_name;

ini_set('track_errors', true);
$fp = @fopen($config_file, "r");
if (!is_resource($fp)) {
$this->_trigger_error_msg("Could not open config file '$config_file'");
return false;
}

$contents = ($size = filesize($config_file)) ? fread($fp, $size) : '';
fclose($fp);

$this->_config_data[$config_file] = $this->parse_contents($contents);
return true;
}

/**
* Store the contents of a file manually.
*
* @param string $config_file file name of the related contents
* @param string $contents the file-contents to parse
*/
function set_file_contents($config_file, $contents)
{
$this->_config_data[$config_file] = $this->parse_contents($contents);
return true;
}

/**
* parse the source of a configuration file manually.
*
* @param string $contents the file-contents to parse
*/
function parse_contents($contents)
{
if($this->fix_newlines) {
// fix mac/dos formatted newlines
$contents = preg_replace('!\r\n?!', "\n", $contents);
}

$config_data = array();
$config_data['sections'] = array();
$config_data['vars'] = array();

/* reference to fill with data */
$vars =& $config_data['vars'];

/* parse file line by line */
preg_match_all('!^.*\r?\n?!m', $contents, $match);
$lines = $match[0];
for ($i=0, $count=count($lines); $i<$count; $i++) {
$line = $lines[$i];
if (empty($line)) continue;

if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) {
/* section found */
if (substr($match[1], 0, 1) == '.') {
/* hidden section */
if ($this->read_hidden) {
$section_name = substr($match[1], 1);
} else {
/* break reference to $vars to ignore hidden section */
unset($vars);
$vars = array();
continue;
}
} else {
$section_name = $match[1];
}
if (!isset($config_data['sections'][$section_name]))
$config_data['sections'][$section_name] = array('vars' => array());
$vars =& $config_data['sections'][$section_name]['vars'];
continue;
}

if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) {
/* variable found */
$var_name = rtrim($match[1]);
if (strpos($match[2], '"""') === 0) {
/* handle multiline-value */
$lines[$i] = substr($match[2], 3);
$var_value = '';
while ($i<$count) {
if (($pos = strpos($lines[$i], '"""')) === false) {
$var_value .= $lines[$i++];
} else {
/* end of multiline-value */
$var_value .= substr($lines[$i], 0, $pos);
break;
}
}
$booleanize = false;

} else {
/* handle simple value */
$var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2]));
$booleanize = $this->booleanize;

}
$this->_set_config_var($vars, $var_name, $var_value, $booleanize);
}
/* else unparsable line / means it is a comment / means ignore it */
}
return $config_data;
}

/**#@+ @access private */
/**
* @param array &$container
* @param string $var_name
* @param mixed $var_value
* @param boolean $booleanize determines whether $var_value is converted to
* to true/false
*/
function _set_config_var(&$container, $var_name, $var_value, $booleanize)
{
if (substr($var_name, 0, 1) == '.') {
if (!$this->read_hidden)
return;
else
$var_name = substr($var_name, 1);
}

if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) {
$this->_trigger_error_msg("Bad variable name '$var_name'");
return;
}

if ($booleanize) {
if (preg_match("/^(on|true|yes)$/i", $var_value))
$var_value = true;
else if (preg_match("/^(off|false|no)$/i", $var_value))
$var_value = false;
}

if (!isset($container[$var_name]) || $this->overwrite)
$container[$var_name] = $var_value;
else {
settype($container[$var_name], 'array');
$container[$var_name][] = $var_value;
}
}

/**
* @uses trigger_error() creates a PHP warning/error
* @param string $error_msg
* @param integer $error_type one of
*/
function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING)
{
trigger_error("Config_File error: $error_msg", $error_type);
}
/**#@-*/
}

?>

+ 1944
- 0
trunk/docs/include/smarty/Smarty.class.php
File diff suppressed because it is too large
Näytä tiedosto


+ 2320
- 0
trunk/docs/include/smarty/Smarty_Compiler.class.php
File diff suppressed because it is too large
Näytä tiedosto


+ 157
- 0
trunk/docs/include/smarty/debug.tpl Näytä tiedosto

@@ -0,0 +1,157 @@
{* Smarty *}
{* debug.tpl, last updated version 2.1.0 *}
{assign_debug_info}
{capture assign=debug_output}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Smarty Debug Console</title>
{literal}
<style type="text/css">
/* <![CDATA[ */
body, h1, h2, td, th, p {
font-family: sans-serif;
font-weight: normal;
font-size: 0.9em;
margin: 1px;
padding: 0;
}

h1 {
margin: 0;
text-align: left;
padding: 2px;
background-color: #f0c040;
color: black;
font-weight: bold;
font-size: 1.2em;
}

h2 {
background-color: #9B410E;
color: white;
text-align: left;
font-weight: bold;
padding: 2px;
border-top: 1px solid black;
}

body {
background: black;
}

p, table, div {
background: #f0ead8;
}

p {
margin: 0;
font-style: italic;
text-align: center;
}

table {
width: 100%;
}

th, td {
font-family: monospace;
vertical-align: top;
text-align: left;
width: 50%;
}

td {
color: green;
}

.odd {
background-color: #eeeeee;
}

.even {
background-color: #fafafa;
}

.exectime {
font-size: 0.8em;
font-style: italic;
}

#table_assigned_vars th {
color: blue;
}

#table_config_vars th {
color: maroon;
}
/* ]]> */
</style>
{/literal}
</head>
<body>

<h1>Smarty Debug Console</h1>

<h2>included templates &amp; config files (load time in seconds)</h2>

<div>
{section name=templates loop=$_debug_tpls}
{section name=indent loop=$_debug_tpls[templates].depth}&nbsp;&nbsp;&nbsp;{/section}
<font color={if $_debug_tpls[templates].type eq "template"}brown{elseif $_debug_tpls[templates].type eq "insert"}black{else}green{/if}>
{$_debug_tpls[templates].filename|escape:html}</font>
{if isset($_debug_tpls[templates].exec_time)}
<span class="exectime">
({$_debug_tpls[templates].exec_time|string_format:"%.5f"})
{if %templates.index% eq 0}(total){/if}
</span>
{/if}
<br />
{sectionelse}
<p>no templates included</p>
{/section}
</div>

<h2>assigned template variables</h2>

<table id="table_assigned_vars">
{section name=vars loop=$_debug_keys}
<tr class="{cycle values="odd,even"}">
<th>{ldelim}${$_debug_keys[vars]|escape:'html'}{rdelim}</th>
<td>{$_debug_vals[vars]|@debug_print_var}</td></tr>
{sectionelse}
<tr><td><p>no template variables assigned</p></td></tr>
{/section}
</table>

<h2>assigned config file variables (outer template scope)</h2>

<table id="table_config_vars">
{section name=config_vars loop=$_debug_config_keys}
<tr class="{cycle values="odd,even"}">
<th>{ldelim}#{$_debug_config_keys[config_vars]|escape:'html'}#{rdelim}</th>
<td>{$_debug_config_vals[config_vars]|@debug_print_var}</td></tr>
{sectionelse}
<tr><td><p>no config vars assigned</p></td></tr>
{/section}
</table>
</body>
</html>
{/capture}
{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"}
{$debug_output}
{else}
<script type="text/javascript">
// <![CDATA[
if ( self.name == '' ) {ldelim}
var title = 'Console';
{rdelim}
else {ldelim}
var title = 'Console_' + self.name;
{rdelim}
_smarty_console = window.open("",title.value,"width=680,height=600,resizable,scrollbars=yes");
_smarty_console.document.write('{$debug_output|escape:'javascript'}');
_smarty_console.document.close();
// ]]>
</script>
{/if}

+ 67
- 0
trunk/docs/include/smarty/internals/core.assemble_plugin_filepath.php Näytä tiedosto

@@ -0,0 +1,67 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* assemble filepath of requested plugin
*
* @param string $type
* @param string $name
* @return string|false
*/
function smarty_core_assemble_plugin_filepath($params, &$smarty)
{
static $_filepaths_cache = array();

$_plugin_filename = $params['type'] . '.' . $params['name'] . '.php';
if (isset($_filepaths_cache[$_plugin_filename])) {
return $_filepaths_cache[$_plugin_filename];
}
$_return = false;

foreach ((array)$smarty->plugins_dir as $_plugin_dir) {

$_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;

// see if path is relative
if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) {
$_relative_paths[] = $_plugin_dir;
// relative path, see if it is in the SMARTY_DIR
if (@is_readable(SMARTY_DIR . $_plugin_filepath)) {
$_return = SMARTY_DIR . $_plugin_filepath;
break;
}
}
// try relative to cwd (or absolute)
if (@is_readable($_plugin_filepath)) {
$_return = $_plugin_filepath;
break;
}
}

if($_return === false) {
// still not found, try PHP include_path
if(isset($_relative_paths)) {
foreach ((array)$_relative_paths as $_plugin_dir) {

$_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;

$_params = array('file_path' => $_plugin_filepath);
require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
if(smarty_core_get_include_path($_params, $smarty)) {
$_return = $_params['new_file_path'];
break;
}
}
}
}
$_filepaths_cache[$_plugin_filename] = $_return;
return $_return;
}

/* vim: set expandtab: */

?>

+ 43
- 0
trunk/docs/include/smarty/internals/core.assign_smarty_interface.php Näytä tiedosto

@@ -0,0 +1,43 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Smarty assign_smarty_interface core plugin
*
* Type: core<br>
* Name: assign_smarty_interface<br>
* Purpose: assign the $smarty interface variable
* @param array Format: null
* @param Smarty
*/
function smarty_core_assign_smarty_interface($params, &$smarty)
{
if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) {
return;
}

$_globals_map = array('g' => 'HTTP_GET_VARS',
'p' => 'HTTP_POST_VARS',
'c' => 'HTTP_COOKIE_VARS',
's' => 'HTTP_SERVER_VARS',
'e' => 'HTTP_ENV_VARS');

$_smarty_vars_request = array();

foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) {
if (isset($_globals_map[$_c])) {
$_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]);
}
}
$_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']);

$smarty->_smarty_vars['request'] = $_smarty_vars_request;
}

/* vim: set expandtab: */

?>

+ 79
- 0
trunk/docs/include/smarty/internals/core.create_dir_structure.php Näytä tiedosto

@@ -0,0 +1,79 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* create full directory structure
*
* @param string $dir
*/

// $dir

function smarty_core_create_dir_structure($params, &$smarty)
{
if (!file_exists($params['dir'])) {
$_open_basedir_ini = ini_get('open_basedir');

if (DIRECTORY_SEPARATOR=='/') {
/* unix-style paths */
$_dir = $params['dir'];
$_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);
$_new_dir = (substr($_dir, 0, 1)=='/') ? '/' : getcwd().'/';
if($_use_open_basedir = !empty($_open_basedir_ini)) {
$_open_basedirs = explode(':', $_open_basedir_ini);
}

} else {
/* other-style paths */
$_dir = str_replace('\\','/', $params['dir']);
$_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);
if (preg_match('!^((//)|([a-zA-Z]:/))!', $_dir, $_root_dir)) {
/* leading "//" for network volume, or "[letter]:/" for full path */
$_new_dir = $_root_dir[1];
/* remove drive-letter from _dir_parts */
if (isset($_root_dir[3])) array_shift($_dir_parts);

} else {
$_new_dir = str_replace('\\', '/', getcwd()).'/';

}

if($_use_open_basedir = !empty($_open_basedir_ini)) {
$_open_basedirs = explode(';', str_replace('\\', '/', $_open_basedir_ini));
}

}

/* all paths use "/" only from here */
foreach ($_dir_parts as $_dir_part) {
$_new_dir .= $_dir_part;

if ($_use_open_basedir) {
// do not attempt to test or make directories outside of open_basedir
$_make_new_dir = false;
foreach ($_open_basedirs as $_open_basedir) {
if (substr($_new_dir, 0, strlen($_open_basedir)) == $_open_basedir) {
$_make_new_dir = true;
break;
}
}
} else {
$_make_new_dir = true;
}

if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, $smarty->_dir_perms) && !is_dir($_new_dir)) {
$smarty->trigger_error("problem creating directory '" . $_new_dir . "'");
return false;
}
$_new_dir .= '/';
}
}
}

/* vim: set expandtab: */

?>

+ 61
- 0
trunk/docs/include/smarty/internals/core.display_debug_console.php Näytä tiedosto

@@ -0,0 +1,61 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Smarty debug_console function plugin
*
* Type: core<br>
* Name: display_debug_console<br>
* Purpose: display the javascript debug console window
* @param array Format: null
* @param Smarty
*/
function smarty_core_display_debug_console($params, &$smarty)
{
// we must force compile the debug template in case the environment
// changed between separate applications.

if(empty($smarty->debug_tpl)) {
// set path to debug template from SMARTY_DIR
$smarty->debug_tpl = SMARTY_DIR . 'debug.tpl';
if($smarty->security && is_file($smarty->debug_tpl)) {
$smarty->secure_dir[] = realpath($smarty->debug_tpl);
}
$smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl';
}

$_ldelim_orig = $smarty->left_delimiter;
$_rdelim_orig = $smarty->right_delimiter;

$smarty->left_delimiter = '{';
$smarty->right_delimiter = '}';

$_compile_id_orig = $smarty->_compile_id;
$smarty->_compile_id = null;

$_compile_path = $smarty->_get_compile_path($smarty->debug_tpl);
if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path))
{
ob_start();
$smarty->_include($_compile_path);
$_results = ob_get_contents();
ob_end_clean();
} else {
$_results = '';
}

$smarty->_compile_id = $_compile_id_orig;

$smarty->left_delimiter = $_ldelim_orig;
$smarty->right_delimiter = $_rdelim_orig;

return $_results;
}

/* vim: set expandtab: */

?>

+ 44
- 0
trunk/docs/include/smarty/internals/core.get_include_path.php Näytä tiedosto

@@ -0,0 +1,44 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Get path to file from include_path
*
* @param string $file_path
* @param string $new_file_path
* @return boolean
* @staticvar array|null
*/

// $file_path, &$new_file_path

function smarty_core_get_include_path(&$params, &$smarty)
{
static $_path_array = null;

if(!isset($_path_array)) {
$_ini_include_path = ini_get('include_path');

if(strstr($_ini_include_path,';')) {
// windows pathnames
$_path_array = explode(';',$_ini_include_path);
} else {
$_path_array = explode(':',$_ini_include_path);
}
}
foreach ($_path_array as $_include_path) {
if (@is_readable($_include_path . DIRECTORY_SEPARATOR . $params['file_path'])) {
$params['new_file_path'] = $_include_path . DIRECTORY_SEPARATOR . $params['file_path'];
return true;
}
}
return false;
}

/* vim: set expandtab: */

?>

+ 23
- 0
trunk/docs/include/smarty/internals/core.get_microtime.php Näytä tiedosto

@@ -0,0 +1,23 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Get seconds and microseconds
* @return double
*/
function smarty_core_get_microtime($params, &$smarty)
{
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = (double)($mtime[1]) + (double)($mtime[0]);
return ($mtime);
}


/* vim: set expandtab: */

?>

+ 80
- 0
trunk/docs/include/smarty/internals/core.get_php_resource.php Näytä tiedosto

@@ -0,0 +1,80 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Retrieves PHP script resource
*
* sets $php_resource to the returned resource
* @param string $resource
* @param string $resource_type
* @param $php_resource
* @return boolean
*/

function smarty_core_get_php_resource(&$params, &$smarty)
{

$params['resource_base_path'] = $smarty->trusted_dir;
$smarty->_parse_resource_name($params, $smarty);

/*
* Find out if the resource exists.
*/

if ($params['resource_type'] == 'file') {
$_readable = false;
if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) {
$_readable = true;
} else {
// test for file in include_path
$_params = array('file_path' => $params['resource_name']);
require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
if(smarty_core_get_include_path($_params, $smarty)) {
$_include_path = $_params['new_file_path'];
$_readable = true;
}
}
} else if ($params['resource_type'] != 'file') {
$_template_source = null;
$_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0])
&& call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0],
array($params['resource_name'], &$_template_source, &$smarty));
}

/*
* Set the error function, depending on which class calls us.
*/
if (method_exists($smarty, '_syntax_error')) {
$_error_funcc = '_syntax_error';
} else {
$_error_funcc = 'trigger_error';
}

if ($_readable) {
if ($smarty->security) {
require_once(SMARTY_CORE_DIR . 'core.is_trusted.php');
if (!smarty_core_is_trusted($params, $smarty)) {
$smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted');
return false;
}
}
} else {
$smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable');
return false;
}

if ($params['resource_type'] == 'file') {
$params['php_resource'] = $params['resource_name'];
} else {
$params['php_resource'] = $_template_source;
}
return true;
}

/* vim: set expandtab: */

?>

+ 59
- 0
trunk/docs/include/smarty/internals/core.is_secure.php Näytä tiedosto

@@ -0,0 +1,59 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* determines if a resource is secure or not.
*
* @param string $resource_type
* @param string $resource_name
* @return boolean
*/

// $resource_type, $resource_name

function smarty_core_is_secure($params, &$smarty)
{
if (!$smarty->security || $smarty->security_settings['INCLUDE_ANY']) {
return true;
}

if ($params['resource_type'] == 'file') {
$_rp = realpath($params['resource_name']);
if (isset($params['resource_base_path'])) {
foreach ((array)$params['resource_base_path'] as $curr_dir) {
if ( ($_cd = realpath($curr_dir)) !== false &&
strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) {
return true;
}
}
}
if (!empty($smarty->secure_dir)) {
foreach ((array)$smarty->secure_dir as $curr_dir) {
if ( ($_cd = realpath($curr_dir)) !== false) {
if($_cd == $_rp) {
return true;
} elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR) {
return true;
}
}
}
}
} else {
// resource is not on local file system
return call_user_func_array(
$smarty->_plugins['resource'][$params['resource_type']][0][2],
array($params['resource_name'], &$smarty));
}

return false;
}

/* vim: set expandtab: */

?>

+ 47
- 0
trunk/docs/include/smarty/internals/core.is_trusted.php Näytä tiedosto

@@ -0,0 +1,47 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* determines if a resource is trusted or not
*
* @param string $resource_type
* @param string $resource_name
* @return boolean
*/

// $resource_type, $resource_name

function smarty_core_is_trusted($params, &$smarty)
{
$_smarty_trusted = false;
if ($params['resource_type'] == 'file') {
if (!empty($smarty->trusted_dir)) {
$_rp = realpath($params['resource_name']);
foreach ((array)$smarty->trusted_dir as $curr_dir) {
if (!empty($curr_dir) && is_readable ($curr_dir)) {
$_cd = realpath($curr_dir);
if (strncmp($_rp, $_cd, strlen($_cd)) == 0
&& substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) {
$_smarty_trusted = true;
break;
}
}
}
}

} else {
// resource is not on local file system
$_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3],
array($params['resource_name'], $smarty));
}

return $_smarty_trusted;
}

/* vim: set expandtab: */

?>

+ 125
- 0
trunk/docs/include/smarty/internals/core.load_plugins.php Näytä tiedosto

@@ -0,0 +1,125 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Load requested plugins
*
* @param array $plugins
*/

// $plugins

function smarty_core_load_plugins($params, &$smarty)
{

foreach ($params['plugins'] as $_plugin_info) {
list($_type, $_name, $_tpl_file, $_tpl_line, $_delayed_loading) = $_plugin_info;
$_plugin = &$smarty->_plugins[$_type][$_name];

/*
* We do not load plugin more than once for each instance of Smarty.
* The following code checks for that. The plugin can also be
* registered dynamically at runtime, in which case template file
* and line number will be unknown, so we fill them in.
*
* The final element of the info array is a flag that indicates
* whether the dynamically registered plugin function has been
* checked for existence yet or not.
*/
if (isset($_plugin)) {
if (empty($_plugin[3])) {
if (!is_callable($_plugin[0])) {
$smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__);
} else {
$_plugin[1] = $_tpl_file;
$_plugin[2] = $_tpl_line;
$_plugin[3] = true;
if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */
}
}
continue;
} else if ($_type == 'insert') {
/*
* For backwards compatibility, we check for insert functions in
* the symbol table before trying to load them as a plugin.
*/
$_plugin_func = 'insert_' . $_name;
if (function_exists($_plugin_func)) {
$_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false);
continue;
}
}

$_plugin_file = $smarty->_get_plugin_filepath($_type, $_name);

if (! $_found = ($_plugin_file != false)) {
$_message = "could not load plugin file '$_type.$_name.php'\n";
}

/*
* If plugin file is found, it -must- provide the properly named
* plugin function. In case it doesn't, simply output the error and
* do not fall back on any other method.
*/
if ($_found) {
include_once $_plugin_file;

$_plugin_func = 'smarty_' . $_type . '_' . $_name;
if (!function_exists($_plugin_func)) {
$smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__);
continue;
}
}
/*
* In case of insert plugins, their code may be loaded later via
* 'script' attribute.
*/
else if ($_type == 'insert' && $_delayed_loading) {
$_plugin_func = 'smarty_' . $_type . '_' . $_name;
$_found = true;
}

/*
* Plugin specific processing and error checking.
*/
if (!$_found) {
if ($_type == 'modifier') {
/*
* In case modifier falls back on using PHP functions
* directly, we only allow those specified in the security
* context.
*/
if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) {
$_message = "(secure mode) modifier '$_name' is not allowed";
} else {
if (!function_exists($_name)) {
$_message = "modifier '$_name' is not implemented";
} else {
$_plugin_func = $_name;
$_found = true;
}
}
} else if ($_type == 'function') {
/*
* This is a catch-all situation.
*/
$_message = "unknown tag - '$_name'";
}
}

if ($_found) {
$smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true);
} else {
// output error
$smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__);
}
}
}

/* vim: set expandtab: */

?>

+ 74
- 0
trunk/docs/include/smarty/internals/core.load_resource_plugin.php Näytä tiedosto

@@ -0,0 +1,74 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* load a resource plugin
*
* @param string $type
*/

// $type

function smarty_core_load_resource_plugin($params, &$smarty)
{
/*
* Resource plugins are not quite like the other ones, so they are
* handled differently. The first element of plugin info is the array of
* functions provided by the plugin, the second one indicates whether
* all of them exist or not.
*/

$_plugin = &$smarty->_plugins['resource'][$params['type']];
if (isset($_plugin)) {
if (!$_plugin[1] && count($_plugin[0])) {
$_plugin[1] = true;
foreach ($_plugin[0] as $_plugin_func) {
if (!is_callable($_plugin_func)) {
$_plugin[1] = false;
break;
}
}
}

if (!$_plugin[1]) {
$smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__);
}

return;
}

$_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']);
$_found = ($_plugin_file != false);

if ($_found) { /*
* If the plugin file is found, it -must- provide the properly named
* plugin functions.
*/
include_once($_plugin_file);

/*
* Locate functions that we require the plugin to provide.
*/
$_resource_ops = array('source', 'timestamp', 'secure', 'trusted');
$_resource_funcs = array();
foreach ($_resource_ops as $_op) {
$_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op;
if (!function_exists($_plugin_func)) {
$smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__);
return;
} else {
$_resource_funcs[] = $_plugin_func;
}
}

$smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true);
}
}

/* vim: set expandtab: */

?>

+ 71
- 0
trunk/docs/include/smarty/internals/core.process_cached_inserts.php Näytä tiedosto

@@ -0,0 +1,71 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Replace cached inserts with the actual results
*
* @param string $results
* @return string
*/
function smarty_core_process_cached_inserts($params, &$smarty)
{
preg_match_all('!'.$smarty->_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis',
$params['results'], $match);
list($cached_inserts, $insert_args) = $match;

for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {
if ($smarty->debugging) {
$_params = array();
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
$debug_start_time = smarty_core_get_microtime($_params, $smarty);
}

$args = unserialize($insert_args[$i]);
$name = $args['name'];

if (isset($args['script'])) {
$_params = array('resource_name' => $smarty->_dequote($args['script']));
require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
if(!smarty_core_get_php_resource($_params, $smarty)) {
return false;
}
$resource_type = $_params['resource_type'];
$php_resource = $_params['php_resource'];


if ($resource_type == 'file') {
$smarty->_include($php_resource, true);
} else {
$smarty->_eval($php_resource);
}
}

$function_name = $smarty->_plugins['insert'][$name][0];
if (empty($args['assign'])) {
$replace = $function_name($args, $smarty);
} else {
$smarty->assign($args['assign'], $function_name($args, $smarty));
$replace = '';
}

$params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i]));
if ($smarty->debugging) {
$_params = array();
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
$smarty->_smarty_debug_info[] = array('type' => 'insert',
'filename' => 'insert_'.$name,
'depth' => $smarty->_inclusion_depth,
'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time);
}
}

return $params['results'];
}

/* vim: set expandtab: */

?>

+ 37
- 0
trunk/docs/include/smarty/internals/core.process_compiled_include.php Näytä tiedosto

@@ -0,0 +1,37 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* Replace nocache-tags by results of the corresponding non-cacheable
* functions and return it
*
* @param string $compiled_tpl
* @param string $cached_source
* @return string
*/

function smarty_core_process_compiled_include($params, &$smarty)
{
$_cache_including = $smarty->_cache_including;
$smarty->_cache_including = true;

$_return = $params['results'];

foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) {
$smarty->_include($_include_file_path, true);
}

foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) {
$_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s',
array(&$smarty, '_process_compiled_include_callback'),
$_return);
}
$smarty->_cache_including = $_cache_including;
return $_return;
}

?>

+ 101
- 0
trunk/docs/include/smarty/internals/core.read_cache_file.php Näytä tiedosto

@@ -0,0 +1,101 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
*/

/**
* read a cache file, determine if it needs to be
* regenerated or not
*
* @param string $tpl_file
* @param string $cache_id
* @param string $compile_id
* @param string $results
* @return boolean
*/

// $tpl_file, $cache_id, $compile_id, &$results

function smarty_core_read_cache_file(&$params, &$smarty)
{
static $content_cache = array();

if ($smarty->force_compile) {
// force compile enabled, always regenerate
return false;
}

if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) {
list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']];
return true;
}

if (!empty($smarty->cache_handler_func)) {
// use cache_handler function
call_user_func_array($smarty->cache_handler_func,
array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));
} else {
// use local cache file
$_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);
$_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);
$params['results'] = $smarty->_read_file($_cache_file);
}

if (empty($params['results'])) {
// nothing to parse (error?), regenerate cache
return false;
}

$_contents = $params['results'];
$_info_start = strpos($_contents, "\n") + 1;
$_info_len = (int)substr($_contents, 0, $_info_start - 1);
$_cache_info = unserialize(substr($_contents, $_info_start, $_info_len));
$params['results'] = substr($_contents, $_info_start + $_info_len);

if ($smarty->caching == 2 && isset ($_cache_info['expires'])){
// caching by expiration time
if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) {
// cache expired, regenerate
return false;
}
} else {
// caching by lifetime
if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) {
// cache expired, regenerate
return false;
}
}

if ($smarty->compile_check) {
$_params = array('get_source' => false, 'quiet'=>true);
foreach (array_keys($_cache_info['template']) as $_template_dep) {
$_params['resource_name'] = $_template_dep;
if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {
// template file has changed, regenerate cache
return false;
}
}

if (isset($_cache_info['config'])) {
$_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true);
foreach (array_keys($_cache_info['config']) as $_config_dep) {
$_params['resource_name'] = $_config_dep;
if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {
// config file has changed, regenerate cache
return false;
}
}
}
}

$content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info);

$smarty->_cache_info = $_cache_info;
return true;
}

/* vim: set expandtab: */

?>

Some files were not shown because too many files changed in this diff

Ladataan…
Peruuta
Tallenna