/tags/0.1/signin.php |
---|
Новый файл |
0,0 → 1,7 |
<? |
include "lib/init.php"; |
$smarty->display('signin.tpl'); |
?> |
/tags/0.1/signout.php |
---|
Новый файл |
0,0 → 1,13 |
<? |
include "lib/init.php"; |
$login = str_replace("'", "", $_COOKIE[$CookieLogin]); |
$securepass = $_COOKIE[$CookiePasswd]; |
setcookie($CookieLogin, $login, time()-10); |
setcookie($CookiePasswd, $securepass, time()-10); |
header("Location: ./"); |
exit; |
?> |
/tags/0.1/admin.php |
---|
Новый файл |
0,0 → 1,489 |
<?php |
include "./sign-valid.php"; |
$mode = abs(intval($_GET["mode"])); |
$act = abs(intval($_GET["action"])); |
$uid = abs(intval($_GET["uid"])); |
$query =& $db->query("SELECT * FROM settings WHERE opt LIKE 'version'"); |
$query->fetchInto($antv, DB_FETCHMODE_ASSOC); |
$antversion = $antv["optvalue"]; |
switch ($mode) { |
case '0': |
$display = "<ul><li><a href='./admin.php?mode=1'>Управление дистрибутивами</a></li><li><a href='./admin.php?mode=2'>Управление версиями дистрибутивов</a></li><li><a href='./admin.php?mode=3'>Управление репозиториями</a></li><li><a href='./admin.php?mode=4'>Управление секциями репозиториев</a></li><li><a href='./admin.php?mode=5'>Управление схемами репозиториев</a></li><li><a href='./admin.php?mode=7'>Управление типами репозиториев</a></li><li><a href='./admin.php?mode=6'>Управление настройками Ant</a></li></ul>"; |
break; |
case '1': |
// Работа с дистрибутивами |
switch ($act) { |
case '0': |
// Список дистрибутивов |
$dist =& $db->query("SELECT * FROM distribution"); |
if ($dist->numRows()>0) { |
$display = "В наличии есть:<ul id='distlist'>"; |
while ($dist->fetchInto($info, DB_FETCHMODE_ASSOC)) { |
$display .= "<li>".stripslashes($info["distname"])." — [<a href='./admin.php?mode=1&action=2&uid=".$info["dist_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=1&action=3&uid=".$info["dist_id"]."' class='delete'>удалить</a>]</li>"; |
} |
$display .= "</ul><p><a href='./admin.php?mode=1&action=1'>Добавить новый apt-дистрибутив</a></p>"; |
} |
break; |
case '1': |
// Добавление нового дистрибутива |
$dtype =& $db->query("SELECT * FROM dtype"); |
$type = "<select name='distType'>"; |
while ($dtype->fetchInto($dtinfo, DB_FETCHMODE_ASSOC)) { |
$type .= "<option value='".$dtinfo["type_id"]."'>".stripslashes($dtinfo["type"])."</option>"; |
} |
$type .= "</select>\n"; |
$display = "<h3>Добавление нового apt-дистрибутива</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='1'>\n"; |
$display .= "Название дистрибутива: <input type='text' name='distName'><br>\n"; |
$display .= "Тип дистрибутива: ".$type."<br>"; |
$display .= "<input type='submit' value='Создать'></form>\n"; |
break; |
case '2': |
// Правка существующего дистрибутива |
$dist =& $db->query("SELECT * FROM distribution WHERE dist_id='$uid'"); |
$dist->fetchInto($info, DB_FETCHMODE_ASSOC); |
$dtype =& $db->query("SELECT * FROM dtype"); |
$type = "<select name='distType'>"; |
while ($dtype->fetchInto($dtinfo, DB_FETCHMODE_ASSOC)) { |
if ($info["disttype"]==$dtinfo["type_id"]) { |
$type .= "<option value='".$dtinfo["type_id"]."' selected>".stripslashes($dtinfo["type"])."</option>"; |
} else { |
$type .= "<option value='".$dtinfo["type_id"]."'>".stripslashes($dtinfo["type"])."</option>"; |
} |
} |
$type .= "</select>\n"; |
$display = "<h3>Правка apt-дистрибутива <em>".stripslashes($info["distname"])."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='2'>\n"; |
$display .= "<input type='hidden' name='distID' value='$uid'>\n"; |
$display .= "Название дистрибутива: <input type='text' name='distName' value='".stripslashes($info["distname"])."'><br>\n"; |
$display .= "Тип дистрибутива: ".$type."<br>"; |
$display .= "<input type='submit' value='Править'></form>\n"; |
break; |
case '3': |
// Удаление существующего дистрибутива |
$dist =& $db->query("SELECT * FROM distribution WHERE dist_id='$uid'"); |
$dist->fetchInto($info, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление apt-дистрибутива <em>".stripslashes($info["distname"])."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='3'>\n"; |
$display .= "<input type='hidden' name='distID' value='$uid'>\n"; |
$display .= "<input type='submit' value='Удалить'></form>\n"; |
break; |
} |
break; |
case '2': |
// Работа с версиями дистрибутивов |
switch ($act) { |
case '0': |
// Все версии имеющихся дистрибутивов |
$dist =& $db->query("SELECT * FROM distribution d JOIN version v ON d.dist_id=v.dist_id ORDER BY d.dist_id,v.version ASC"); |
$display = "В наличии есть следующие версии apt-дистрибутивов:<ul id='distlist'>"; |
while ($dist->fetchInto($info, DB_FETCHMODE_ASSOC)) { |
$display .= "<li>".stripslashes($info["distname"])." ".stripslashes($info["version"])." “".stripslashes($info["vname"])."” — [<a href='./admin.php?mode=2&action=2&uid=".$info["version_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=2&action=3&uid=".$info["version_id"]."' class='delete'>удалить</a>]</li>"; |
} |
$display .= "</ul><p><a href='./admin.php?mode=2&action=1'>Добавить новую версию дистрибутива</a></p>"; |
break; |
case '1': |
// Добавление новой версии дистрибутива |
$dtype =& $db->query("SELECT * FROM distribution"); |
$type = "<select name='distName'>"; |
while ($dtype->fetchInto($dtinfo, DB_FETCHMODE_ASSOC)) { |
$type .= "<option value='".$dtinfo["dist_id"]."'>".stripslashes($dtinfo["distname"])."</option>"; |
} |
$type .= "</select>\n"; |
$display = "<h3>Добавление новой версии apt-дистрибутива</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='4'>\n"; |
$display .= "Номер версии: <input type='text' name='versNum'><br>\n"; |
$display .= "Название версии: <input type='text' name='versNam'><br>\n"; |
$display .= "Кодовое имя версии: <input type='text' name='versCN'><br>\n"; |
$display .= "Дистрибутив: ".$type."<br>"; |
$display .= "<input type='submit' value='Создать'></form>\n"; |
break; |
case '2': |
// Правка имеющейся версии дистрибутива |
$vers =& $db->query("SELECT * FROM version v JOIN distribution d ON d.dist_id=v.dist_id WHERE version_id='$uid'"); |
$vers->fetchInto($info, DB_FETCHMODE_ASSOC); |
$display = "<h3>Правка имеющейся версии <em>".stripslashes($info["distname"])."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='5'>\n"; |
$display .= "<input type='hidden' name='versID' value='$uid'>\n"; |
$display .= "Номер версии: <input type='text' name='versNum' value='".stripslashes($info["version"])."'><br>\n"; |
$display .= "Название версии: <input type='text' name='versNam' value='".stripslashes($info["vname"])."'><br>\n"; |
$display .= "Кодовое имя версии: <input type='text' name='versCN' value='".stripslashes($info["vcodename"])."'><br>\n"; |
$display .= "<input type='submit' value='Править'></form>\n"; |
break; |
case '3': |
// Удаление существующей версии дистрибутива |
$dist =& $db->query("SELECT * FROM version v JOIN distribution d ON v.dist_id=d.dist_id WHERE v.version_id='$uid'"); |
$dist->fetchInto($info, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление версии ".stripslashes($info["version"])." (“".stripslashes($info["vname"])."”) <em>".stripslashes($info["distname"])."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='6'>\n"; |
$display .= "<input type='hidden' name='versID' value='$uid'>\n"; |
$display .= "<input type='submit' value='Удалить'></form>\n"; |
break; |
} |
break; |
case '3': |
// Работа с репозиториями |
switch ($act) { |
case '0': |
// Выбор дистрибутива |
$dist =& $db->query("SELECT * FROM distribution d JOIN version v ON v.dist_id=d.dist_id"); |
$display = "В наличии есть следующие версии apt-дистрибутивов:<ul id='distlist'>"; |
while ($dist->fetchInto($info, DB_FETCHMODE_ASSOC)) { |
$display .= "<li><a href='./admin.php?mode=3&action=1&uid=".$info["version_id"]."'>".stripslashes($info["distname"])." ".stripslashes($info["version"])." “".stripslashes($info["vname"])."”</a></li>"; |
} |
$display .= "</ul>"; |
break; |
case '1': |
// Список доступных репозиториев для конкретной версии дистрибутива |
$reps =& $db->query("SELECT * FROM repository r JOIN ver2rep a ON a.rep_id=r.rep_id WHERE a.ver_id='$uid'"); |
$display = "Доступные репозитории для выбранного дистрибутива: <ul id='replist'>"; |
if ($reps->numRows()>0) { |
while ($reps->fetchInto($info, DB_FETCHMODE_ASSOC)) { |
$display .= "<li>[<a href='./admin.php?mode=3&action=3&uid=".$info["rep_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=3&action=4&uid=".$info["rep_id"]."' class='delete'>удалить</a>] ".stripslashes($info["repname"])." — ".stripslashes($info["repdescribe"])."</li>"; |
} |
} |
$display .= "</ul><p><a href='./admin.php?mode=3&action=2&uid=".$uid."'>Добавить новый репозиторий</a></p>"; |
break; |
case '2': |
// Новый репозиторий |
$rep =& $db->query("SELECT * FROM distribution d JOIN version v ON v.dist_id=d.dist_id WHERE v.version_id='$uid'"); |
$rep->fetchInto($dist, DB_FETCHMODE_ASSOC); |
$dist_id = $dist["dist_id"]; |
$dist_vname = stripslashes($dist["distname"])." ".stripslashes($dist["version"])." “".stripslashes($dist["vname"])."”"; |
$dtype =& $db->query("SELECT * FROM scheme"); |
$rscheme = "<select name='scheme'>"; |
while ($dtype->fetchInto($dtinfo, DB_FETCHMODE_ASSOC)) { |
$rscheme .= "<option value='".$dtinfo["scheme_id"]."'>".stripslashes($dtinfo["scheme"])."</option>"; |
} |
$rscheme .= "</select>"; |
$rtype =& $db->query("SELECT * FROM rtype"); |
$reptype = "<select name='rtype'>"; |
while ($rtype->fetchInto($rtinfo, DB_FETCHMODE_ASSOC)) { |
$reptype .= "<option value='".$rtinfo["rtype_id"]."'>".stripslashes($rtinfo["rtype"])."</option>"; |
} |
$reptype .= "</select>\n"; |
$sect =& $db->query("SELECT * FROM section s JOIN sect2dist d ON d.sect_id=s.sect_id WHERE d.dist_id='$dist_id'"); |
$list = ""; |
while ($sect->fetchInto($slist, DB_FETCHMODE_ASSOC)) { |
$list .= "<input type='checkbox' name='sect[]' value='".$slist["sect_id"]."'> <span title='".stripslashes($slist["sectinfo"])."'>".stripslashes($slist["sectname"])."</span> "; |
} |
$type .= "</select>\n"; |
$display = "<h3>Добавление нового репозитория для ".$dist_vname."</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='7'>\n"; |
$display .= "<input type='hidden' name='vers' value='$uid'>\n"; |
$display .= "Название репозитория (codename): <input type='text' name='repName'><br>\n"; |
$display .= "Описание репозитория:<br> <textarea name='repInfo'></textarea><br>\n"; |
$display .= "Схема репозитория: ".$rscheme."<br>"; |
$display .= "Тип репозитория: ".$reptype."<br>"; |
$display .= "Секции: ".$list; |
$display .= "<br><input type='submit' value='Создать'></form>\n"; |
break; |
case '3': |
// Редактирование репозитория |
$rep =& $db->query("SELECT * FROM repository WHERE rep_id='$uid'"); |
$rep->fetchInto($info, DB_FETCHMODE_ASSOC); |
$tlist = "<select name='scheme'>"; |
$sq =& $db->query("SELECT * FROM scheme"); |
while ($sq->fetchInto($type, DB_FETCHMODE_ASSOC)) { |
if ($type["scheme_id"]==$info["scheme_id"]) { |
$tlist .= "<option value='".$type["scheme_id"]."' selected>".stripslashes($type["scheme"])."</option>"; |
} else { |
$tlist .= "<option value='".$type["scheme_id"]."'>".stripslashes($type["scheme"])."</option>"; |
} |
} |
$tlist .= "</select>"; |
$tlist2 = "<select name='rtype'>"; |
$sq =& $db->query("SELECT * FROM rtype"); |
while ($sq->fetchInto($type, DB_FETCHMODE_ASSOC)) { |
if ($type["rtype_id"]==$info["rtype_id"]) { |
$tlist2 .= "<option value='".$type["rtype_id"]."' selected>".stripslashes($type["rtype"])."</option>"; |
} else { |
$tlist2 .= "<option value='".$type["rtype_id"]."'>".stripslashes($type["rtype"])."</option>"; |
} |
} |
$tlist2 .= "</select>"; |
$list = ""; |
$req =& $db->query("SELECT * FROM section s JOIN sect2rep r ON s.sect_id=r.sect_id WHERE r.rep_id='$uid'"); |
if ($req->numRows()>0) { |
while ($req->fetchInto($sect, DB_FETCHMODE_ASSOC)) { |
$list .= "<input type='checkbox' name='sect[]' value='".$sect["sect_id"]."' checked><span title='".stripslashes($sect["sectinfo"])."'>".stripslashes($sect["sectname"])."</span> "; |
} |
} |
$req =& $db->query("SELECT s.* FROM section s WHERE s.sect_id NOT IN (SELECT sect_id FROM sect2rep WHERE rep_id='$uid')"); |
if ($req->numRows()>0) { |
while ($req->fetchInto($sect, DB_FETCHMODE_ASSOC)) { |
$list .= "<input type='checkbox' name='sect[]' value='".$sect["sect_id"]."'><span title='".stripslashes($sect["sectinfo"])."'>".stripslashes($sect["sectname"])."</span> "; |
} |
} |
$display = "<h3>Правка репозитория ".$info["repname"]." для <em>".$dist_name."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='8'>\n"; |
$display .= "<input type='hidden' name='rep' value='$uid'>\n"; |
$display .= "Название репозитория (codename): <input type='text' name='repName' value='".stripslashes($info["repname"])."'><br>\n"; |
$display .= "Описание репозитория:<br> <textarea name='repInfo'>".stripslashes($info["repdescribe"])."</textarea><br>\n"; |
$display .= "Схема репозитория: ".$tlist."<br>"; |
$display .= "Тип репозитория: ".$tlist2."<br>"; |
$display .= "Секции: ".$list; |
$display .= "<br><input type='submit' value='Править'></form>\n"; |
break; |
case '4': |
// Удаление репозитория |
$rep =& $db->query("SELECT * FROM repository WHERE rep_id='$uid'"); |
$rep->fetchInto($info, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление репозитория ".$info["repname"]." для <em>".$dist_name."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='9'>\n"; |
$display .= "<input type='hidden' name='rep' value='$uid'>\n"; |
$display .= "<input type='submit' value='Удалить'></form>\n"; |
break; |
} |
break; |
case '4': |
// Управление разделами |
switch ($act) { |
case '0': |
// Список секций |
$req =& $db->query("SELECT * FROM section"); |
$display = "<p>Имеющиеся секции в репозиториях</p><ul class='sectlist'>"; |
while ($req->fetchInto($sect, DB_FETCHMODE_ASSOC)) { |
$sreq =& $db->query("SELECT * FROM distribution d JOIN sect2dist s ON s.dist_id=d.dist_id WHERE s.sect_id='".$sect["sect_id"]."'"); |
$replist = "<small>Используется в "; |
while ($sreq->fetchInto($rep, DB_FETCHMODE_ASSOC)) { |
$replist .= "<em>".stripslashes($rep["distname"])."</em>, "; |
} |
$replist = substr($replist, 0, -2); |
$replist .= "</small>"; |
$display .= "<li><strong>".stripslashes($sect["sectname"])."</strong> — [<a href='./admin.php?mode=4&action=2&uid=".$sect["sect_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=4&action=3&uid=".$sect["sect_id"]."' class='delete'>удалить</a>] — ".stripslashes($sect["sectinfo"])."<br>".$replist."</li>"; |
} |
$display .= "</ul><p><a href='./admin.php?mode=4&action=1'>Добавить секцию</a></p>"; |
break; |
case '1': |
$req =& $db->query("SELECT * FROM distribution"); |
while ($req->fetchInto($dist, DB_FETCHMODE_ASSOC)) { |
$list .= "<br><input type='checkbox' name='dist' value='".$dist["dist_id"]."'>".stripslashes($dist["distname"])." "; |
} |
$display = "<h3>Создание секции репозитория</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='10'>\n"; |
$display .= "Название секции (codename): <input type='text' name='sectName'><br>\n"; |
$display .= "Описание секции:<br> <textarea name='sectInfo'></textarea><br>\n"; |
$display .= "Используется в дистрибутивах: ".$list; |
$display .= "<br><input type='submit' value='Добавить'></form>\n"; |
break; |
case '2': |
$req =& $db->query("SELECT * FROM distribution d JOIN sect2dist s ON s.dist_id=d.dist_id WHERE s.sect_id='$uid'"); |
if ($req->numRows()>0) { |
while ($req->fetchInto($dist, DB_FETCHMODE_ASSOC)) { |
$list .= "<br><input type='checkbox' name='dist[]' value='".$dist["dist_id"]."' checked>".stripslashes($dist["distname"])." "; |
} |
} |
$req =& $db->query("SELECT d.* FROM distribution d WHERE dist_id NOT IN (SELECT dist_id FROM sect2dist WHERE sect_id='$uid')"); |
if ($req->numRows()>0) { |
while ($req->fetchInto($dist, DB_FETCHMODE_ASSOC)) { |
$list .= "<br><input type='checkbox' name='dist[]' value='".$dist["dist_id"]."'>".stripslashes($dist["distname"])." "; |
} |
} |
$req =& $db->query("SELECT * FROM section WHERE sect_id='$uid'"); |
$req->fetchInto($sect, DB_FETCHMODE_ASSOC); |
$display = "<h3>Правка секции репозитория</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='11'>\n"; |
$display .= "<input type='hidden' name='sectID' value='$uid'>\n"; |
$display .= "Название секции (codename): <input type='text' name='sectName' value='".stripslashes($sect["sectname"])."'><br>\n"; |
$display .= "Описание секции:<br> <textarea name='sectInfo'>".stripslashes($sect["sectinfo"])."</textarea><br>\n"; |
$display .= "Используется в дистрибутивах: ".$list; |
$display .= "<br><input type='submit' value='Править'></form>\n"; |
break; |
case '3': |
$req =& $db->query("SELECT * FROM section WHERE sect_id='$uid'"); |
$req->fetchInto($sect, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление секции <em>".stripslashes($sect["sectname"])."</em></h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='12'>\n"; |
$display .= "<input type='hidden' name='sectID' value='$uid'>\n"; |
$display .= "<br><input type='submit' value='Удалить'></form>\n"; |
break; |
} |
break; |
case '5': |
// Управление схемами репозиториев |
switch ($act) { |
case '0': |
// Список схем |
$req =& $db->query("SELECT * FROM scheme"); |
$display = "<p>Имеющиеся схемы репозиториев</p><ul class='sectlist'>"; |
while ($req->fetchInto($sect, DB_FETCHMODE_ASSOC)) { |
$display .= "<li>".stripslashes($sect["scheme"])." — [<a href='./admin.php?mode=5&action=2&uid=".$sect["scheme_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=5&action=3&uid=".$sect["scheme_id"]."' class='delete'>удалить</a>]</li>"; |
} |
$display .= "</ul><p><a href='./admin.php?mode=5&action=1'>Добавить новую схему</a></p>"; |
break; |
case '1': |
// Добавление новой схемы |
$display = "<h3>Создание схемы репозитория</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='13'>\n"; |
$display .= "Схема репозитория: <input type='text' name='scheme'><br>\n"; |
$display .= "<input type='submit' value='Добавить'></form>\n"; |
break; |
case '2': |
// Правка существующей схемы |
$req =& $db->query("SELECT * FROM scheme WHERE scheme_id='$uid'"); |
if ($req->numRows()>0) { |
$req->fetchInto($scheme, DB_FETCHMODE_ASSOC); |
$display = "<h3>Правка схемы репозитория</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='14'>\n"; |
$display .= "<input type='hidden' name='schemeID' value='".stripslashes($scheme["scheme_id"])."'><br>\n"; |
$display .= "Схема репозитория: <input type='text' name='scheme' value='".stripslashes($scheme["scheme"])."'><br>\n"; |
$display .= "<input type='submit' value='Править'></form>\n"; |
} else { |
$display = "Такой схемы репозитория не существует"; |
} |
break; |
case '3': |
// Удаление существующей схемы |
$req =& $db->query("SELECT * FROM scheme WHERE scheme_id='$uid'"); |
if ($req->numRows()>0) { |
$req->fetchInto($scheme, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление схемы репозитория</h3>"; |
$display .= "Удаляемая схема: ".stripslashes($scheme["scheme"])."<br>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='15'>\n"; |
$display .= "<input type='hidden' name='schemeID' value='".$scheme["scheme_id"]."'><br>\n"; |
$display .= "<input type='submit' value='Удалить'></form>\n"; |
} else { |
$display = "Такой схемы репозитория не существует"; |
} |
break; |
} |
break; |
case '6': |
// Управление настройками Ant |
switch ($act) { |
case '0': |
// Список настроек Ant |
$req =& $db->query("SELECT * FROM settings"); |
$display = "<p>Имеющиеся настройки Ant</p><ul class='sectlist'>"; |
if ($req->numRows()>0) { |
while ($req->fetchInto($setting, DB_FETCHMODE_ASSOC)) { |
$display .= "<li>Настройка: <em>".stripslashes($setting["opt"])."</em> Свойство: <em>".stripslashes($setting["optvalue"])."</em> [<a href='./admin.php?mode=6&action=2&uid=".$setting["opt_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=6&action=3&uid=".$setting["opt_id"]."' class='delete'>удалить</a>]</li>"; |
} |
} |
$display .= "</ul><p><a href='./admin.php?mode=6&action=1'>Добавить новую настройку</a></p>"; |
break; |
case '1': |
// Добавление новой настройки Ant |
$display = "<h3>Создание настройки Ant</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='16'>\n"; |
$display .= "Настройка (латиница, без пробелов): <input type='text' name='setoption'><br>\n"; |
$display .= "Свойство (значение) настройки: <input type='text' name='setvalue'><br>\n"; |
$display .= "<input type='submit' value='Добавить'></form>\n"; |
break; |
case '2': |
// Правка существующей настройки Ant |
$req =& $db->query("SELECT * FROM settings WHERE opt_id='$uid'"); |
if ($req->numRows()>0) { |
$req->fetchInto($setting, DB_FETCHMODE_ASSOC); |
$display = "<h3>Правка настройки Ant</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='17'>\n"; |
$display .= "<input type='hidden' name='optID' value='".stripslashes($setting["opt_id"])."'><br>\n"; |
$display .= "Настройка: <input type='text' name='setoption' value='".stripslashes($setting["opt"])."'><br>\n"; |
$display .= "Свойство: <input type='text' name='setvalue' value='".stripslashes($setting["optvalue"])."'><br>\n"; |
$display .= "<input type='submit' value='Править'></form>\n"; |
} else { |
$display = "Такой настройки не существует"; |
} |
break; |
case '3': |
// Удаление существующей настройки Ant |
$req =& $db->query("SELECT * FROM settings WHERE opt_id='$uid'"); |
if ($req->numRows()>0) { |
$req->fetchInto($setting, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление настройки Ant</h3>"; |
$display .= "Удаляемая настройка <em>".stripslashes($setting["opt"])."</em> с свойством <em>".stripslashes($setting["optvalue"])."</em><br>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='18'>\n"; |
$display .= "<input type='hidden' name='optID' value='".$setting["opt_id"]."'><br>\n"; |
$display .= "<input type='submit' value='Удалить'></form>\n"; |
} else { |
$display = "Такой настройки не существует"; |
} |
break; |
} |
break; |
case '7': |
// Управление типами репозиториев |
switch ($act) { |
case '0': |
// Список типов репозиториев |
$req =& $db->query("SELECT * FROM rtype"); |
$display = "<p>Имеющиеся типы репозиториев</p><ul class='sectlist'>"; |
if ($req->numRows()>0) { |
while ($req->fetchInto($setting, DB_FETCHMODE_ASSOC)) { |
$display .= "<li>".stripslashes($setting["rtype"])." [<a href='./admin.php?mode=7&action=2&uid=".$setting["rtype_id"]."' class='edit'>править</a>][<a href='./admin.php?mode=7&action=3&uid=".$setting["rtype_id"]."' class='delete'>удалить</a>]</li>"; |
} |
} |
$display .= "</ul><p><a href='./admin.php?mode=7&action=1'>Добавить новый тип репозитория</a></p>"; |
break; |
case '1': |
// Добавление нового типа репозитория |
$display = "<h3>Создание нового типа репозитория</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='19'>\n"; |
$display .= "Тип: <input type='text' name='rtype'><br>\n"; |
$display .= "<input type='submit' value='Добавить'></form>\n"; |
break; |
case '2': |
// Правка существующего типа репозитория |
$req =& $db->query("SELECT * FROM rtypes WHERE rtype_id='$uid'"); |
if ($req->numRows()>0) { |
$req->fetchInto($setting, DB_FETCHMODE_ASSOC); |
$display = "<h3>Правка типа репозитория</h3>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='20'>\n"; |
$display .= "<input type='hidden' name='rtypeID' value='".stripslashes($setting["rtype_id"])."'><br>\n"; |
$display .= "Тип: <input type='text' name='rtype' value='".stripslashes($setting["rtype"])."'><br>\n"; |
$display .= "<input type='submit' value='Править'></form>\n"; |
} else { |
$display = "Такого типа репозитория не существует"; |
} |
break; |
case '3': |
// Удаление существующего типа репозитория |
$req =& $db->query("SELECT * FROM rtypes WHERE rtype_id='$uid'"); |
if ($req->numRows()>0) { |
$req->fetchInto($setting, DB_FETCHMODE_ASSOC); |
$display = "<h3>Удаление существующего типа репозитория</h3>"; |
$display .= "Удаляемый тип <em>".stripslashes($setting["rtype"])."</em><br>"; |
$display .= "<form action='./process.php' method='POST'>\n"; |
$display .= "<input type='hidden' name='mode' value='21'>\n"; |
$display .= "<input type='hidden' name='rtypeID' value='".$setting["rtype_id"]."'><br>\n"; |
$display .= "<input type='submit' value='Удалить'></form>\n"; |
} else { |
$display = "Такого типа репозитория не существует"; |
} |
break; |
} |
break; |
} |
$smarty->assign('display',$display); |
$smarty->assign('antversion',$antversion); |
$smarty->display('admin.tpl'); |
?> |
/tags/0.1/oops.tpl |
---|
Новый файл |
0,0 → 1,8 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
<h2>Упс...</h2> |
<p>Во время авторизации возникли какие-то проблемы. Подозреваю, что Вы забыли пароль...</p> |
<p><a href='./signin.php'>Еще одну попытку входа?</a></p> |
{include file="footer.tpl"} |
/tags/0.1/sign-valid.php |
---|
Новый файл |
0,0 → 1,17 |
<?php |
include "lib/init.php"; |
$login = mysql_real_escape_string($_COOKIE[$CookieLogin]); |
$securepass = $_COOKIE[$CookiePasswd]; |
$res =& $db->query("SELECT * FROM owner WHERE login='$login' AND passwd='$securepass'"); |
if ($res->numRows()==0) { |
header("Location: ./signin.php"); |
$res->free(); |
exit; |
} |
?> |
/tags/0.1/signin.tpl |
---|
Новый файл |
0,0 → 1,11 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
<form action='./sign-check.php' method='POST'> |
<input type='hidden' name='sign' value='1'> |
Логин: <input type='text' name='signName'><br> |
Пароль: <input type='password' name='signPass'><br> |
<input type='submit'> |
</form> |
{include file="footer.tpl"} |
/tags/0.1/header.tpl |
---|
Новый файл |
0,0 → 1,10 |
<!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="ru" lang="ru"> |
<head> |
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
<title>{$title}</title> |
<link rel="stylesheet" type="text/css" href="./css/ant.css" /> |
</head> |
<body> |
/tags/0.1/admin.tpl |
---|
Новый файл |
0,0 → 1,7 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
{$display} |
<div id="footer">Ant {$antversion}</div> |
{include file="footer.tpl"} |
/tags/0.1/css/ant.css |
---|
Новый файл |
0,0 → 1,38 |
#ant { |
font: 12pt/20pt Georgia; |
} |
#ant input { |
margin: 0 5px 0 15px; |
font: 12pt Georgia; |
} |
#ant p { |
margin: 0; |
} |
#footer { |
margin: 5px 0; |
padding: 5px 0; |
border-top: 1px solid #a9a9a9; |
font: 10pt Georgia; |
color: #a9a9a9; |
} |
#footer a { |
color: #a9a9a9; |
text-decoration: none; |
} |
pre { |
font: 12pt Arial; |
border: 1px solid #000; |
margin: 10px 0; |
padding: 10px; |
background-color: #dcdcdc; |
} |
#sourceslist { |
font-family: Arial; |
padding: 1px 3px; |
} |
/tags/0.1/configs/ant.conf |
---|
Новый файл |
0,0 → 1,5 |
title = Welcome to Smarty! |
cutoff_size = 40 |
[setup] |
bold = true |
/tags/0.1/footer.tpl |
---|
Новый файл |
0,0 → 1,2 |
</body> |
</html> |
/tags/0.1/index.php |
---|
Новый файл |
0,0 → 1,78 |
<?php |
include "lib/init.php"; |
$status = abs(intval($_GET["step"])); |
$dist = abs(intval($_GET["d"])); |
$vers = abs(intval($_GET["v"])); |
$query =& $db->query("SELECT * FROM settings WHERE opt LIKE 'version'"); |
$query->fetchInto($antv, DB_FETCHMODE_ASSOC); |
$antversion = $antv["optvalue"]; |
$query =& $db->query("SELECT * FROM distribution"); |
while ($query->fetchInto($data, DB_FETCHMODE_ASSOC)) { |
$linux .= "<p><input type='radio' name='d' value='".$data["dist_id"]."' />".stripslashes($data["distname"])."</p>\n"; |
} |
if (!isset($status)) { $status = 0; }; |
if (isset($dist)) { |
$query =& $db->query("SELECT * FROM version v JOIN distribution d ON d.dist_id=v.dist_id WHERE v.dist_id='$dist'"); |
$distvers = "<p><input type='hidden' name='d' value='".$dist."' /></p>\n"; |
while ($query->fetchInto($version, DB_FETCHMODE_ASSOC)) { |
if ($version["vname"]!="") { |
$distname = "“".stripslashes($version["vname"])."”"; |
} else { |
$distname = ""; |
} |
$distvers .= "<p><input type='radio' name='v' value='".$version["version_id"]."' />".stripslashes($version["distname"])." ".stripslashes($version["version"])." ".$distname."</p>\n"; |
} |
} |
if (isset($vers)) { |
$query =& $db->query("SELECT * FROM settings"); |
$settings = array(); |
while ($query->fetchInto($setting, DB_FETCHMODE_ASSOC)) { |
$settings[stripslashes($setting["opt"])] = stripslashes($setting["optvalue"]); |
}; |
$query =& $db->query("SELECT * FROM version v JOIN distribution d ON d.dist_id=v.dist_id JOIN dtype p ON d.disttype=p.type_id WHERE v.dist_id='$dist' AND v.version_id='$vers'"); |
$query->fetchInto($infodist, DB_FETCHMODE_ASSOC); |
$distname = ""; |
if ($infodist["vname"]!="") { |
$distname = "“".stripslashes($infodist["vname"])."”"; |
} |
$info = "<h2>Доступные репозитории для <em>".stripslashes($infodist["distname"])." ".stripslashes($infodist["version"])." ".$distname."</em></h2>"; |
$query =& $db->query("SELECT * FROM repository r JOIN ver2rep v ON r.rep_id=v.rep_id JOIN version v2 ON v.ver_id=v2.version_id JOIN scheme s ON s.scheme_id=r.scheme_id WHERE v.ver_id='$vers' ORDER BY r.rtype_id, r.scheme_id ASC"); |
$result = "<p>Скопируйте эти строки в файл <span id='sourceslist'>/etc/apt/sources.list</span>:</p><pre>"; |
while ($query->fetchInto($resinfo, DB_FETCHMODE_ASSOC)) { |
$repscheme = stripslashes($resinfo["scheme"]); |
$querysect =& $db->query("SELECT * FROM section s JOIN sect2rep r ON s.sect_id=r.sect_id WHERE |
r.rep_id='$resinfo[rep_id]'"); |
$sections = ""; |
while ($querysect->fetchInto($section,DB_FETCHMODE_ASSOC)) { |
$sections .= stripslashes($section["sectname"])." "; |
} |
$repscheme = str_replace("{TYPE}",stripslashes($infodist["type"]),$repscheme); |
$repscheme = str_replace("{PROTO}",$settings["proto"],$repscheme); |
$repscheme = str_replace("{URL}",$settings["url"],$repscheme); |
$repscheme = str_replace("{REP}",stripslashes($resinfo["repname"]),$repscheme); |
$repscheme = str_replace("{DIST}",stripslashes($infodist["vcodename"]),$repscheme); |
$repscheme = str_replace("{SECT}",$sections,$repscheme); |
$result .= $repscheme."\n"; |
} |
$result .= "</pre>"; |
$result = $info.$result; |
} |
$smarty->assign('status',$status); |
$smarty->assign('linux',$linux); |
$smarty->assign('version',$distvers); |
$smarty->assign('result',$result); |
$smarty->assign('antversion',$antversion); |
$smarty->display('index.tpl'); |
?> |
/tags/0.1/templates/footer.tpl |
---|
Новый файл |
0,0 → 1,2 |
</body> |
</html> |
/tags/0.1/templates/oops.tpl |
---|
Новый файл |
0,0 → 1,8 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
<h2>Упс...</h2> |
<p>Во время авторизации возникли какие-то проблемы. Подозреваю, что Вы забыли пароль...</p> |
<p><a href='./signin.php'>Еще одну попытку входа?</a></p> |
{include file="footer.tpl"} |
/tags/0.1/templates/index.tpl |
---|
Новый файл |
0,0 → 1,30 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
<div id='ant'> |
{if $status == 0} |
<h2>Выбор дистрибутива</h2> |
<form action='./index.php' method='get'> |
<p><input type='hidden' name='step' value='1' /></p> |
{$linux} |
<p><input type='submit' value=' Выбрать дистрибутив ' /></p> |
</form> |
{/if} |
{if $status == 1} |
<h2>Выбор версии дистрибутива</h2> |
<form action='./index.php' method='get'> |
<p><input type='hidden' name='step' value='2' /></p> |
{$version} |
<p><input type='submit' value=' Получить sources.list ' /></p> |
</form> |
{/if} |
{if $status == 2} |
{$result} |
{/if} |
</div> |
<div id='footer'><a href="http://track.altlug.ru/projects/show/ant">Ant {$antversion}</a></div> |
{include file="footer.tpl"} |
/tags/0.1/templates/signin.tpl |
---|
Новый файл |
0,0 → 1,11 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
<form action='./sign-check.php' method='POST'> |
<input type='hidden' name='sign' value='1'> |
Логин: <input type='text' name='signName'><br> |
Пароль: <input type='password' name='signPass'><br> |
<input type='submit'> |
</form> |
{include file="footer.tpl"} |
/tags/0.1/templates/admin.tpl |
---|
Новый файл |
0,0 → 1,7 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
{$display} |
<div id="footer">Ant {$antversion}</div> |
{include file="footer.tpl"} |
/tags/0.1/templates/header.tpl |
---|
Новый файл |
0,0 → 1,10 |
<!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="ru" lang="ru"> |
<head> |
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> |
<title>{$title}</title> |
<link rel="stylesheet" type="text/css" href="./css/ant.css" /> |
</head> |
<body> |
/tags/0.1/sql/ant.sql |
---|
Новый файл |
0,0 → 1,634 |
-- phpMyAdmin SQL Dump |
-- version 3.0.0-alpha |
-- http://www.phpmyadmin.net |
-- |
-- Хост: localhost |
-- Время создания: Мар 09 2009 г., 17:26 |
-- Версия сервера: 5.0.51 |
-- Версия PHP: 5.2.6-1+lenny2 |
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; |
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; |
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; |
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; |
/*!40101 SET NAMES utf8 */; |
-- |
-- База данных: `ant` |
-- |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `arch` |
-- |
CREATE TABLE IF NOT EXISTS `arch` ( |
`arch_id` int(2) NOT NULL auto_increment, |
`arch` varchar(10) default NULL, |
PRIMARY KEY (`arch_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; |
-- |
-- Дамп данных таблицы `arch` |
-- |
INSERT INTO `arch` (`arch_id`, `arch`) VALUES |
(1, 'i386'), |
(2, 'amd64'); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `arch2rep` |
-- |
CREATE TABLE IF NOT EXISTS `arch2rep` ( |
`id` int(11) NOT NULL auto_increment, |
`arch_id` int(2) default NULL, |
`rep_id` int(5) default NULL, |
PRIMARY KEY (`id`), |
KEY `arch_id` (`arch_id`), |
KEY `rep_id` (`rep_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; |
-- |
-- Дамп данных таблицы `arch2rep` |
-- |
INSERT INTO `arch2rep` (`id`, `arch_id`, `rep_id`) VALUES |
(1, 1, 1), |
(2, 1, 2), |
(3, 2, 2); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `distribution` |
-- |
CREATE TABLE IF NOT EXISTS `distribution` ( |
`dist_id` int(5) NOT NULL auto_increment, |
`distname` varchar(25) default NULL, |
`disttype` int(1) NOT NULL, |
PRIMARY KEY (`dist_id`), |
KEY `disttype` (`disttype`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ; |
-- |
-- Дамп данных таблицы `distribution` |
-- |
INSERT INTO `distribution` (`dist_id`, `distname`, `disttype`) VALUES |
(1, 'Debian GNU/Linux', 1), |
(2, 'Ubuntu Linux', 1), |
(3, 'InfraLinux', 1); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `dtype` |
-- |
CREATE TABLE IF NOT EXISTS `dtype` ( |
`type_id` int(1) NOT NULL auto_increment, |
`type` char(3) character set utf8 NOT NULL, |
PRIMARY KEY (`type_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=3 ; |
-- |
-- Дамп данных таблицы `dtype` |
-- |
INSERT INTO `dtype` (`type_id`, `type`) VALUES |
(1, 'deb'), |
(2, 'rpm'); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `owner` |
-- |
CREATE TABLE IF NOT EXISTS `owner` ( |
`id` int(11) NOT NULL auto_increment, |
`login` char(32) default NULL, |
`passwd` char(32) default NULL, |
PRIMARY KEY (`id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; |
-- |
-- Дамп данных таблицы `owner` |
-- |
INSERT INTO `owner` (`id`, `login`, `passwd`) VALUES |
(1, 'admin', 'b167f5e9e5794a7e1eaca776fed7afb9'); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `repository` |
-- |
CREATE TABLE IF NOT EXISTS `repository` ( |
`rep_id` int(5) NOT NULL auto_increment, |
`repname` varchar(20) default NULL, |
`repdescribe` text, |
`scheme_id` int(2) NOT NULL, |
`rtype_id` int(2) NOT NULL, |
PRIMARY KEY (`rep_id`), |
KEY `scheme` (`scheme_id`), |
KEY `rtype_id` (`rtype_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=50 ; |
-- |
-- Дамп данных таблицы `repository` |
-- |
INSERT INTO `repository` (`rep_id`, `repname`, `repdescribe`, `scheme_id`, `rtype_id`) VALUES |
(1, 'sarge', 'Базовый репозиторий', 4, 1), |
(2, 'sarge-backports', 'Бэкпорты для Sarge', 9, 2), |
(3, 'etch', 'Базовый репозиторий', 4, 1), |
(4, 'etch-updates', 'Обновления безопасности', 6, 2), |
(5, 'etch-backports', 'Бэкпорты для Etch', 9, 2), |
(6, 'etch-opera', 'Репозиторий с браузером Opera', 4, 3), |
(7, 'etch-virtualbox', 'Репозиторий с VirtualBox', 4, 3), |
(8, 'etch-winehq', 'Репозиторий с wine', 4, 3), |
(9, 'lenny', 'Базовый репозиторий', 4, 1), |
(10, 'lenny-2gis', 'Репозиторий с 2GIS', 4, 3), |
(11, 'lenny-opera', 'Репозиторий с браузером Opera', 4, 3), |
(12, 'lenny-updates', 'Обновления безопасности', 6, 2), |
(13, 'lenny-virtualbox', 'Репозиторий с VirtualBox', 4, 3), |
(14, 'hardy', 'Базовый репозиторий', 4, 1), |
(15, 'hardy-commercial', 'Репозиторий с коммерческим ПО', 4, 2), |
(16, 'hardy', 'Обновления безопасности', 11, 2), |
(17, 'hardy', 'Обновления', 10, 2), |
(18, 'ubuntu-2gis', 'Репозиторий с 2GIS', 4, 3), |
(19, 'ubuntu-freenx', 'Репозиторий с FreeNX', 4, 3), |
(20, 'ubuntu-playonlinux', 'Репозиторий с играми', 4, 3), |
(35, 'intrepid', 'Обновления безопасности', 11, 2), |
(21, 'ubuntu-virtualbox', 'Репозиторий с VirtualBox', 4, 3), |
(22, 'ubuntu-winehq', 'Репозиторий с Wine', 4, 3), |
(23, 'intrepid', 'Бэкпорты для Intrepid Ibex', 9, 2), |
(24, 'hardy', 'Бэкпорты для Hardy Heron', 9, 2), |
(25, 'intrepid', 'Базовый репозиторий', 4, 1), |
(26, 'intrepid', 'Обновления безопасности', 11, 2), |
(27, 'intrepid', 'Обновления', 10, 2), |
(28, 'intrepid-commercial', 'Репозиторий с коммерческим ПО', 4, 2), |
(34, 'intrepid', 'Базовый репозиторий Ubuntu', 4, 1), |
(29, 'kubuntu-experimental', 'Экспериментальный репозиторий с KDE 4', 4, 3), |
(30, 'ubuntu-playonlinux', 'Репозиторий с играми', 4, 3), |
(33, 'infralinux', 'Базовый репозиторий', 4, 1), |
(31, 'ubuntu-virtualbox', 'Репозиторий с VirtualBox', 4, 3), |
(32, 'ubuntu-winehq', 'Репозиторий с Wine', 4, 3), |
(36, 'intrepid', 'Обновления', 10, 2), |
(37, 'intrepid', 'Бэкпорты для Intrepid Ibex', 9, 2), |
(38, 'intrepid-commercial', 'Коммерческое ПО', 4, 2), |
(39, 'kubuntu-experimental', 'Экспериментальный репозиторий с KDE 4', 4, 3), |
(40, 'ubuntu-playonlinux', 'Репозиторий с играми', 4, 0), |
(41, 'ubuntu-virtualbox', 'Репозиторий с VirtualBox', 4, 3), |
(42, 'ubuntu-winehq', 'Репозиторий с wine', 4, 3), |
(43, 'etch-multimedia', 'Мультимедийный репозиторий для Etch', 4, 3), |
(44, 'lenny-multimedia', 'Мультимедийный репозиторий для Lenny', 4, 3), |
(45, 'etch', 'Обновления для Etch', 5, 2), |
(46, 'lenny', 'Обновления для Lenny', 5, 2), |
(47, 'lenny-volatile', 'Обновления для Lenny', 7, 2), |
(48, 'lenny-volatile', 'Обновления для Lenny', 8, 2); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `rtype` |
-- |
CREATE TABLE IF NOT EXISTS `rtype` ( |
`rtype_id` int(2) NOT NULL auto_increment, |
`rtype` varchar(25) NOT NULL, |
PRIMARY KEY (`rtype_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; |
-- |
-- Дамп данных таблицы `rtype` |
-- |
INSERT INTO `rtype` (`rtype_id`, `rtype`) VALUES |
(1, 'Базовый'), |
(2, 'Дополнительный'), |
(3, 'Extra (добавочный)'); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `scheme` |
-- |
CREATE TABLE IF NOT EXISTS `scheme` ( |
`scheme_id` int(2) NOT NULL auto_increment, |
`scheme` varchar(200) NOT NULL, |
PRIMARY KEY (`scheme_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=12 ; |
-- |
-- Дамп данных таблицы `scheme` |
-- |
INSERT INTO `scheme` (`scheme_id`, `scheme`) VALUES |
(4, '{TYPE} {PROTO}{URL}/{REP} {DIST} {SECT}'), |
(5, '{TYPE} {PROTO}{URL}/{REP} {DIST}-proposed-updates {SECT}'), |
(6, '{TYPE} {PROTO}{URL}/{REP} {DIST}/updates {SECT}'), |
(7, '{TYPE} {PROTO}{URL}/{REP} {DIST}/volatile {SECT}'), |
(8, '{TYPE} {PROTO}{URL}/{REP} {DIST}/volatile-sloppy {SECT}'), |
(9, '{TYPE} {PROTO}{URL}/{REP} {DIST}-backports {SECT}'), |
(10, '{TYPE} {PROTO}{URL}/{REP} {DIST}-updates {SECT}'), |
(11, '{TYPE} {PROTO}{URL}/{REP} {DIST}-security {SECT}'); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `sect2dist` |
-- |
CREATE TABLE IF NOT EXISTS `sect2dist` ( |
`id` int(10) NOT NULL auto_increment, |
`sect_id` int(3) NOT NULL, |
`dist_id` int(5) NOT NULL, |
PRIMARY KEY (`id`), |
KEY `sect_id` (`sect_id`,`dist_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ; |
-- |
-- Дамп данных таблицы `sect2dist` |
-- |
INSERT INTO `sect2dist` (`id`, `sect_id`, `dist_id`) VALUES |
(11, 0, 2), |
(2, 2, 1), |
(25, 3, 2), |
(10, 0, 1), |
(16, 4, 2), |
(18, 5, 2), |
(20, 6, 2), |
(22, 7, 2), |
(24, 3, 1), |
(12, 0, 3), |
(13, 1, 1), |
(14, 1, 2), |
(15, 1, 3), |
(17, 4, 3), |
(19, 5, 3), |
(21, 6, 3), |
(23, 7, 3), |
(26, 3, 3); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `sect2rep` |
-- |
CREATE TABLE IF NOT EXISTS `sect2rep` ( |
`id` int(10) NOT NULL auto_increment, |
`sect_id` int(3) NOT NULL, |
`rep_id` int(5) NOT NULL, |
PRIMARY KEY (`id`), |
KEY `sect_id` (`sect_id`,`rep_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=475 ; |
-- |
-- Дамп данных таблицы `sect2rep` |
-- |
INSERT INTO `sect2rep` (`id`, `sect_id`, `rep_id`) VALUES |
(74, 3, 0), |
(73, 2, 0), |
(72, 1, 0), |
(77, 3, 0), |
(76, 2, 0), |
(75, 1, 0), |
(80, 3, 0), |
(79, 2, 0), |
(78, 1, 0), |
(83, 3, 0), |
(82, 2, 0), |
(81, 1, 0), |
(86, 3, 0), |
(85, 2, 0), |
(84, 1, 0), |
(87, 3, 0), |
(88, 3, 0), |
(89, 1, 0), |
(92, 3, 0), |
(91, 2, 0), |
(90, 1, 0), |
(93, 3, 0), |
(94, 3, 0), |
(97, 3, 0), |
(96, 2, 0), |
(95, 1, 0), |
(98, 3, 0), |
(102, 6, 0), |
(101, 5, 0), |
(100, 4, 0), |
(99, 1, 0), |
(103, 7, 0), |
(107, 6, 0), |
(106, 5, 0), |
(105, 4, 0), |
(104, 1, 0), |
(111, 6, 0), |
(110, 5, 0), |
(109, 4, 0), |
(108, 1, 0), |
(112, 3, 0), |
(113, 1, 0), |
(114, 1, 0), |
(115, 3, 0), |
(116, 1, 0), |
(124, 6, 0), |
(123, 5, 0), |
(122, 4, 0), |
(121, 1, 0), |
(120, 6, 0), |
(119, 5, 0), |
(118, 4, 0), |
(117, 1, 0), |
(128, 6, 0), |
(127, 5, 0), |
(126, 4, 0), |
(125, 1, 0), |
(132, 6, 0), |
(131, 5, 0), |
(130, 4, 0), |
(129, 1, 0), |
(136, 6, 0), |
(135, 5, 0), |
(134, 4, 0), |
(133, 1, 0), |
(137, 7, 0), |
(138, 1, 0), |
(139, 1, 0), |
(140, 3, 0), |
(71, 1, 0), |
(454, 6, 33), |
(453, 5, 33), |
(452, 4, 33), |
(451, 1, 33), |
(458, 6, 34), |
(457, 5, 34), |
(456, 4, 34), |
(455, 1, 34), |
(462, 6, 35), |
(461, 5, 35), |
(460, 4, 35), |
(459, 1, 35), |
(466, 6, 36), |
(465, 5, 36), |
(464, 4, 36), |
(463, 1, 36), |
(470, 6, 37), |
(469, 5, 37), |
(468, 4, 37), |
(467, 1, 37), |
(161, 1, 0), |
(162, 4, 0), |
(163, 5, 0), |
(164, 6, 0), |
(165, 1, 0), |
(166, 2, 0), |
(167, 3, 0), |
(367, 3, 1), |
(366, 2, 1), |
(365, 1, 1), |
(370, 3, 2), |
(369, 2, 2), |
(368, 1, 2), |
(373, 3, 3), |
(372, 2, 3), |
(371, 1, 3), |
(377, 3, 4), |
(376, 2, 4), |
(375, 1, 4), |
(380, 3, 5), |
(379, 2, 5), |
(378, 1, 5), |
(384, 3, 6), |
(385, 3, 7), |
(386, 1, 8), |
(391, 3, 9), |
(390, 2, 9), |
(389, 1, 9), |
(404, 3, 10), |
(405, 3, 11), |
(394, 3, 12), |
(393, 2, 12), |
(392, 1, 12), |
(406, 3, 13), |
(411, 6, 14), |
(410, 5, 14), |
(409, 4, 14), |
(408, 1, 14), |
(412, 7, 15), |
(416, 6, 16), |
(415, 5, 16), |
(414, 4, 16), |
(413, 1, 16), |
(420, 6, 17), |
(419, 5, 17), |
(418, 4, 17), |
(417, 1, 17), |
(425, 3, 18), |
(426, 1, 19), |
(427, 1, 20), |
(428, 3, 21), |
(429, 1, 22), |
(424, 6, 24), |
(423, 5, 24), |
(422, 4, 24), |
(421, 1, 24), |
(433, 6, 23), |
(432, 5, 23), |
(431, 4, 23), |
(430, 1, 23), |
(437, 6, 25), |
(436, 5, 25), |
(435, 4, 25), |
(434, 1, 25), |
(441, 6, 26), |
(440, 5, 26), |
(439, 4, 26), |
(438, 1, 26), |
(445, 6, 27), |
(444, 5, 27), |
(443, 4, 27), |
(442, 1, 27), |
(446, 7, 28), |
(447, 1, 29), |
(448, 1, 30), |
(449, 3, 31), |
(450, 1, 32), |
(471, 7, 38), |
(472, 1, 39), |
(343, 1, 40), |
(473, 3, 41), |
(474, 1, 42), |
(387, 1, 43), |
(407, 1, 44), |
(383, 3, 45), |
(382, 2, 45), |
(381, 1, 45), |
(397, 3, 46), |
(396, 2, 46), |
(395, 1, 46), |
(400, 3, 47), |
(399, 2, 47), |
(398, 1, 47), |
(403, 3, 48), |
(402, 2, 48), |
(401, 1, 48); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `section` |
-- |
CREATE TABLE IF NOT EXISTS `section` ( |
`sect_id` int(3) NOT NULL auto_increment, |
`sectname` varchar(25) NOT NULL, |
`sectinfo` text NOT NULL, |
PRIMARY KEY (`sect_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ; |
-- |
-- Дамп данных таблицы `section` |
-- |
INSERT INTO `section` (`sect_id`, `sectname`, `sectinfo`) VALUES |
(1, 'main', 'Основной раздел, в котором собраны пакеты ПО только под свободными лицензиями.'), |
(4, 'restricted', ''), |
(5, 'universe', ''), |
(2, 'contrib', 'Пакеты в этой части распространяются владельцем авторских прав на условиях свободной лицензии, но зависят от несвободного программного обеспечения.'), |
(6, 'multiverse', ''), |
(3, 'non-free', 'Лицензии пакетов в этой части содержат условия, ограничивающие использование или распространение ПО'), |
(7, 'partner', ''); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `settings` |
-- |
CREATE TABLE IF NOT EXISTS `settings` ( |
`opt_id` int(2) NOT NULL auto_increment, |
`opt` varchar(50) NOT NULL, |
`optvalue` varchar(200) NOT NULL, |
PRIMARY KEY (`opt_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ; |
-- |
-- Дамп данных таблицы `settings` |
-- |
INSERT INTO `settings` (`opt_id`, `opt`, `optvalue`) VALUES |
(1, 'proto', 'http://'), |
(2, 'url', 'apt.nix-files.org.ru'), |
(3, 'version', '0.1RC2'); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `ver2rep` |
-- |
CREATE TABLE IF NOT EXISTS `ver2rep` ( |
`id` int(11) NOT NULL auto_increment, |
`ver_id` int(5) default NULL, |
`rep_id` int(5) default NULL, |
PRIMARY KEY (`id`), |
KEY `ver_id` (`ver_id`), |
KEY `rep_id` (`rep_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=50 ; |
-- |
-- Дамп данных таблицы `ver2rep` |
-- |
INSERT INTO `ver2rep` (`id`, `ver_id`, `rep_id`) VALUES |
(1, 1, 1), |
(2, 1, 2), |
(3, 2, 3), |
(4, 2, 4), |
(5, 2, 5), |
(6, 2, 6), |
(7, 2, 7), |
(8, 2, 8), |
(9, 3, 9), |
(10, 3, 10), |
(11, 3, 11), |
(12, 3, 12), |
(13, 3, 13), |
(14, 4, 14), |
(15, 4, 15), |
(16, 4, 16), |
(17, 4, 17), |
(18, 4, 18), |
(19, 4, 19), |
(20, 4, 20), |
(21, 4, 21), |
(22, 4, 22), |
(23, 5, 23), |
(24, 4, 24), |
(25, 5, 25), |
(26, 5, 26), |
(27, 5, 27), |
(28, 5, 28), |
(29, 5, 29), |
(30, 5, 30), |
(31, 5, 31), |
(32, 5, 32), |
(33, 6, 33), |
(34, 6, 34), |
(35, 6, 35), |
(36, 6, 36), |
(37, 6, 37), |
(38, 6, 38), |
(39, 6, 39), |
(40, 6, 40), |
(41, 6, 41), |
(42, 6, 42), |
(43, 2, 43), |
(44, 3, 44), |
(45, 2, 45), |
(46, 3, 46), |
(47, 3, 47), |
(48, 3, 48); |
-- -------------------------------------------------------- |
-- |
-- Структура таблицы `version` |
-- |
CREATE TABLE IF NOT EXISTS `version` ( |
`version_id` int(5) NOT NULL auto_increment, |
`dist_id` int(5) default NULL, |
`vname` varchar(25) default NULL, |
`version` varchar(10) NOT NULL, |
`vcodename` varchar(10) default NULL, |
PRIMARY KEY (`version_id`), |
KEY `dist_id` (`dist_id`) |
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ; |
-- |
-- Дамп данных таблицы `version` |
-- |
INSERT INTO `version` (`version_id`, `dist_id`, `vname`, `version`, `vcodename`) VALUES |
(1, 1, 'Sarge', '3.1', 'sarge'), |
(2, 1, 'Etch', '4.0', 'etch'), |
(3, 1, 'Lenny', '5.0', 'lenny'), |
(4, 2, 'Hardy Heron', '8.04', 'hardy'), |
(5, 2, 'Intrepid Ibex', '8.10', 'intrepid'), |
(6, 3, 'Intrepid Ibex', '8.10', 'intrepid'); |
/tags/0.1/sign-check.php |
---|
Новый файл |
0,0 → 1,26 |
<? |
include "lib/init.php"; |
$auth = mysql_real_escape_string($_POST["signName"]); |
$pass = mysql_real_escape_string($_POST["signPass"]); |
$securepass = md5($pass."ANT"); |
$query = "SELECT * FROM owner WHERE login='$auth' AND passwd='".$securepass."'"; |
$res =& $db->query($query); |
if ($res->numRows()!=0) { |
setcookie($CookieLogin, $auth); |
setcookie($CookiePasswd, $securepass); |
header("Location: ./admin.php\n\n"); |
$res->free(); |
exit; |
} else { |
header("Location: ./oops.php\n\n"); |
} |
$db->disconnect(); |
?> |
/tags/0.1/process.php |
---|
Новый файл |
0,0 → 1,217 |
<?php |
include "./sign-valid.php"; |
$mode = abs(intval($_POST["mode"])); |
$go = "./admin.php"; |
switch ($mode) { |
case '0': |
break; |
case '1': |
// Добавление нового дистрибутива |
$distname = mysql_real_escape_string($_POST["distName"]); |
$disttype = abs(intval($_POST["distType"])); |
$res =& $db->query("INSERT INTO distribution SET distname='$distname', disttype='$disttype'"); |
break; |
case '2': |
// Правка существующего дистрибутива |
$distname = mysql_real_escape_string($_POST["distName"]); |
$disttype = abs(intval($_POST["distType"])); |
$distID = abs(intval($_POST["distID"])); |
$res =& $db->query("UPDATE distribution SET distname='$distname', disttype='$disttype' WHERE dist_id='$distID'"); |
break; |
case '3': |
// Удаление существующего дистрибутива |
$distID = abs(intval($_POST["distID"])); |
$res =& $db->query("DELETE FROM distribution WHERE dist_id='$distID'"); |
$res =& $db->query("DELETE FROM sect2dist WHERE dist_id='$distID'"); |
break; |
case '4': |
// Добавление новой версии дистрибутива |
$versname = mysql_real_escape_string($_POST["versNam"]); |
$versnumb = mysql_real_escape_string($_POST["versNum"]); |
$verscode = mysql_real_escape_string($_POST["versCN"]); |
$distname = abs(intval($_POST["distName"])); |
$res =& $db->query("INSERT INTO version SET dist_id='$distname', vname='$versname', version='$versnumb', vcodename='$verscode'"); |
break; |
case '5': |
// Правка имеющейся версии дистрибутива |
$versname = mysql_real_escape_string($_POST["versNam"]); |
$versnumb = mysql_real_escape_string($_POST["versNum"]); |
$verscode = mysql_real_escape_string($_POST["versCN"]); |
$distname = abs(intval($_POST["distName"])); |
$versID = abs(intval($_POST["versID"])); |
$res =& $db->query("UPDATE version SET dist_id='$distname', vname='$versname', version='$versnumb', vcodename='$verscode' WHERE version_id='$versID'"); |
break; |
case '6': |
// Удаление существующей версии дистрибутива |
$versID = abs(intval($_POST["versID"])); |
$res =& $db->query("DELETE FROM version WHERE version_id='$versID'"); |
$res =& $db->query("DELETE FROM ver2rep WHERE ver_id='$versID'"); |
break; |
case '7': |
// Добавление нового репозитория |
$versID = abs(intval($_POST["vers"])); |
$repname = mysql_real_escape_string($_POST["repName"]); |
$repinfo = mysql_real_escape_string($_POST["repInfo"]); |
$repsche = abs(intval($_POST["scheme"])); |
$reptype = abs(intval($_POST["rtype"])); |
$res =& $db->query("INSERT INTO repository SET repname='$repname', repdescribe='$repinfo', scheme_id='$repsche', rtype_id='$reptype'"); |
$res =& $db->query("SELECT rep_id FROM repository ORDER BY rep_id DESC LIMIT 1"); |
$res->fetchInto($rep, DB_FETCHMODE_ASSOC); |
$rep_id = $rep["rep_id"]; |
$res =& $db->query("INSERT INTO ver2rep SET ver_id='$versID', rep_id='$rep_id'"); |
for ($i=0;$i<count($_POST["sect"]);$i++) { |
$res =& $db->query("INSERT INTO sect2rep SET sect_id='".$_POST["sect"][$i]."', rep_id='$rep_id'"); |
} |
break; |
case '8': |
// Правка репозитория |
$repID = abs(intval($_POST["rep"])); |
$repname = mysql_real_escape_string($_POST["repName"]); |
$repinfo = mysql_real_escape_string($_POST["repInfo"]); |
$repsche = abs(intval($_POST["scheme"])); |
$reptype = abs(intval($_POST["rtype"])); |
$res =& $db->query("UPDATE repository SET repname='$repname', repdescribe='$repinfo', scheme_id='$repsche', rtype_id='$reptype' WHERE rep_id='$repID'"); |
$res =& $db->query("DELETE FROM sect2rep WHERE rep_id='$repID'"); |
for ($i=0;$i<count($_POST["sect"]);$i++) { |
$res =& $db->query("INSERT INTO sect2rep SET sect_id='".$_POST["sect"][$i]."', rep_id='$repID'"); |
} |
break; |
case '9': |
// Удаление репозитория |
$repID = abs(intval($_POST["rep"])); |
$res =& $db->query("DELETE FROM repository WHERE rep_id='$repID'"); |
$res =& $db->query("DELETE FROM sect2rep WHERE rep_id='$repID'"); |
$res =& $db->query("DELETE FROM ver2rep WHERE rep_id='$repID'"); |
break; |
case '10': |
// Создание секции |
$sectname = mysql_real_escape_string($_POST["sectName"]); |
$sectinfo = mysql_real_escape_string($_POST["sectInfo"]); |
$req =& $db->query("INSERT INTO section SET sectname='$sectname', sectinfo='$sectinfo'"); |
$req =& $db->query("SELECT sect_id FROM section ORDER BY sect_id DESC LIMIT 1"); |
$req->fetchInto($sect, DB_FETCHMODE_ASSOC); |
for($i=0;$i<count($_POST["dist"]);$i++) { |
$req =& $db->query("INSERT INTO sect2dist SET dist_id='".$_POST["dist"][$i]."', sect_id='".$sect["sect_id"]."'"); |
} |
break; |
case '11': |
// Правка секции |
$sectID = abs(intval($_POST["sectID"])); |
$sectname = mysql_real_escape_string($_POST["sectName"]); |
$sectinfo = mysql_real_escape_string($_POST["sectInfo"]); |
$req =& $db->query("UPDATE section SET sectname='$sectname', sectinfo='$sectinfo' WHERE sect_id='$sectID'"); |
$req =& $db->query("DELETE FROM sect2dist WHERE sect_id='$sectID'"); |
for($i=0;$i<count($_POST["dist"]);$i++) { |
$req =& $db->query("INSERT INTO sect2dist SET dist_id='".$_POST["dist"][$i]."', sect_id='".$sectID."'"); |
} |
break; |
case '12': |
// Удаление секции |
$sectID = abs(intval($_POST["sectID"])); |
$req =& $db->query("DELETE FROM section WHERE sect_id='$sectID'"); |
$req =& $db->query("DELETE FROM sect2dist WHERE sect_id='$sectID'"); |
$req =& $db->query("DELETE FROM sect2rep WHERE sect_id='$sectID'"); |
break; |
case '13': |
// Добавление новой схемы |
$scheme = mysql_real_escape_string($_POST["scheme"]); |
$req =& $db->query("INSERT INTO scheme SET scheme='$scheme'"); |
break; |
case '14': |
// Правка схемы |
$schemeID = abs(intval($_POST["schemeID"])); |
$scheme = mysql_real_escape_string($_POST["scheme"]); |
$req =& $db->query("UPDATE scheme SET scheme='$scheme' WHERE scheme_id='$schemeID'"); |
break; |
case '15': |
// Удаление схемы |
$schemeID = abs(intval($_POST["schemeID"])); |
$req =& $db->query("DELETE FROM scheme WHERE scheme_id='$schemeID'"); |
break; |
case '16': |
// Добавление новой настройки Ant |
$option = mysql_real_escape_string($_POST["setoption"]); |
$value = mysql_real_escape_string($_POST["setvalue"]); |
$req =& $db->query("INSERT INTO settings SET opt='$option', optvalue='$value'"); |
break; |
case '17': |
// Правка настройки Ant |
$optID = abs(intval($_POST["optID"])); |
$option = mysql_real_escape_string($_POST["setoption"]); |
$value = mysql_real_escape_string($_POST["setvalue"]); |
$req =& $db->query("UPDATE settings SET opt='$option', optvalue='$value' WHERE opt_id='$optID'"); |
break; |
case '18': |
// Удаление настройки |
$optID = abs(intval($_POST["optID"])); |
$req =& $db->query("DELETE FROM settings WHERE opt_id='$optID'"); |
break; |
case '19': |
// Добавление нового типа репозитория |
$rtype = mysql_real_escape_string($_POST["rtype"]); |
$req =& $db->query("INSERT INTO rtype SET rtype='$rtype'"); |
break; |
case '20': |
// Правка существующего типа репозитория |
$rtypeID = abs(intval($_POST["rtypeID"])); |
$rtype = mysql_real_escape_string($_POST["rtype"]); |
$req =& $db->query("UPDATE rtype SET rtype='$rtype' WHERE rtype_id='$rtypeID'"); |
break; |
case '18': |
// Удаление типа репозитория |
$rtypeID = abs(intval($_POST["rtypeID"])); |
$req =& $db->query("DELETE FROM rtype WHERE rtype_id='$rtypeID'"); |
break; |
} |
header("Location: $go\n\n"); |
?> |
/tags/0.1/index.tpl |
---|
Новый файл |
0,0 → 1,30 |
{config_load file=ant.conf section="setup"} |
{include file="header.tpl" title='Ant'} |
<div id='ant'> |
{if $status == 0} |
<h2>Выбор дистрибутива</h2> |
<form action='./index.php' method='get'> |
<p><input type='hidden' name='step' value='1' /></p> |
{$linux} |
<p><input type='submit' value=' Выбрать дистрибутив ' /></p> |
</form> |
{/if} |
{if $status == 1} |
<h2>Выбор версии дистрибутива</h2> |
<form action='./index.php' method='get'> |
<p><input type='hidden' name='step' value='2' /></p> |
{$version} |
<p><input type='submit' value=' Получить sources.list ' /></p> |
</form> |
{/if} |
{if $status == 2} |
{$result} |
{/if} |
</div> |
<div id='footer'><a href="http://track.altlug.ru/projects/show/ant">Ant {$antversion}</a></div> |
{include file="footer.tpl"} |
/tags/0.1/lib/Smarty_Compiler.class.php |
---|
Новый файл |
0,0 → 1,2351 |
<?php |
/** |
* Project: Smarty: the PHP compiling template engine |
* File: Smarty_Compiler.class.php |
* |
* 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://www.smarty.net/ |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author Andrei Zmievski <andrei@php.net> |
* @version 2.6.22 |
* @copyright 2001-2005 New Digital Group, Inc. |
* @package Smarty |
*/ |
/* $Id: Smarty_Compiler.class.php 2966 2008-12-08 15:10:03Z monte.ohrt $ */ |
/** |
* Template compiling class |
* @package Smarty |
*/ |
class Smarty_Compiler extends Smarty { |
// internal vars |
/**#@+ |
* @access private |
*/ |
var $_folded_blocks = array(); // keeps folded template blocks |
var $_current_file = null; // the current template being compiled |
var $_current_line_no = 1; // line number for error messages |
var $_capture_stack = array(); // keeps track of nested capture buffers |
var $_plugin_info = array(); // keeps track of plugins to load |
var $_init_smarty_vars = false; |
var $_permitted_tokens = array('true','false','yes','no','on','off','null'); |
var $_db_qstr_regexp = null; // regexps are setup in the constructor |
var $_si_qstr_regexp = null; |
var $_qstr_regexp = null; |
var $_func_regexp = null; |
var $_reg_obj_regexp = null; |
var $_var_bracket_regexp = null; |
var $_num_const_regexp = null; |
var $_dvar_guts_regexp = null; |
var $_dvar_regexp = null; |
var $_cvar_regexp = null; |
var $_svar_regexp = null; |
var $_avar_regexp = null; |
var $_mod_regexp = null; |
var $_var_regexp = null; |
var $_parenth_param_regexp = null; |
var $_func_call_regexp = null; |
var $_obj_ext_regexp = null; |
var $_obj_start_regexp = null; |
var $_obj_params_regexp = null; |
var $_obj_call_regexp = null; |
var $_cacheable_state = 0; |
var $_cache_attrs_count = 0; |
var $_nocache_count = 0; |
var $_cache_serial = null; |
var $_cache_include = null; |
var $_strip_depth = 0; |
var $_additional_newline = "\n"; |
var $_phpversion = 0; |
/**#@-*/ |
/** |
* The class constructor. |
*/ |
function Smarty_Compiler() |
{ |
$this->_phpversion = substr(phpversion(),0,1); |
// matches double quoted strings: |
// "foobar" |
// "foo\"bar" |
$this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; |
// matches single quoted strings: |
// 'foobar' |
// 'foo\'bar' |
$this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; |
// matches single or double quoted strings |
$this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; |
// matches bracket portion of vars |
// [0] |
// [foo] |
// [$bar] |
$this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; |
// matches numerical constants |
// 30 |
// -12 |
// 13.22 |
$this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; |
// matches $ vars (not objects): |
// $foo |
// $foo.bar |
// $foo.bar.foobar |
// $foo[0] |
// $foo[$bar] |
// $foo[5][blah] |
// $foo[5].bar[$foobar][4] |
$this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; |
$this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; |
$this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp |
. ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; |
$this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; |
// matches config vars: |
// #foo# |
// #foobar123_foo# |
$this->_cvar_regexp = '\#\w+\#'; |
// matches section vars: |
// %foo.bar% |
$this->_svar_regexp = '\%\w+\.\w+\%'; |
// matches all valid variables (no quotes, no modifiers) |
$this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' |
. $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; |
// matches valid variable syntax: |
// $foo |
// $foo |
// #foo# |
// #foo# |
// "text" |
// "text" |
$this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; |
// matches valid object call (one level of object nesting allowed in parameters): |
// $foo->bar |
// $foo->bar() |
// $foo->bar("text") |
// $foo->bar($foo, $bar, "text") |
// $foo->bar($foo, "foo") |
// $foo->bar->foo() |
// $foo->bar->foo->bar() |
// $foo->bar($foo->bar) |
// $foo->bar($foo->bar()) |
// $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) |
// $foo->getBar()->getFoo() |
// $foo->getBar()->foo |
$this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; |
$this->_obj_restricted_param_regexp = '(?:' |
. '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' |
. '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; |
$this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' |
. $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; |
$this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp |
. '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; |
$this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; |
$this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; |
// matches valid modifier syntax: |
// |foo |
// |@foo |
// |foo:"bar" |
// |foo:$bar |
// |foo:"bar":$foobar |
// |foo|bar |
// |foo:$foo->bar |
$this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' |
. $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; |
// matches valid function name: |
// foo123 |
// _foo_bar |
$this->_func_regexp = '[a-zA-Z_]\w*'; |
// matches valid registered object: |
// foo->bar |
$this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; |
// matches valid parameter values: |
// true |
// $foo |
// $foo|bar |
// #foo# |
// #foo#|bar |
// "text" |
// "text"|bar |
// $foo->bar |
$this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' |
. $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; |
// matches valid parenthesised function parameters: |
// |
// "text" |
// $foo, $bar, "text" |
// $foo|bar, "foo"|bar, $foo->bar($foo)|bar |
$this->_parenth_param_regexp = '(?:\((?:\w+|' |
. $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' |
. $this->_param_regexp . ')))*)?\))'; |
// matches valid function call: |
// foo() |
// foo_bar($foo) |
// _foo_bar($foo,"bar") |
// foo123($foo,$foo->bar(),"foo") |
$this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' |
. $this->_parenth_param_regexp . '))'; |
} |
/** |
* compile a resource |
* |
* sets $compiled_content to the compiled source |
* @param string $resource_name |
* @param string $source_content |
* @param string $compiled_content |
* @return true |
*/ |
function _compile_file($resource_name, $source_content, &$compiled_content) |
{ |
if ($this->security) { |
// do not allow php syntax to be executed unless specified |
if ($this->php_handling == SMARTY_PHP_ALLOW && |
!$this->security_settings['PHP_HANDLING']) { |
$this->php_handling = SMARTY_PHP_PASSTHRU; |
} |
} |
$this->_load_filters(); |
$this->_current_file = $resource_name; |
$this->_current_line_no = 1; |
$ldq = preg_quote($this->left_delimiter, '~'); |
$rdq = preg_quote($this->right_delimiter, '~'); |
// run template source through prefilter functions |
if (count($this->_plugins['prefilter']) > 0) { |
foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { |
if ($prefilter === false) continue; |
if ($prefilter[3] || is_callable($prefilter[0])) { |
$source_content = call_user_func_array($prefilter[0], |
array($source_content, &$this)); |
$this->_plugins['prefilter'][$filter_name][3] = true; |
} else { |
$this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); |
} |
} |
} |
/* fetch all special blocks */ |
$search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; |
preg_match_all($search, $source_content, $match, PREG_SET_ORDER); |
$this->_folded_blocks = $match; |
reset($this->_folded_blocks); |
/* replace special blocks by "{php}" */ |
$source_content = preg_replace($search.'e', "'" |
. $this->_quote_replace($this->left_delimiter) . 'php' |
. "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" |
. $this->_quote_replace($this->right_delimiter) |
. "'" |
, $source_content); |
/* Gather all template tags. */ |
preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); |
$template_tags = $_match[1]; |
/* Split content by template tags to obtain non-template content. */ |
$text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); |
/* loop through text blocks */ |
for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { |
/* match anything resembling php tags */ |
if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { |
/* replace tags with placeholders to prevent recursive replacements */ |
$sp_match[1] = array_unique($sp_match[1]); |
usort($sp_match[1], '_smarty_sort_length'); |
for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { |
$text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); |
} |
/* process each one */ |
for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { |
if ($this->php_handling == SMARTY_PHP_PASSTHRU) { |
/* echo php contents */ |
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]); |
} else if ($this->php_handling == SMARTY_PHP_QUOTE) { |
/* quote php tags */ |
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); |
} else if ($this->php_handling == SMARTY_PHP_REMOVE) { |
/* remove php tags */ |
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); |
} else { |
/* SMARTY_PHP_ALLOW, but echo non php starting tags */ |
$sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]); |
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); |
} |
} |
} |
} |
/* Compile the template tags into PHP code. */ |
$compiled_tags = array(); |
for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { |
$this->_current_line_no += substr_count($text_blocks[$i], "\n"); |
$compiled_tags[] = $this->_compile_tag($template_tags[$i]); |
$this->_current_line_no += substr_count($template_tags[$i], "\n"); |
} |
if (count($this->_tag_stack)>0) { |
list($_open_tag, $_line_no) = end($this->_tag_stack); |
$this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); |
return; |
} |
/* Reformat $text_blocks between 'strip' and '/strip' tags, |
removing spaces, tabs and newlines. */ |
$strip = false; |
for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { |
if ($compiled_tags[$i] == '{strip}') { |
$compiled_tags[$i] = ''; |
$strip = true; |
/* remove leading whitespaces */ |
$text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); |
} |
if ($strip) { |
/* strip all $text_blocks before the next '/strip' */ |
for ($j = $i + 1; $j < $for_max; $j++) { |
/* remove leading and trailing whitespaces of each line */ |
$text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); |
if ($compiled_tags[$j] == '{/strip}') { |
/* remove trailing whitespaces from the last text_block */ |
$text_blocks[$j] = rtrim($text_blocks[$j]); |
} |
$text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>"; |
if ($compiled_tags[$j] == '{/strip}') { |
$compiled_tags[$j] = "\n"; /* slurped by php, but necessary |
if a newline is following the closing strip-tag */ |
$strip = false; |
$i = $j; |
break; |
} |
} |
} |
} |
$compiled_content = ''; |
$tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; |
/* Interleave the compiled contents and text blocks to get the final result. */ |
for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { |
if ($compiled_tags[$i] == '') { |
// tag result empty, remove first newline from following text block |
$text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); |
} |
// replace legit PHP tags with placeholder |
$text_blocks[$i] = str_replace('<?', $tag_guard, $text_blocks[$i]); |
$compiled_tags[$i] = str_replace('<?', $tag_guard, $compiled_tags[$i]); |
$compiled_content .= $text_blocks[$i] . $compiled_tags[$i]; |
} |
$compiled_content .= str_replace('<?', $tag_guard, $text_blocks[$i]); |
// escape php tags created by interleaving |
$compiled_content = str_replace('<?', "<?php echo '<?' ?>\n", $compiled_content); |
$compiled_content = preg_replace("~(?<!')language\s*=\s*[\"\']?\s*php\s*[\"\']?~", "<?php echo 'language=php' ?>\n", $compiled_content); |
// recover legit tags |
$compiled_content = str_replace($tag_guard, '<?', $compiled_content); |
// remove \n from the end of the file, if any |
if (strlen($compiled_content) && (substr($compiled_content, -1) == "\n") ) { |
$compiled_content = substr($compiled_content, 0, -1); |
} |
if (!empty($this->_cache_serial)) { |
$compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; |
} |
// run compiled template through postfilter functions |
if (count($this->_plugins['postfilter']) > 0) { |
foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { |
if ($postfilter === false) continue; |
if ($postfilter[3] || is_callable($postfilter[0])) { |
$compiled_content = call_user_func_array($postfilter[0], |
array($compiled_content, &$this)); |
$this->_plugins['postfilter'][$filter_name][3] = true; |
} else { |
$this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); |
} |
} |
} |
// put header at the top of the compiled template |
$template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; |
$template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; |
/* Emit code to load needed plugins. */ |
$this->_plugins_code = ''; |
if (count($this->_plugin_info)) { |
$_plugins_params = "array('plugins' => array("; |
foreach ($this->_plugin_info as $plugin_type => $plugins) { |
foreach ($plugins as $plugin_name => $plugin_info) { |
$_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; |
$_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; |
} |
} |
$_plugins_params .= '))'; |
$plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n"; |
$template_header .= $plugins_code; |
$this->_plugin_info = array(); |
$this->_plugins_code = $plugins_code; |
} |
if ($this->_init_smarty_vars) { |
$template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n"; |
$this->_init_smarty_vars = false; |
} |
$compiled_content = $template_header . $compiled_content; |
return true; |
} |
/** |
* Compile a template tag |
* |
* @param string $template_tag |
* @return string |
*/ |
function _compile_tag($template_tag) |
{ |
/* Matched comment. */ |
if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') |
return ''; |
/* Split tag into two three parts: command, command modifiers and the arguments. */ |
if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp |
. '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) |
(?:\s+(.*))?$ |
~xs', $template_tag, $match)) { |
$this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); |
} |
$tag_command = $match[1]; |
$tag_modifier = isset($match[2]) ? $match[2] : null; |
$tag_args = isset($match[3]) ? $match[3] : null; |
if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { |
/* tag name is a variable or object */ |
$_return = $this->_parse_var_props($tag_command . $tag_modifier); |
return "<?php echo $_return; ?>" . $this->_additional_newline; |
} |
/* If the tag name is a registered object, we process it. */ |
if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { |
return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); |
} |
switch ($tag_command) { |
case 'include': |
return $this->_compile_include_tag($tag_args); |
case 'include_php': |
return $this->_compile_include_php_tag($tag_args); |
case 'if': |
$this->_push_tag('if'); |
return $this->_compile_if_tag($tag_args); |
case 'else': |
list($_open_tag) = end($this->_tag_stack); |
if ($_open_tag != 'if' && $_open_tag != 'elseif') |
$this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); |
else |
$this->_push_tag('else'); |
return '<?php else: ?>'; |
case 'elseif': |
list($_open_tag) = end($this->_tag_stack); |
if ($_open_tag != 'if' && $_open_tag != 'elseif') |
$this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); |
if ($_open_tag == 'if') |
$this->_push_tag('elseif'); |
return $this->_compile_if_tag($tag_args, true); |
case '/if': |
$this->_pop_tag('if'); |
return '<?php endif; ?>'; |
case 'capture': |
return $this->_compile_capture_tag(true, $tag_args); |
case '/capture': |
return $this->_compile_capture_tag(false); |
case 'ldelim': |
return $this->left_delimiter; |
case 'rdelim': |
return $this->right_delimiter; |
case 'section': |
$this->_push_tag('section'); |
return $this->_compile_section_start($tag_args); |
case 'sectionelse': |
$this->_push_tag('sectionelse'); |
return "<?php endfor; else: ?>"; |
break; |
case '/section': |
$_open_tag = $this->_pop_tag('section'); |
if ($_open_tag == 'sectionelse') |
return "<?php endif; ?>"; |
else |
return "<?php endfor; endif; ?>"; |
case 'foreach': |
$this->_push_tag('foreach'); |
return $this->_compile_foreach_start($tag_args); |
break; |
case 'foreachelse': |
$this->_push_tag('foreachelse'); |
return "<?php endforeach; else: ?>"; |
case '/foreach': |
$_open_tag = $this->_pop_tag('foreach'); |
if ($_open_tag == 'foreachelse') |
return "<?php endif; unset(\$_from); ?>"; |
else |
return "<?php endforeach; endif; unset(\$_from); ?>"; |
break; |
case 'strip': |
case '/strip': |
if (substr($tag_command, 0, 1)=='/') { |
$this->_pop_tag('strip'); |
if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ |
$this->_additional_newline = "\n"; |
return '{' . $tag_command . '}'; |
} |
} else { |
$this->_push_tag('strip'); |
if ($this->_strip_depth++==0) { /* outermost opening {strip} */ |
$this->_additional_newline = ""; |
return '{' . $tag_command . '}'; |
} |
} |
return ''; |
case 'php': |
/* handle folded tags replaced by {php} */ |
list(, $block) = each($this->_folded_blocks); |
$this->_current_line_no += substr_count($block[0], "\n"); |
/* the number of matched elements in the regexp in _compile_file() |
determins the type of folded tag that was found */ |
switch (count($block)) { |
case 2: /* comment */ |
return ''; |
case 3: /* literal */ |
return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; |
case 4: /* php */ |
if ($this->security && !$this->security_settings['PHP_TAGS']) { |
$this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); |
return; |
} |
return '<?php ' . $block[3] .' ?>'; |
} |
break; |
case 'insert': |
return $this->_compile_insert_tag($tag_args); |
default: |
if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { |
return $output; |
} else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { |
return $output; |
} else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { |
return $output; |
} else { |
$this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); |
} |
} |
} |
/** |
* compile the custom compiler tag |
* |
* sets $output to the compiled custom compiler tag |
* @param string $tag_command |
* @param string $tag_args |
* @param string $output |
* @return boolean |
*/ |
function _compile_compiler_tag($tag_command, $tag_args, &$output) |
{ |
$found = false; |
$have_function = true; |
/* |
* First we check if the compiler function has already been registered |
* or loaded from a plugin file. |
*/ |
if (isset($this->_plugins['compiler'][$tag_command])) { |
$found = true; |
$plugin_func = $this->_plugins['compiler'][$tag_command][0]; |
if (!is_callable($plugin_func)) { |
$message = "compiler function '$tag_command' is not implemented"; |
$have_function = false; |
} |
} |
/* |
* Otherwise we need to load plugin file and look for the function |
* inside it. |
*/ |
else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { |
$found = true; |
include_once $plugin_file; |
$plugin_func = 'smarty_compiler_' . $tag_command; |
if (!is_callable($plugin_func)) { |
$message = "plugin function $plugin_func() not found in $plugin_file\n"; |
$have_function = false; |
} else { |
$this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); |
} |
} |
/* |
* True return value means that we either found a plugin or a |
* dynamically registered function. False means that we didn't and the |
* compiler should now emit code to load custom function plugin for this |
* tag. |
*/ |
if ($found) { |
if ($have_function) { |
$output = call_user_func_array($plugin_func, array($tag_args, &$this)); |
if($output != '') { |
$output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command) |
. $output |
. $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; |
} |
} else { |
$this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); |
} |
return true; |
} else { |
return false; |
} |
} |
/** |
* compile block function tag |
* |
* sets $output to compiled block function tag |
* @param string $tag_command |
* @param string $tag_args |
* @param string $tag_modifier |
* @param string $output |
* @return boolean |
*/ |
function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) |
{ |
if (substr($tag_command, 0, 1) == '/') { |
$start_tag = false; |
$tag_command = substr($tag_command, 1); |
} else |
$start_tag = true; |
$found = false; |
$have_function = true; |
/* |
* First we check if the block function has already been registered |
* or loaded from a plugin file. |
*/ |
if (isset($this->_plugins['block'][$tag_command])) { |
$found = true; |
$plugin_func = $this->_plugins['block'][$tag_command][0]; |
if (!is_callable($plugin_func)) { |
$message = "block function '$tag_command' is not implemented"; |
$have_function = false; |
} |
} |
/* |
* Otherwise we need to load plugin file and look for the function |
* inside it. |
*/ |
else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { |
$found = true; |
include_once $plugin_file; |
$plugin_func = 'smarty_block_' . $tag_command; |
if (!function_exists($plugin_func)) { |
$message = "plugin function $plugin_func() not found in $plugin_file\n"; |
$have_function = false; |
} else { |
$this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); |
} |
} |
if (!$found) { |
return false; |
} else if (!$have_function) { |
$this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); |
return true; |
} |
/* |
* Even though we've located the plugin function, compilation |
* happens only once, so the plugin will still need to be loaded |
* at runtime for future requests. |
*/ |
$this->_add_plugin('block', $tag_command); |
if ($start_tag) |
$this->_push_tag($tag_command); |
else |
$this->_pop_tag($tag_command); |
if ($start_tag) { |
$output = '<?php ' . $this->_push_cacheable_state('block', $tag_command); |
$attrs = $this->_parse_attrs($tag_args); |
$_cache_attrs=''; |
$arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); |
$output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; |
$output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; |
$output .= 'while ($_block_repeat) { ob_start(); ?>'; |
} else { |
$output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); '; |
$_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; |
if ($tag_modifier != '') { |
$this->_parse_modifiers($_out_tag_text, $tag_modifier); |
} |
$output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; |
$output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; |
} |
return true; |
} |
/** |
* compile custom function tag |
* |
* @param string $tag_command |
* @param string $tag_args |
* @param string $tag_modifier |
* @return string |
*/ |
function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) |
{ |
$found = false; |
$have_function = true; |
/* |
* First we check if the custom function has already been registered |
* or loaded from a plugin file. |
*/ |
if (isset($this->_plugins['function'][$tag_command])) { |
$found = true; |
$plugin_func = $this->_plugins['function'][$tag_command][0]; |
if (!is_callable($plugin_func)) { |
$message = "custom function '$tag_command' is not implemented"; |
$have_function = false; |
} |
} |
/* |
* Otherwise we need to load plugin file and look for the function |
* inside it. |
*/ |
else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { |
$found = true; |
include_once $plugin_file; |
$plugin_func = 'smarty_function_' . $tag_command; |
if (!function_exists($plugin_func)) { |
$message = "plugin function $plugin_func() not found in $plugin_file\n"; |
$have_function = false; |
} else { |
$this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); |
} |
} |
if (!$found) { |
return false; |
} else if (!$have_function) { |
$this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); |
return true; |
} |
/* declare plugin to be loaded on display of the template that |
we compile right now */ |
$this->_add_plugin('function', $tag_command); |
$_cacheable_state = $this->_push_cacheable_state('function', $tag_command); |
$attrs = $this->_parse_attrs($tag_args); |
$_cache_attrs = ''; |
$arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); |
$output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; |
if($tag_modifier != '') { |
$this->_parse_modifiers($output, $tag_modifier); |
} |
if($output != '') { |
$output = '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';' |
. $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; |
} |
return true; |
} |
/** |
* compile a registered object tag |
* |
* @param string $tag_command |
* @param array $attrs |
* @param string $tag_modifier |
* @return string |
*/ |
function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) |
{ |
if (substr($tag_command, 0, 1) == '/') { |
$start_tag = false; |
$tag_command = substr($tag_command, 1); |
} else { |
$start_tag = true; |
} |
list($object, $obj_comp) = explode('->', $tag_command); |
$arg_list = array(); |
if(count($attrs)) { |
$_assign_var = false; |
foreach ($attrs as $arg_name => $arg_value) { |
if($arg_name == 'assign') { |
$_assign_var = $arg_value; |
unset($attrs['assign']); |
continue; |
} |
if (is_bool($arg_value)) |
$arg_value = $arg_value ? 'true' : 'false'; |
$arg_list[] = "'$arg_name' => $arg_value"; |
} |
} |
if($this->_reg_objects[$object][2]) { |
// smarty object argument format |
$args = "array(".implode(',', (array)$arg_list)."), \$this"; |
} else { |
// traditional argument format |
$args = implode(',', array_values($attrs)); |
if (empty($args)) { |
$args = ''; |
} |
} |
$prefix = ''; |
$postfix = ''; |
$newline = ''; |
if(!is_object($this->_reg_objects[$object][0])) { |
$this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); |
} elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { |
$this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); |
} elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { |
// method |
if(in_array($obj_comp, $this->_reg_objects[$object][3])) { |
// block method |
if ($start_tag) { |
$prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; |
$prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; |
$prefix .= "while (\$_block_repeat) { ob_start();"; |
$return = null; |
$postfix = ''; |
} else { |
$prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; |
$return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; |
$postfix = "} array_pop(\$this->_tag_stack);"; |
} |
} else { |
// non-block method |
$return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; |
} |
} else { |
// property |
$return = "\$this->_reg_objects['$object'][0]->$obj_comp"; |
} |
if($return != null) { |
if($tag_modifier != '') { |
$this->_parse_modifiers($return, $tag_modifier); |
} |
if(!empty($_assign_var)) { |
$output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; |
} else { |
$output = 'echo ' . $return . ';'; |
$newline = $this->_additional_newline; |
} |
} else { |
$output = ''; |
} |
return '<?php ' . $prefix . $output . $postfix . "?>" . $newline; |
} |
/** |
* Compile {insert ...} tag |
* |
* @param string $tag_args |
* @return string |
*/ |
function _compile_insert_tag($tag_args) |
{ |
$attrs = $this->_parse_attrs($tag_args); |
$name = $this->_dequote($attrs['name']); |
if (empty($name)) { |
return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); |
} |
if (!preg_match('~^\w+$~', $name)) { |
return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); |
} |
if (!empty($attrs['script'])) { |
$delayed_loading = true; |
} else { |
$delayed_loading = false; |
} |
foreach ($attrs as $arg_name => $arg_value) { |
if (is_bool($arg_value)) |
$arg_value = $arg_value ? 'true' : 'false'; |
$arg_list[] = "'$arg_name' => $arg_value"; |
} |
$this->_add_plugin('insert', $name, $delayed_loading); |
$_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; |
return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline; |
} |
/** |
* Compile {include ...} tag |
* |
* @param string $tag_args |
* @return string |
*/ |
function _compile_include_tag($tag_args) |
{ |
$attrs = $this->_parse_attrs($tag_args); |
$arg_list = array(); |
if (empty($attrs['file'])) { |
$this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); |
} |
foreach ($attrs as $arg_name => $arg_value) { |
if ($arg_name == 'file') { |
$include_file = $arg_value; |
continue; |
} else if ($arg_name == 'assign') { |
$assign_var = $arg_value; |
continue; |
} |
if (is_bool($arg_value)) |
$arg_value = $arg_value ? 'true' : 'false'; |
$arg_list[] = "'$arg_name' => $arg_value"; |
} |
$output = '<?php '; |
if (isset($assign_var)) { |
$output .= "ob_start();\n"; |
} |
$output .= |
"\$_smarty_tpl_vars = \$this->_tpl_vars;\n"; |
$_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; |
$output .= "\$this->_smarty_include($_params);\n" . |
"\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . |
"unset(\$_smarty_tpl_vars);\n"; |
if (isset($assign_var)) { |
$output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; |
} |
$output .= ' ?>'; |
return $output; |
} |
/** |
* Compile {include ...} tag |
* |
* @param string $tag_args |
* @return string |
*/ |
function _compile_include_php_tag($tag_args) |
{ |
$attrs = $this->_parse_attrs($tag_args); |
if (empty($attrs['file'])) { |
$this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); |
} |
$assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); |
$once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; |
$arg_list = array(); |
foreach($attrs as $arg_name => $arg_value) { |
if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { |
if(is_bool($arg_value)) |
$arg_value = $arg_value ? 'true' : 'false'; |
$arg_list[] = "'$arg_name' => $arg_value"; |
} |
} |
$_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; |
return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline; |
} |
/** |
* Compile {section ...} tag |
* |
* @param string $tag_args |
* @return string |
*/ |
function _compile_section_start($tag_args) |
{ |
$attrs = $this->_parse_attrs($tag_args); |
$arg_list = array(); |
$output = '<?php '; |
$section_name = $attrs['name']; |
if (empty($section_name)) { |
$this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); |
} |
$output .= "unset(\$this->_sections[$section_name]);\n"; |
$section_props = "\$this->_sections[$section_name]"; |
foreach ($attrs as $attr_name => $attr_value) { |
switch ($attr_name) { |
case 'loop': |
$output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; |
break; |
case 'show': |
if (is_bool($attr_value)) |
$show_attr_value = $attr_value ? 'true' : 'false'; |
else |
$show_attr_value = "(bool)$attr_value"; |
$output .= "{$section_props}['show'] = $show_attr_value;\n"; |
break; |
case 'name': |
$output .= "{$section_props}['$attr_name'] = $attr_value;\n"; |
break; |
case 'max': |
case 'start': |
$output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; |
break; |
case 'step': |
$output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; |
break; |
default: |
$this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); |
break; |
} |
} |
if (!isset($attrs['show'])) |
$output .= "{$section_props}['show'] = true;\n"; |
if (!isset($attrs['loop'])) |
$output .= "{$section_props}['loop'] = 1;\n"; |
if (!isset($attrs['max'])) |
$output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; |
else |
$output .= "if ({$section_props}['max'] < 0)\n" . |
" {$section_props}['max'] = {$section_props}['loop'];\n"; |
if (!isset($attrs['step'])) |
$output .= "{$section_props}['step'] = 1;\n"; |
if (!isset($attrs['start'])) |
$output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; |
else { |
$output .= "if ({$section_props}['start'] < 0)\n" . |
" {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . |
"else\n" . |
" {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; |
} |
$output .= "if ({$section_props}['show']) {\n"; |
if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { |
$output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; |
} else { |
$output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; |
} |
$output .= " if ({$section_props}['total'] == 0)\n" . |
" {$section_props}['show'] = false;\n" . |
"} else\n" . |
" {$section_props}['total'] = 0;\n"; |
$output .= "if ({$section_props}['show']):\n"; |
$output .= " |
for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; |
{$section_props}['iteration'] <= {$section_props}['total']; |
{$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; |
$output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; |
$output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; |
$output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; |
$output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; |
$output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; |
$output .= "?>"; |
return $output; |
} |
/** |
* Compile {foreach ...} tag. |
* |
* @param string $tag_args |
* @return string |
*/ |
function _compile_foreach_start($tag_args) |
{ |
$attrs = $this->_parse_attrs($tag_args); |
$arg_list = array(); |
if (empty($attrs['from'])) { |
return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); |
} |
$from = $attrs['from']; |
if (empty($attrs['item'])) { |
return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); |
} |
$item = $this->_dequote($attrs['item']); |
if (!preg_match('~^\w+$~', $item)) { |
return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); |
} |
if (isset($attrs['key'])) { |
$key = $this->_dequote($attrs['key']); |
if (!preg_match('~^\w+$~', $key)) { |
return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); |
} |
$key_part = "\$this->_tpl_vars['$key'] => "; |
} else { |
$key = null; |
$key_part = ''; |
} |
if (isset($attrs['name'])) { |
$name = $attrs['name']; |
} else { |
$name = null; |
} |
$output = '<?php '; |
$output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }"; |
if (isset($name)) { |
$foreach_props = "\$this->_foreach[$name]"; |
$output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; |
$output .= "if ({$foreach_props}['total'] > 0):\n"; |
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; |
$output .= " {$foreach_props}['iteration']++;\n"; |
} else { |
$output .= "if (count(\$_from)):\n"; |
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; |
} |
$output .= '?>'; |
return $output; |
} |
/** |
* Compile {capture} .. {/capture} tags |
* |
* @param boolean $start true if this is the {capture} tag |
* @param string $tag_args |
* @return string |
*/ |
function _compile_capture_tag($start, $tag_args = '') |
{ |
$attrs = $this->_parse_attrs($tag_args); |
if ($start) { |
$buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; |
$assign = isset($attrs['assign']) ? $attrs['assign'] : null; |
$append = isset($attrs['append']) ? $attrs['append'] : null; |
$output = "<?php ob_start(); ?>"; |
$this->_capture_stack[] = array($buffer, $assign, $append); |
} else { |
list($buffer, $assign, $append) = array_pop($this->_capture_stack); |
$output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); "; |
if (isset($assign)) { |
$output .= " \$this->assign($assign, ob_get_contents());"; |
} |
if (isset($append)) { |
$output .= " \$this->append($append, ob_get_contents());"; |
} |
$output .= "ob_end_clean(); ?>"; |
} |
return $output; |
} |
/** |
* Compile {if ...} tag |
* |
* @param string $tag_args |
* @param boolean $elseif if true, uses elseif instead of if |
* @return string |
*/ |
function _compile_if_tag($tag_args, $elseif = false) |
{ |
/* Tokenize args for 'if' tag. */ |
preg_match_all('~(?> |
' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call |
' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string |
\-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token |
\b\w+\b | # valid word token |
\S+ # anything else |
)~x', $tag_args, $match); |
$tokens = $match[0]; |
if(empty($tokens)) { |
$_error_msg = $elseif ? "'elseif'" : "'if'"; |
$_error_msg .= ' statement requires arguments'; |
$this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); |
} |
// make sure we have balanced parenthesis |
$token_count = array_count_values($tokens); |
if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { |
$this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); |
} |
$is_arg_stack = array(); |
for ($i = 0; $i < count($tokens); $i++) { |
$token = &$tokens[$i]; |
switch (strtolower($token)) { |
case '!': |
case '%': |
case '!==': |
case '==': |
case '===': |
case '>': |
case '<': |
case '!=': |
case '<>': |
case '<<': |
case '>>': |
case '<=': |
case '>=': |
case '&&': |
case '||': |
case '|': |
case '^': |
case '&': |
case '~': |
case ')': |
case ',': |
case '+': |
case '-': |
case '*': |
case '/': |
case '@': |
break; |
case 'eq': |
$token = '=='; |
break; |
case 'ne': |
case 'neq': |
$token = '!='; |
break; |
case 'lt': |
$token = '<'; |
break; |
case 'le': |
case 'lte': |
$token = '<='; |
break; |
case 'gt': |
$token = '>'; |
break; |
case 'ge': |
case 'gte': |
$token = '>='; |
break; |
case 'and': |
$token = '&&'; |
break; |
case 'or': |
$token = '||'; |
break; |
case 'not': |
$token = '!'; |
break; |
case 'mod': |
$token = '%'; |
break; |
case '(': |
array_push($is_arg_stack, $i); |
break; |
case 'is': |
/* If last token was a ')', we operate on the parenthesized |
expression. The start of the expression is on the stack. |
Otherwise, we operate on the last encountered token. */ |
if ($tokens[$i-1] == ')') { |
$is_arg_start = array_pop($is_arg_stack); |
if ($is_arg_start != 0) { |
if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) { |
$is_arg_start--; |
} |
} |
} else |
$is_arg_start = $i-1; |
/* Construct the argument for 'is' expression, so it knows |
what to operate on. */ |
$is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); |
/* Pass all tokens from next one until the end to the |
'is' expression parsing function. The function will |
return modified tokens, where the first one is the result |
of the 'is' expression and the rest are the tokens it |
didn't touch. */ |
$new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); |
/* Replace the old tokens with the new ones. */ |
array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); |
/* Adjust argument start so that it won't change from the |
current position for the next iteration. */ |
$i = $is_arg_start; |
break; |
default: |
if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { |
// function call |
if($this->security && |
!in_array($token, $this->security_settings['IF_FUNCS'])) { |
$this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); |
} |
} elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { |
// variable function call |
$this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); |
} elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { |
// object or variable |
$token = $this->_parse_var_props($token); |
} elseif(is_numeric($token)) { |
// number, skip it |
} else { |
$this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); |
} |
break; |
} |
} |
if ($elseif) |
return '<?php elseif ('.implode(' ', $tokens).'): ?>'; |
else |
return '<?php if ('.implode(' ', $tokens).'): ?>'; |
} |
function _compile_arg_list($type, $name, $attrs, &$cache_code) { |
$arg_list = array(); |
if (isset($type) && isset($name) |
&& isset($this->_plugins[$type]) |
&& isset($this->_plugins[$type][$name]) |
&& empty($this->_plugins[$type][$name][4]) |
&& is_array($this->_plugins[$type][$name][5]) |
) { |
/* we have a list of parameters that should be cached */ |
$_cache_attrs = $this->_plugins[$type][$name][5]; |
$_count = $this->_cache_attrs_count++; |
$cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; |
} else { |
/* no parameters are cached */ |
$_cache_attrs = null; |
} |
foreach ($attrs as $arg_name => $arg_value) { |
if (is_bool($arg_value)) |
$arg_value = $arg_value ? 'true' : 'false'; |
if (is_null($arg_value)) |
$arg_value = 'null'; |
if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { |
$arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; |
} else { |
$arg_list[] = "'$arg_name' => $arg_value"; |
} |
} |
return $arg_list; |
} |
/** |
* Parse is expression |
* |
* @param string $is_arg |
* @param array $tokens |
* @return array |
*/ |
function _parse_is_expr($is_arg, $tokens) |
{ |
$expr_end = 0; |
$negate_expr = false; |
if (($first_token = array_shift($tokens)) == 'not') { |
$negate_expr = true; |
$expr_type = array_shift($tokens); |
} else |
$expr_type = $first_token; |
switch ($expr_type) { |
case 'even': |
if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { |
$expr_end++; |
$expr_arg = $tokens[$expr_end++]; |
$expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; |
} else |
$expr = "!(1 & $is_arg)"; |
break; |
case 'odd': |
if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { |
$expr_end++; |
$expr_arg = $tokens[$expr_end++]; |
$expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; |
} else |
$expr = "(1 & $is_arg)"; |
break; |
case 'div': |
if (@$tokens[$expr_end] == 'by') { |
$expr_end++; |
$expr_arg = $tokens[$expr_end++]; |
$expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; |
} else { |
$this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); |
} |
break; |
default: |
$this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); |
break; |
} |
if ($negate_expr) { |
$expr = "!($expr)"; |
} |
array_splice($tokens, 0, $expr_end, $expr); |
return $tokens; |
} |
/** |
* Parse attribute string |
* |
* @param string $tag_args |
* @return array |
*/ |
function _parse_attrs($tag_args) |
{ |
/* Tokenize tag attributes. */ |
preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) |
)+ | |
[=] |
~x', $tag_args, $match); |
$tokens = $match[0]; |
$attrs = array(); |
/* Parse state: |
0 - expecting attribute name |
1 - expecting '=' |
2 - expecting attribute value (not '=') */ |
$state = 0; |
foreach ($tokens as $token) { |
switch ($state) { |
case 0: |
/* If the token is a valid identifier, we set attribute name |
and go to state 1. */ |
if (preg_match('~^\w+$~', $token)) { |
$attr_name = $token; |
$state = 1; |
} else |
$this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); |
break; |
case 1: |
/* If the token is '=', then we go to state 2. */ |
if ($token == '=') { |
$state = 2; |
} else |
$this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); |
break; |
case 2: |
/* If token is not '=', we set the attribute value and go to |
state 0. */ |
if ($token != '=') { |
/* We booleanize the token if it's a non-quoted possible |
boolean value. */ |
if (preg_match('~^(on|yes|true)$~', $token)) { |
$token = 'true'; |
} else if (preg_match('~^(off|no|false)$~', $token)) { |
$token = 'false'; |
} else if ($token == 'null') { |
$token = 'null'; |
} else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { |
/* treat integer literally */ |
} else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { |
/* treat as a string, double-quote it escaping quotes */ |
$token = '"'.addslashes($token).'"'; |
} |
$attrs[$attr_name] = $token; |
$state = 0; |
} else |
$this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); |
break; |
} |
$last_token = $token; |
} |
if($state != 0) { |
if($state == 1) { |
$this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); |
} else { |
$this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); |
} |
} |
$this->_parse_vars_props($attrs); |
return $attrs; |
} |
/** |
* compile multiple variables and section properties tokens into |
* PHP code |
* |
* @param array $tokens |
*/ |
function _parse_vars_props(&$tokens) |
{ |
foreach($tokens as $key => $val) { |
$tokens[$key] = $this->_parse_var_props($val); |
} |
} |
/** |
* compile single variable and section properties token into |
* PHP code |
* |
* @param string $val |
* @param string $tag_attrs |
* @return string |
*/ |
function _parse_var_props($val) |
{ |
$val = trim($val); |
if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { |
// $ variable or object |
$return = $this->_parse_var($match[1]); |
$modifiers = $match[2]; |
if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { |
$_default_mod_string = implode('|',(array)$this->default_modifiers); |
$modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; |
} |
$this->_parse_modifiers($return, $modifiers); |
return $return; |
} elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { |
// double quoted text |
preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); |
$return = $this->_expand_quoted_text($match[1]); |
if($match[2] != '') { |
$this->_parse_modifiers($return, $match[2]); |
} |
return $return; |
} |
elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { |
// numerical constant |
preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); |
if($match[2] != '') { |
$this->_parse_modifiers($match[1], $match[2]); |
return $match[1]; |
} |
} |
elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { |
// single quoted text |
preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); |
if($match[2] != '') { |
$this->_parse_modifiers($match[1], $match[2]); |
return $match[1]; |
} |
} |
elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { |
// config var |
return $this->_parse_conf_var($val); |
} |
elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { |
// section var |
return $this->_parse_section_prop($val); |
} |
elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { |
// literal string |
return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); |
} |
return $val; |
} |
/** |
* expand quoted text with embedded variables |
* |
* @param string $var_expr |
* @return string |
*/ |
function _expand_quoted_text($var_expr) |
{ |
// if contains unescaped $, expand it |
if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) { |
$_match = $_match[0]; |
$_replace = array(); |
foreach($_match as $_var) { |
$_replace[$_var] = '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."'; |
} |
$var_expr = strtr($var_expr, $_replace); |
$_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr); |
} else { |
$_return = $var_expr; |
} |
// replace double quoted literal string with single quotes |
$_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return); |
// escape dollar sign if not printing a var |
$_return = preg_replace('~\$(\W)~',"\\\\\$\\1",$_return); |
return $_return; |
} |
/** |
* parse variable expression into PHP code |
* |
* @param string $var_expr |
* @param string $output |
* @return string |
*/ |
function _parse_var($var_expr) |
{ |
$_has_math = false; |
$_has_php4_method_chaining = false; |
$_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); |
if(count($_math_vars) > 1) { |
$_first_var = ""; |
$_complete_var = ""; |
$_output = ""; |
// simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) |
foreach($_math_vars as $_k => $_math_var) { |
$_math_var = $_math_vars[$_k]; |
if(!empty($_math_var) || is_numeric($_math_var)) { |
// hit a math operator, so process the stuff which came before it |
if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { |
$_has_math = true; |
if(!empty($_complete_var) || is_numeric($_complete_var)) { |
$_output .= $this->_parse_var($_complete_var); |
} |
// just output the math operator to php |
$_output .= $_math_var; |
if(empty($_first_var)) |
$_first_var = $_complete_var; |
$_complete_var = ""; |
} else { |
$_complete_var .= $_math_var; |
} |
} |
} |
if($_has_math) { |
if(!empty($_complete_var) || is_numeric($_complete_var)) |
$_output .= $this->_parse_var($_complete_var); |
// get the modifiers working (only the last var from math + modifier is left) |
$var_expr = $_complete_var; |
} |
} |
// prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) |
if(is_numeric(substr($var_expr, 0, 1))) |
$_var_ref = $var_expr; |
else |
$_var_ref = substr($var_expr, 1); |
if(!$_has_math) { |
// get [foo] and .foo and ->foo and (...) pieces |
preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); |
$_indexes = $match[0]; |
$_var_name = array_shift($_indexes); |
/* Handle $smarty.* variable references as a special case. */ |
if ($_var_name == 'smarty') { |
/* |
* If the reference could be compiled, use the compiled output; |
* otherwise, fall back on the $smarty variable generated at |
* run-time. |
*/ |
if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { |
$_output = $smarty_ref; |
} else { |
$_var_name = substr(array_shift($_indexes), 1); |
$_output = "\$this->_smarty_vars['$_var_name']"; |
} |
} elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { |
// because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers |
if(count($_indexes) > 0) |
{ |
$_var_name .= implode("", $_indexes); |
$_indexes = array(); |
} |
$_output = $_var_name; |
} else { |
$_output = "\$this->_tpl_vars['$_var_name']"; |
} |
foreach ($_indexes as $_index) { |
if (substr($_index, 0, 1) == '[') { |
$_index = substr($_index, 1, -1); |
if (is_numeric($_index)) { |
$_output .= "[$_index]"; |
} elseif (substr($_index, 0, 1) == '$') { |
if (strpos($_index, '.') !== false) { |
$_output .= '[' . $this->_parse_var($_index) . ']'; |
} else { |
$_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; |
} |
} else { |
$_var_parts = explode('.', $_index); |
$_var_section = $_var_parts[0]; |
$_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; |
$_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; |
} |
} else if (substr($_index, 0, 1) == '.') { |
if (substr($_index, 1, 1) == '$') |
$_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; |
else |
$_output .= "['" . substr($_index, 1) . "']"; |
} else if (substr($_index,0,2) == '->') { |
if(substr($_index,2,2) == '__') { |
$this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); |
} elseif($this->security && substr($_index, 2, 1) == '_') { |
$this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); |
} elseif (substr($_index, 2, 1) == '$') { |
if ($this->security) { |
$this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); |
} else { |
$_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; |
} |
} else { |
if ($this->_phpversion < 5) { |
$_has_php4_method_chaining = true; |
$_output .= "; \$_foo = \$_foo"; |
} |
$_output .= $_index; |
} |
} elseif (substr($_index, 0, 1) == '(') { |
$_index = $this->_parse_parenth_args($_index); |
$_output .= $_index; |
} else { |
$_output .= $_index; |
} |
} |
} |
if ($_has_php4_method_chaining) { |
$_tmp = str_replace("'","\'",'$_foo = '.$_output.'; return $_foo;'); |
return "eval('".$_tmp."')"; |
} else { |
return $_output; |
} |
} |
/** |
* parse arguments in function call parenthesis |
* |
* @param string $parenth_args |
* @return string |
*/ |
function _parse_parenth_args($parenth_args) |
{ |
preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); |
$orig_vals = $match = $match[0]; |
$this->_parse_vars_props($match); |
$replace = array(); |
for ($i = 0, $count = count($match); $i < $count; $i++) { |
$replace[$orig_vals[$i]] = $match[$i]; |
} |
return strtr($parenth_args, $replace); |
} |
/** |
* parse configuration variable expression into PHP code |
* |
* @param string $conf_var_expr |
*/ |
function _parse_conf_var($conf_var_expr) |
{ |
$parts = explode('|', $conf_var_expr, 2); |
$var_ref = $parts[0]; |
$modifiers = isset($parts[1]) ? $parts[1] : ''; |
$var_name = substr($var_ref, 1, -1); |
$output = "\$this->_config[0]['vars']['$var_name']"; |
$this->_parse_modifiers($output, $modifiers); |
return $output; |
} |
/** |
* parse section property expression into PHP code |
* |
* @param string $section_prop_expr |
* @return string |
*/ |
function _parse_section_prop($section_prop_expr) |
{ |
$parts = explode('|', $section_prop_expr, 2); |
$var_ref = $parts[0]; |
$modifiers = isset($parts[1]) ? $parts[1] : ''; |
preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); |
$section_name = $match[1]; |
$prop_name = $match[2]; |
$output = "\$this->_sections['$section_name']['$prop_name']"; |
$this->_parse_modifiers($output, $modifiers); |
return $output; |
} |
/** |
* parse modifier chain into PHP code |
* |
* sets $output to parsed modified chain |
* @param string $output |
* @param string $modifier_string |
*/ |
function _parse_modifiers(&$output, $modifier_string) |
{ |
preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); |
list(, $_modifiers, $modifier_arg_strings) = $_match; |
for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { |
$_modifier_name = $_modifiers[$_i]; |
if($_modifier_name == 'smarty') { |
// skip smarty modifier |
continue; |
} |
preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); |
$_modifier_args = $_match[1]; |
if (substr($_modifier_name, 0, 1) == '@') { |
$_map_array = false; |
$_modifier_name = substr($_modifier_name, 1); |
} else { |
$_map_array = true; |
} |
if (empty($this->_plugins['modifier'][$_modifier_name]) |
&& !$this->_get_plugin_filepath('modifier', $_modifier_name) |
&& function_exists($_modifier_name)) { |
if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { |
$this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); |
} else { |
$this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); |
} |
} |
$this->_add_plugin('modifier', $_modifier_name); |
$this->_parse_vars_props($_modifier_args); |
if($_modifier_name == 'default') { |
// supress notifications of default modifier vars and args |
if(substr($output, 0, 1) == '$') { |
$output = '@' . $output; |
} |
if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { |
$_modifier_args[0] = '@' . $_modifier_args[0]; |
} |
} |
if (count($_modifier_args) > 0) |
$_modifier_args = ', '.implode(', ', $_modifier_args); |
else |
$_modifier_args = ''; |
if ($_map_array) { |
$output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; |
} else { |
$output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; |
} |
} |
} |
/** |
* add plugin |
* |
* @param string $type |
* @param string $name |
* @param boolean? $delayed_loading |
*/ |
function _add_plugin($type, $name, $delayed_loading = null) |
{ |
if (!isset($this->_plugin_info[$type])) { |
$this->_plugin_info[$type] = array(); |
} |
if (!isset($this->_plugin_info[$type][$name])) { |
$this->_plugin_info[$type][$name] = array($this->_current_file, |
$this->_current_line_no, |
$delayed_loading); |
} |
} |
/** |
* Compiles references of type $smarty.foo |
* |
* @param string $indexes |
* @return string |
*/ |
function _compile_smarty_ref(&$indexes) |
{ |
/* Extract the reference name. */ |
$_ref = substr($indexes[0], 1); |
foreach($indexes as $_index_no=>$_index) { |
if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { |
$this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); |
} |
} |
switch ($_ref) { |
case 'now': |
$compiled_ref = 'time()'; |
$_max_index = 1; |
break; |
case 'foreach': |
array_shift($indexes); |
$_var = $this->_parse_var_props(substr($indexes[0], 1)); |
$_propname = substr($indexes[1], 1); |
$_max_index = 1; |
switch ($_propname) { |
case 'index': |
array_shift($indexes); |
$compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; |
break; |
case 'first': |
array_shift($indexes); |
$compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; |
break; |
case 'last': |
array_shift($indexes); |
$compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; |
break; |
case 'show': |
array_shift($indexes); |
$compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; |
break; |
default: |
unset($_max_index); |
$compiled_ref = "\$this->_foreach[$_var]"; |
} |
break; |
case 'section': |
array_shift($indexes); |
$_var = $this->_parse_var_props(substr($indexes[0], 1)); |
$compiled_ref = "\$this->_sections[$_var]"; |
break; |
case 'get': |
$compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; |
break; |
case 'post': |
$compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; |
break; |
case 'cookies': |
$compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; |
break; |
case 'env': |
$compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; |
break; |
case 'server': |
$compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; |
break; |
case 'session': |
$compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; |
break; |
/* |
* These cases are handled either at run-time or elsewhere in the |
* compiler. |
*/ |
case 'request': |
if ($this->request_use_auto_globals) { |
$compiled_ref = '$_REQUEST'; |
break; |
} else { |
$this->_init_smarty_vars = true; |
} |
return null; |
case 'capture': |
return null; |
case 'template': |
$compiled_ref = "'$this->_current_file'"; |
$_max_index = 1; |
break; |
case 'version': |
$compiled_ref = "'$this->_version'"; |
$_max_index = 1; |
break; |
case 'const': |
if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { |
$this->_syntax_error("(secure mode) constants not permitted", |
E_USER_WARNING, __FILE__, __LINE__); |
return; |
} |
array_shift($indexes); |
if (preg_match('!^\.\w+$!', $indexes[0])) { |
$compiled_ref = '@' . substr($indexes[0], 1); |
} else { |
$_val = $this->_parse_var_props(substr($indexes[0], 1)); |
$compiled_ref = '@constant(' . $_val . ')'; |
} |
$_max_index = 1; |
break; |
case 'config': |
$compiled_ref = "\$this->_config[0]['vars']"; |
$_max_index = 3; |
break; |
case 'ldelim': |
$compiled_ref = "'$this->left_delimiter'"; |
break; |
case 'rdelim': |
$compiled_ref = "'$this->right_delimiter'"; |
break; |
default: |
$this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); |
break; |
} |
if (isset($_max_index) && count($indexes) > $_max_index) { |
$this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); |
} |
array_shift($indexes); |
return $compiled_ref; |
} |
/** |
* compiles call to plugin of type $type with name $name |
* returns a string containing the function-name or method call |
* without the paramter-list that would have follow to make the |
* call valid php-syntax |
* |
* @param string $type |
* @param string $name |
* @return string |
*/ |
function _compile_plugin_call($type, $name) { |
if (isset($this->_plugins[$type][$name])) { |
/* plugin loaded */ |
if (is_array($this->_plugins[$type][$name][0])) { |
return ((is_object($this->_plugins[$type][$name][0][0])) ? |
"\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ |
: (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ |
). $this->_plugins[$type][$name][0][1]; |
} else { |
/* function callback */ |
return $this->_plugins[$type][$name][0]; |
} |
} else { |
/* plugin not loaded -> auto-loadable-plugin */ |
return 'smarty_'.$type.'_'.$name; |
} |
} |
/** |
* load pre- and post-filters |
*/ |
function _load_filters() |
{ |
if (count($this->_plugins['prefilter']) > 0) { |
foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { |
if ($prefilter === false) { |
unset($this->_plugins['prefilter'][$filter_name]); |
$_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); |
require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); |
smarty_core_load_plugins($_params, $this); |
} |
} |
} |
if (count($this->_plugins['postfilter']) > 0) { |
foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { |
if ($postfilter === false) { |
unset($this->_plugins['postfilter'][$filter_name]); |
$_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); |
require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); |
smarty_core_load_plugins($_params, $this); |
} |
} |
} |
} |
/** |
* Quote subpattern references |
* |
* @param string $string |
* @return string |
*/ |
function _quote_replace($string) |
{ |
return strtr($string, array('\\' => '\\\\', '$' => '\\$')); |
} |
/** |
* display Smarty syntax error |
* |
* @param string $error_msg |
* @param integer $error_type |
* @param string $file |
* @param integer $line |
*/ |
function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) |
{ |
$this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); |
} |
/** |
* check if the compilation changes from cacheable to |
* non-cacheable state with the beginning of the current |
* plugin. return php-code to reflect the transition. |
* @return string |
*/ |
function _push_cacheable_state($type, $name) { |
$_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; |
if ($_cacheable |
|| 0<$this->_cacheable_state++) return ''; |
if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); |
$_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' |
. $this->_cache_serial . '#' . $this->_nocache_count |
. '}\'; endif;'; |
return $_ret; |
} |
/** |
* check if the compilation changes from non-cacheable to |
* cacheable state with the end of the current plugin return |
* php-code to reflect the transition. |
* @return string |
*/ |
function _pop_cacheable_state($type, $name) { |
$_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; |
if ($_cacheable |
|| --$this->_cacheable_state>0) return ''; |
return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' |
. $this->_cache_serial . '#' . ($this->_nocache_count++) |
. '}\'; endif;'; |
} |
/** |
* push opening tag-name, file-name and line-number on the tag-stack |
* @param string the opening tag's name |
*/ |
function _push_tag($open_tag) |
{ |
array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); |
} |
/** |
* pop closing tag-name |
* raise an error if this stack-top doesn't match with the closing tag |
* @param string the closing tag's name |
* @return string the opening tag's name |
*/ |
function _pop_tag($close_tag) |
{ |
$message = ''; |
if (count($this->_tag_stack)>0) { |
list($_open_tag, $_line_no) = array_pop($this->_tag_stack); |
if ($close_tag == $_open_tag) { |
return $_open_tag; |
} |
if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { |
return $this->_pop_tag($close_tag); |
} |
if ($close_tag == 'section' && $_open_tag == 'sectionelse') { |
$this->_pop_tag($close_tag); |
return $_open_tag; |
} |
if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { |
$this->_pop_tag($close_tag); |
return $_open_tag; |
} |
if ($_open_tag == 'else' || $_open_tag == 'elseif') { |
$_open_tag = 'if'; |
} elseif ($_open_tag == 'sectionelse') { |
$_open_tag = 'section'; |
} elseif ($_open_tag == 'foreachelse') { |
$_open_tag = 'foreach'; |
} |
$message = " expected {/$_open_tag} (opened line $_line_no)."; |
} |
$this->_syntax_error("mismatched tag {/$close_tag}.$message", |
E_USER_ERROR, __FILE__, __LINE__); |
} |
} |
/** |
* compare to values by their string length |
* |
* @access private |
* @param string $a |
* @param string $b |
* @return 0|-1|1 |
*/ |
function _smarty_sort_length($a, $b) |
{ |
if($a == $b) |
return 0; |
if(strlen($a) == strlen($b)) |
return ($a > $b) ? -1 : 1; |
return (strlen($a) > strlen($b)) ? -1 : 1; |
} |
/* vim: set et: */ |
?> |
/tags/0.1/lib/config.inc.php |
---|
Новый файл |
0,0 → 1,14 |
<?php |
$CookieLogin = "AntLogin"; |
$CookiePasswd = "AntPWD"; |
$CookieDomain = "alex-w.org.ru"; |
$CookiePath = "/p/ant/"; |
$CookieTime = 60*30; |
$DBname = "ant"; |
$DBhost = "localhost"; |
$DBuser = ""; |
$DBpass = ""; |
?> |
/tags/0.1/lib/DB/mssql.php |
---|
Новый файл |
0,0 → 1,963 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's mssql extension |
* for interacting with Microsoft SQL Server databases |
* |
* 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 Sterling Hughes <sterling@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: mssql.php,v 1.92 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's mssql extension |
* for interacting with Microsoft SQL Server databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* DB's mssql driver is only for Microsfoft SQL Server databases. |
* |
* If you're connecting to a Sybase database, you MUST specify "sybase" |
* as the "phptype" in the DSN. |
* |
* This class only works correctly if you have compiled PHP using |
* --with-mssql=[dir_to_FreeTDS]. |
* |
* @category Database |
* @package DB |
* @author Sterling Hughes <sterling@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_mssql extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'mssql'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'mssql'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'emulate', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
// XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX |
var $errorcode_map = array( |
102 => DB_ERROR_SYNTAX, |
110 => DB_ERROR_VALUE_COUNT_ON_ROW, |
155 => DB_ERROR_NOSUCHFIELD, |
156 => DB_ERROR_SYNTAX, |
170 => DB_ERROR_SYNTAX, |
207 => DB_ERROR_NOSUCHFIELD, |
208 => DB_ERROR_NOSUCHTABLE, |
245 => DB_ERROR_INVALID_NUMBER, |
319 => DB_ERROR_SYNTAX, |
321 => DB_ERROR_NOSUCHFIELD, |
325 => DB_ERROR_SYNTAX, |
336 => DB_ERROR_SYNTAX, |
515 => DB_ERROR_CONSTRAINT_NOT_NULL, |
547 => DB_ERROR_CONSTRAINT, |
1018 => DB_ERROR_SYNTAX, |
1035 => DB_ERROR_SYNTAX, |
1913 => DB_ERROR_ALREADY_EXISTS, |
2209 => DB_ERROR_SYNTAX, |
2223 => DB_ERROR_SYNTAX, |
2248 => DB_ERROR_SYNTAX, |
2256 => DB_ERROR_SYNTAX, |
2257 => DB_ERROR_SYNTAX, |
2627 => DB_ERROR_CONSTRAINT, |
2714 => DB_ERROR_ALREADY_EXISTS, |
3607 => DB_ERROR_DIVZERO, |
3701 => DB_ERROR_NOSUCHTABLE, |
7630 => DB_ERROR_SYNTAX, |
8134 => DB_ERROR_DIVZERO, |
9303 => DB_ERROR_SYNTAX, |
9317 => DB_ERROR_SYNTAX, |
9318 => DB_ERROR_SYNTAX, |
9331 => DB_ERROR_SYNTAX, |
9332 => DB_ERROR_SYNTAX, |
15253 => DB_ERROR_SYNTAX, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The quantity of transactions begun |
* |
* {@internal While this is private, it can't actually be designated |
* private in PHP 5 because it is directly accessed in the test suite.}} |
* |
* @var integer |
* @access private |
*/ |
var $transaction_opcount = 0; |
/** |
* The database specified in the DSN |
* |
* It's a fix to allow calls to different databases in the same script. |
* |
* @var string |
* @access private |
*/ |
var $_db = null; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_mssql() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase') |
&& !PEAR::loadExtension('sybase_ct')) |
{ |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$params = array( |
$dsn['hostspec'] ? $dsn['hostspec'] : 'localhost', |
$dsn['username'] ? $dsn['username'] : null, |
$dsn['password'] ? $dsn['password'] : null, |
); |
if ($dsn['port']) { |
$params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':') |
. $dsn['port']; |
} |
$connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect'; |
$this->connection = @call_user_func_array($connect_function, $params); |
if (!$this->connection) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
@mssql_get_last_message()); |
} |
if ($dsn['database']) { |
if (!@mssql_select_db($dsn['database'], $this->connection)) { |
return $this->raiseError(DB_ERROR_NODBSELECTED, |
null, null, null, |
@mssql_get_last_message()); |
} |
$this->_db = $dsn['database']; |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @mssql_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
if (!@mssql_select_db($this->_db, $this->connection)) { |
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
$query = $this->modifyQuery($query); |
if (!$this->autocommit && $ismanip) { |
if ($this->transaction_opcount == 0) { |
$result = @mssql_query('BEGIN TRAN', $this->connection); |
if (!$result) { |
return $this->mssqlRaiseError(); |
} |
} |
$this->transaction_opcount++; |
} |
$result = @mssql_query($query, $this->connection); |
if (!$result) { |
return $this->mssqlRaiseError(); |
} |
// Determine which queries that should return data, and which |
// should return an error code only. |
return $ismanip ? DB_OK : $result; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal mssql result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return @mssql_next_result($result); |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@mssql_data_seek($result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @mssql_fetch_assoc($result); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @mssql_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? mssql_free_result($result) : false; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @mssql_num_fields($result); |
if (!$cols) { |
return $this->mssqlRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @mssql_num_rows($result); |
if ($rows === false) { |
return $this->mssqlRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
// XXX if $this->transaction_opcount > 0, we should probably |
// issue a warning here. |
$this->autocommit = $onoff ? true : false; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if ($this->transaction_opcount > 0) { |
if (!@mssql_select_db($this->_db, $this->connection)) { |
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
$result = @mssql_query('COMMIT TRAN', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->mssqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if ($this->transaction_opcount > 0) { |
if (!@mssql_select_db($this->_db, $this->connection)) { |
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
$result = @mssql_query('ROLLBACK TRAN', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->mssqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->_last_query_manip) { |
$res = @mssql_query('select @@rowcount', $this->connection); |
if (!$res) { |
return $this->mssqlRaiseError(); |
} |
$ar = @mssql_fetch_row($res); |
if (!$ar) { |
$result = 0; |
} else { |
@mssql_free_result($res); |
$result = $ar[0]; |
} |
} else { |
$result = 0; |
} |
return $result; |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_mssql::createSequence(), DB_mssql::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
if (!@mssql_select_db($this->_db, $this->connection)) { |
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
$repeat = 0; |
do { |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)"); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result) && |
($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) |
{ |
$repeat = 1; |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
} elseif (!DB::isError($result)) { |
$result = $this->query("SELECT IDENT_CURRENT('$seqname')"); |
if (DB::isError($result)) { |
/* Fallback code for MS SQL Server 7.0, which doesn't have |
* IDENT_CURRENT. This is *not* safe for concurrent |
* requests, and really, if you're using it, you're in a |
* world of hurt. Nevertheless, it's here to ensure BC. See |
* bug #181 for the gory details.*/ |
$result = $this->query("SELECT @@IDENTITY FROM $seqname"); |
} |
$repeat = 0; |
} else { |
$repeat = false; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$result = $result->fetchRow(DB_FETCHMODE_ORDERED); |
return $result[0]; |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_mssql::nextID(), DB_mssql::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
return $this->query('CREATE TABLE ' |
. $this->getSequenceName($seq_name) |
. ' ([id] [int] IDENTITY (1, 1) NOT NULL,' |
. ' [vapor] [int] NULL)'); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_mssql::nextID(), DB_mssql::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ quoteIdentifier() |
/** |
* Quotes a string so it can be safely used as a table or column name |
* |
* @param string $str identifier name to be quoted |
* |
* @return string quoted identifier string |
* |
* @see DB_common::quoteIdentifier() |
* @since Method available since Release 1.6.0 |
*/ |
function quoteIdentifier($str) |
{ |
return '[' . str_replace(']', ']]', $str) . ']'; |
} |
// }}} |
// {{{ mssqlRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_mssql::errorNative(), DB_mssql::errorCode() |
*/ |
function mssqlRaiseError($code = null) |
{ |
$message = @mssql_get_last_message(); |
if (!$code) { |
$code = $this->errorNative(); |
} |
return $this->raiseError($this->errorCode($code, $message), |
null, null, null, "$code - $message"); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return int the DBMS' error code |
*/ |
function errorNative() |
{ |
$res = @mssql_query('select @@ERROR as ErrorCode', $this->connection); |
if (!$res) { |
return DB_ERROR; |
} |
$row = @mssql_fetch_row($res); |
return $row[0]; |
} |
// }}} |
// {{{ errorCode() |
/** |
* Determines PEAR::DB error code from mssql's native codes. |
* |
* If <var>$nativecode</var> isn't known yet, it will be looked up. |
* |
* @param mixed $nativecode mssql error code, if known |
* @return integer an error number from a DB error constant |
* @see errorNative() |
*/ |
function errorCode($nativecode = null, $msg = '') |
{ |
if (!$nativecode) { |
$nativecode = $this->errorNative(); |
} |
if (isset($this->errorcode_map[$nativecode])) { |
if ($nativecode == 3701 |
&& preg_match('/Cannot drop the index/i', $msg)) |
{ |
return DB_ERROR_NOT_FOUND; |
} |
return $this->errorcode_map[$nativecode]; |
} else { |
return DB_ERROR; |
} |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* NOTE: only supports 'table' and 'flags' if <var>$result</var> |
* is a table name. |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
if (!@mssql_select_db($this->_db, $this->connection)) { |
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
$id = @mssql_query("SELECT * FROM $result WHERE 1=0", |
$this->connection); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @mssql_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
if ($got_string) { |
$flags = $this->_mssql_field_flags($result, |
@mssql_field_name($id, $i)); |
if (DB::isError($flags)) { |
return $flags; |
} |
} else { |
$flags = ''; |
} |
$res[$i] = array( |
'table' => $got_string ? $case_func($result) : '', |
'name' => $case_func(@mssql_field_name($id, $i)), |
'type' => @mssql_field_type($id, $i), |
'len' => @mssql_field_length($id, $i), |
'flags' => $flags, |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@mssql_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ _mssql_field_flags() |
/** |
* Get a column's flags |
* |
* Supports "not_null", "primary_key", |
* "auto_increment" (mssql identity), "timestamp" (mssql timestamp), |
* "unique_key" (mssql unique index, unique check or primary_key) and |
* "multiple_key" (multikey index) |
* |
* mssql timestamp is NOT similar to the mysql timestamp so this is maybe |
* not useful at all - is the behaviour of mysql_field_flags that primary |
* keys are alway unique? is the interpretation of multiple_key correct? |
* |
* @param string $table the table name |
* @param string $column the field name |
* |
* @return string the flags |
* |
* @access private |
* @author Joern Barthel <j_barthel@web.de> |
*/ |
function _mssql_field_flags($table, $column) |
{ |
static $tableName = null; |
static $flags = array(); |
if ($table != $tableName) { |
$flags = array(); |
$tableName = $table; |
// get unique and primary keys |
$res = $this->getAll("EXEC SP_HELPINDEX $table", DB_FETCHMODE_ASSOC); |
if (DB::isError($res)) { |
return $res; |
} |
foreach ($res as $val) { |
$keys = explode(', ', $val['index_keys']); |
if (sizeof($keys) > 1) { |
foreach ($keys as $key) { |
$this->_add_flag($flags[$key], 'multiple_key'); |
} |
} |
if (strpos($val['index_description'], 'primary key')) { |
foreach ($keys as $key) { |
$this->_add_flag($flags[$key], 'primary_key'); |
} |
} elseif (strpos($val['index_description'], 'unique')) { |
foreach ($keys as $key) { |
$this->_add_flag($flags[$key], 'unique_key'); |
} |
} |
} |
// get auto_increment, not_null and timestamp |
$res = $this->getAll("EXEC SP_COLUMNS $table", DB_FETCHMODE_ASSOC); |
if (DB::isError($res)) { |
return $res; |
} |
foreach ($res as $val) { |
$val = array_change_key_case($val, CASE_LOWER); |
if ($val['nullable'] == '0') { |
$this->_add_flag($flags[$val['column_name']], 'not_null'); |
} |
if (strpos($val['type_name'], 'identity')) { |
$this->_add_flag($flags[$val['column_name']], 'auto_increment'); |
} |
if (strpos($val['type_name'], 'timestamp')) { |
$this->_add_flag($flags[$val['column_name']], 'timestamp'); |
} |
} |
} |
if (array_key_exists($column, $flags)) { |
return(implode(' ', $flags[$column])); |
} |
return ''; |
} |
// }}} |
// {{{ _add_flag() |
/** |
* Adds a string to the flags array if the flag is not yet in there |
* - if there is no flag present the array is created |
* |
* @param array &$array the reference to the flag-array |
* @param string $value the flag value |
* |
* @return void |
* |
* @access private |
* @author Joern Barthel <j_barthel@web.de> |
*/ |
function _add_flag(&$array, $value) |
{ |
if (!is_array($array)) { |
$array = array($value); |
} elseif (!in_array($value, $array)) { |
array_push($array, $value); |
} |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return "SELECT name FROM sysobjects WHERE type = 'U'" |
. ' ORDER BY name'; |
case 'views': |
return "SELECT name FROM sysobjects WHERE type = 'V'"; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/sqlite.php |
---|
Новый файл |
0,0 → 1,959 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's sqlite extension |
* for interacting with SQLite databases |
* |
* 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 Urs Gehrig <urs@circle.ch> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 |
* @version CVS: $Id: sqlite.php,v 1.117 2007/09/21 14:23:28 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's sqlite extension |
* for interacting with SQLite databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* NOTICE: This driver needs PHP's track_errors ini setting to be on. |
* It is automatically turned on when connecting to the database. |
* Make sure your scripts don't turn it off. |
* |
* @category Database |
* @package DB |
* @author Urs Gehrig <urs@circle.ch> |
* @author Mika Tuupola <tuupola@appelsiini.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_sqlite extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'sqlite'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'sqlite'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'alter', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => false, |
); |
/** |
* A mapping of native error codes to DB error codes |
* |
* {@internal Error codes according to sqlite_exec. See the online |
* manual at http://sqlite.org/c_interface.html for info. |
* This error handling based on sqlite_exec is not yet implemented.}} |
* |
* @var array |
*/ |
var $errorcode_map = array( |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* SQLite data types |
* |
* @link http://www.sqlite.org/datatypes.html |
* |
* @var array |
*/ |
var $keywords = array ( |
'BLOB' => '', |
'BOOLEAN' => '', |
'CHARACTER' => '', |
'CLOB' => '', |
'FLOAT' => '', |
'INTEGER' => '', |
'KEY' => '', |
'NATIONAL' => '', |
'NUMERIC' => '', |
'NVARCHAR' => '', |
'PRIMARY' => '', |
'TEXT' => '', |
'TIMESTAMP' => '', |
'UNIQUE' => '', |
'VARCHAR' => '', |
'VARYING' => '', |
); |
/** |
* The most recent error message from $php_errormsg |
* @var string |
* @access private |
*/ |
var $_lasterror = ''; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_sqlite() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's sqlite driver supports the following extra DSN options: |
* + mode The permissions for the database file, in four digit |
* chmod octal format (eg "0600"). |
* |
* Example of connecting to a database in read-only mode: |
* <code> |
* require_once 'DB.php'; |
* |
* $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400'; |
* $options = array( |
* 'portability' => DB_PORTABILITY_ALL, |
* ); |
* |
* $db = DB::connect($dsn, $options); |
* if (PEAR::isError($db)) { |
* die($db->getMessage()); |
* } |
* </code> |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('sqlite')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
if (!$dsn['database']) { |
return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); |
} |
if ($dsn['database'] !== ':memory:') { |
if (!file_exists($dsn['database'])) { |
if (!touch($dsn['database'])) { |
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
} |
if (!isset($dsn['mode']) || |
!is_numeric($dsn['mode'])) |
{ |
$mode = 0644; |
} else { |
$mode = octdec($dsn['mode']); |
} |
if (!chmod($dsn['database'], $mode)) { |
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
} |
if (!file_exists($dsn['database'])) { |
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); |
} |
} |
if (!is_file($dsn['database'])) { |
return $this->sqliteRaiseError(DB_ERROR_INVALID); |
} |
if (!is_readable($dsn['database'])) { |
return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); |
} |
} |
$connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open'; |
// track_errors must remain on for simpleQuery() |
@ini_set('track_errors', 1); |
$php_errormsg = ''; |
if (!$this->connection = @$connect_function($dsn['database'])) { |
return $this->raiseError(DB_ERROR_NODBSELECTED, |
null, null, null, |
$php_errormsg); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @sqlite_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* NOTICE: This method needs PHP's track_errors ini setting to be on. |
* It is automatically turned on when connecting to the database. |
* Make sure your scripts don't turn it off. |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
$php_errormsg = ''; |
$result = @sqlite_query($query, $this->connection); |
$this->_lasterror = $php_errormsg ? $php_errormsg : ''; |
$this->result = $result; |
if (!$this->result) { |
return $this->sqliteRaiseError(null); |
} |
// sqlite_query() seems to allways return a resource |
// so cant use that. Using $ismanip instead |
if (!$ismanip) { |
$numRows = $this->numRows($result); |
if (is_object($numRows)) { |
// we've got PEAR_Error |
return $numRows; |
} |
return $result; |
} |
return DB_OK; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal sqlite result pointer to the next available result |
* |
* @param resource $result the valid sqlite result resource |
* |
* @return bool true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@sqlite_seek($this->result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @sqlite_fetch_array($result, SQLITE_ASSOC); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
/* Remove extraneous " characters from the fields in the result. |
* Fixes bug #11716. */ |
if (is_array($arr) && count($arr) > 0) { |
$strippedArr = array(); |
foreach ($arr as $field => $value) { |
$strippedArr[trim($field, '"')] = $value; |
} |
$arr = $strippedArr; |
} |
} else { |
$arr = @sqlite_fetch_array($result, SQLITE_NUM); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
/* |
* Even though this DBMS already trims output, we do this because |
* a field might have intentional whitespace at the end that |
* gets removed by DB_PORTABILITY_RTRIM under another driver. |
*/ |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult(&$result) |
{ |
// XXX No native free? |
if (!is_resource($result)) { |
return false; |
} |
$result = null; |
return true; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @sqlite_num_fields($result); |
if (!$cols) { |
return $this->sqliteRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @sqlite_num_rows($result); |
if ($rows === null) { |
return $this->sqliteRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ affected() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
return @sqlite_changes($this->connection); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_sqlite::nextID(), DB_sqlite::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_sqlite::nextID(), DB_sqlite::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$query = 'CREATE TABLE ' . $seqname . |
' (id INTEGER UNSIGNED PRIMARY KEY) '; |
$result = $this->query($query); |
if (DB::isError($result)) { |
return($result); |
} |
$query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname |
BEGIN |
DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID(); |
END "; |
$result = $this->query($query); |
if (DB::isError($result)) { |
return($result); |
} |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_sqlite::createSequence(), DB_sqlite::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
do { |
$repeat = 0; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)"); |
$this->popErrorHandling(); |
if ($result === DB_OK) { |
$id = @sqlite_last_insert_rowid($this->connection); |
if ($id != 0) { |
return $id; |
} |
} elseif ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) |
{ |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} else { |
$repeat = 1; |
} |
} |
} while ($repeat); |
return $this->raiseError($result); |
} |
// }}} |
// {{{ getDbFileStats() |
/** |
* Get the file stats for the current database |
* |
* Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size, |
* atime, mtime, ctime, blksize, blocks or a numeric key between |
* 0 and 12. |
* |
* @param string $arg the array key for stats() |
* |
* @return mixed an array on an unspecified key, integer on a passed |
* arg and false at a stats error |
*/ |
function getDbFileStats($arg = '') |
{ |
$stats = stat($this->dsn['database']); |
if ($stats == false) { |
return false; |
} |
if (is_array($stats)) { |
if (is_numeric($arg)) { |
if (((int)$arg <= 12) & ((int)$arg >= 0)) { |
return false; |
} |
return $stats[$arg ]; |
} |
if (array_key_exists(trim($arg), $stats)) { |
return $stats[$arg ]; |
} |
} |
return $stats; |
} |
// }}} |
// {{{ escapeSimple() |
/** |
* Escapes a string according to the current DBMS's standards |
* |
* In SQLite, this makes things safe for inserts/updates, but may |
* cause problems when performing text comparisons against columns |
* containing binary data. See the |
* {@link http://php.net/sqlite_escape_string PHP manual} for more info. |
* |
* @param string $str the string to be escaped |
* |
* @return string the escaped string |
* |
* @since Method available since Release 1.6.1 |
* @see DB_common::escapeSimple() |
*/ |
function escapeSimple($str) |
{ |
return @sqlite_escape_string($str); |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
return "$query LIMIT $count OFFSET $from"; |
} |
// }}} |
// {{{ modifyQuery() |
/** |
* Changes a query string for various DBMS specific reasons |
* |
* This little hack lets you know how many rows were deleted |
* when running a "DELETE FROM table" query. Only implemented |
* if the DB_PORTABILITY_DELETE_COUNT portability option is on. |
* |
* @param string $query the query string to modify |
* |
* @return string the modified query string |
* |
* @access protected |
* @see DB_common::setOption() |
*/ |
function modifyQuery($query) |
{ |
if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { |
if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { |
$query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', |
'DELETE FROM \1 WHERE 1=1', $query); |
} |
} |
return $query; |
} |
// }}} |
// {{{ sqliteRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_sqlite::errorNative(), DB_sqlite::errorCode() |
*/ |
function sqliteRaiseError($errno = null) |
{ |
$native = $this->errorNative(); |
if ($errno === null) { |
$errno = $this->errorCode($native); |
} |
$errorcode = @sqlite_last_error($this->connection); |
$userinfo = "$errorcode ** $this->last_query"; |
return $this->raiseError($errno, null, null, $userinfo, $native); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error message produced by the last query |
* |
* {@internal This is used to retrieve more meaningfull error messages |
* because sqlite_last_error() does not provide adequate info.}} |
* |
* @return string the DBMS' error message |
*/ |
function errorNative() |
{ |
return $this->_lasterror; |
} |
// }}} |
// {{{ errorCode() |
/** |
* Determines PEAR::DB error code from the database's text error message |
* |
* @param string $errormsg the error message returned from the database |
* |
* @return integer the DB error number |
*/ |
function errorCode($errormsg) |
{ |
static $error_regexps; |
// PHP 5.2+ prepends the function name to $php_errormsg, so we need |
// this hack to work around it, per bug #9599. |
$errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg); |
if (!isset($error_regexps)) { |
$error_regexps = array( |
'/^no such table:/' => DB_ERROR_NOSUCHTABLE, |
'/^no such index:/' => DB_ERROR_NOT_FOUND, |
'/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS, |
'/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT, |
'/is not unique/' => DB_ERROR_CONSTRAINT, |
'/columns .* are not unique/i' => DB_ERROR_CONSTRAINT, |
'/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT, |
'/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL, |
'/^no such column:/' => DB_ERROR_NOSUCHFIELD, |
'/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD, |
'/^near ".*": syntax error$/' => DB_ERROR_SYNTAX, |
'/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW, |
); |
} |
foreach ($error_regexps as $regexp => $code) { |
if (preg_match($regexp, $errormsg)) { |
return $code; |
} |
} |
// Fall back to DB_ERROR if there was no mapping. |
return DB_ERROR; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table |
* |
* @param string $result a string containing the name of a table |
* @param int $mode a valid tableInfo mode |
* |
* @return array an associative array with the information requested. |
* A DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
* @since Method available since Release 1.7.0 |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @sqlite_array_query($this->connection, |
"PRAGMA table_info('$result');", |
SQLITE_ASSOC); |
$got_string = true; |
} else { |
$this->last_query = ''; |
return $this->raiseError(DB_ERROR_NOT_CAPABLE, null, null, null, |
'This DBMS can not obtain tableInfo' . |
' from result sets'); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = count($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
if (strpos($id[$i]['type'], '(') !== false) { |
$bits = explode('(', $id[$i]['type']); |
$type = $bits[0]; |
$len = rtrim($bits[1],')'); |
} else { |
$type = $id[$i]['type']; |
$len = 0; |
} |
$flags = ''; |
if ($id[$i]['pk']) { |
$flags .= 'primary_key '; |
} |
if ($id[$i]['notnull']) { |
$flags .= 'not_null '; |
} |
if ($id[$i]['dflt_value'] !== null) { |
$flags .= 'default_' . rawurlencode($id[$i]['dflt_value']); |
} |
$flags = trim($flags); |
$res[$i] = array( |
'table' => $case_func($result), |
'name' => $case_func($id[$i]['name']), |
'type' => $type, |
'len' => $len, |
'flags' => $flags, |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* @param array $args SQLITE DRIVER ONLY: a private array of arguments |
* used by the getSpecialQuery(). Do not use |
* this directly. |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type, $args = array()) |
{ |
if (!is_array($args)) { |
return $this->raiseError('no key specified', null, null, null, |
'Argument has to be an array.'); |
} |
switch ($type) { |
case 'master': |
return 'SELECT * FROM sqlite_master;'; |
case 'tables': |
return "SELECT name FROM sqlite_master WHERE type='table' " |
. 'UNION ALL SELECT name FROM sqlite_temp_master ' |
. "WHERE type='table' ORDER BY name;"; |
case 'schema': |
return 'SELECT sql FROM (SELECT * FROM sqlite_master ' |
. 'UNION ALL SELECT * FROM sqlite_temp_master) ' |
. "WHERE type!='meta' " |
. 'ORDER BY tbl_name, type DESC, name;'; |
case 'schemax': |
case 'schema_x': |
/* |
* Use like: |
* $res = $db->query($db->getSpecialQuery('schema_x', |
* array('table' => 'table3'))); |
*/ |
return 'SELECT sql FROM (SELECT * FROM sqlite_master ' |
. 'UNION ALL SELECT * FROM sqlite_temp_master) ' |
. "WHERE tbl_name LIKE '{$args['table']}' " |
. "AND type!='meta' " |
. 'ORDER BY type DESC, name;'; |
case 'alter': |
/* |
* SQLite does not support ALTER TABLE; this is a helper query |
* to handle this. 'table' represents the table name, 'rows' |
* the news rows to create, 'save' the row(s) to keep _with_ |
* the data. |
* |
* Use like: |
* $args = array( |
* 'table' => $table, |
* 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT", |
* 'save' => "NULL, titel, content, datetime" |
* ); |
* $res = $db->query( $db->getSpecialQuery('alter', $args)); |
*/ |
$rows = strtr($args['rows'], $this->keywords); |
$q = array( |
'BEGIN TRANSACTION', |
"CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})", |
"INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}", |
"DROP TABLE {$args['table']}", |
"CREATE TABLE {$args['table']} ({$args['rows']})", |
"INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup", |
"DROP TABLE {$args['table']}_backup", |
'COMMIT', |
); |
/* |
* This is a dirty hack, since the above query will not get |
* executed with a single query call so here the query method |
* will be called directly and return a select instead. |
*/ |
foreach ($q as $query) { |
$this->query($query); |
} |
return "SELECT * FROM {$args['table']};"; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/oci8.php |
---|
Новый файл |
0,0 → 1,1156 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's oci8 extension |
* for interacting with Oracle databases |
* |
* 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 James L. Pine <jlp@valinux.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: oci8.php,v 1.115 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's oci8 extension |
* for interacting with Oracle databases |
* |
* Definitely works with versions 8 and 9 of Oracle. |
* |
* These methods overload the ones declared in DB_common. |
* |
* Be aware... OCIError() only appears to return anything when given a |
* statement, so functions return the generic DB_ERROR instead of more |
* useful errors that have to do with feedback from the database. |
* |
* @category Database |
* @package DB |
* @author James L. Pine <jlp@valinux.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_oci8 extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'oci8'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'oci8'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'alter', |
'new_link' => '5.0.0', |
'numrows' => 'subquery', |
'pconnect' => true, |
'prepare' => true, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
1 => DB_ERROR_CONSTRAINT, |
900 => DB_ERROR_SYNTAX, |
904 => DB_ERROR_NOSUCHFIELD, |
913 => DB_ERROR_VALUE_COUNT_ON_ROW, |
921 => DB_ERROR_SYNTAX, |
923 => DB_ERROR_SYNTAX, |
942 => DB_ERROR_NOSUCHTABLE, |
955 => DB_ERROR_ALREADY_EXISTS, |
1400 => DB_ERROR_CONSTRAINT_NOT_NULL, |
1401 => DB_ERROR_INVALID, |
1407 => DB_ERROR_CONSTRAINT_NOT_NULL, |
1418 => DB_ERROR_NOT_FOUND, |
1476 => DB_ERROR_DIVZERO, |
1722 => DB_ERROR_INVALID_NUMBER, |
2289 => DB_ERROR_NOSUCHTABLE, |
2291 => DB_ERROR_CONSTRAINT, |
2292 => DB_ERROR_CONSTRAINT, |
2449 => DB_ERROR_CONSTRAINT, |
12899 => DB_ERROR_INVALID, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* Stores the $data passed to execute() in the oci8 driver |
* |
* Gets reset to array() when simpleQuery() is run. |
* |
* Needed in case user wants to call numRows() after prepare/execute |
* was used. |
* |
* @var array |
* @access private |
*/ |
var $_data = array(); |
/** |
* The result or statement handle from the most recently executed query |
* @var resource |
*/ |
var $last_stmt; |
/** |
* Is the given prepared statement a data manipulation query? |
* @var array |
* @access private |
*/ |
var $manip_query = array(); |
/** |
* Store of prepared SQL queries. |
* @var array |
* @access private |
*/ |
var $_prepared_queries = array(); |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_oci8() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* If PHP is at version 5.0.0 or greater: |
* + Generally, oci_connect() or oci_pconnect() are used. |
* + But if the new_link DSN option is set to true, oci_new_connect() |
* is used. |
* |
* When using PHP version 4.x, OCILogon() or OCIPLogon() are used. |
* |
* PEAR DB's oci8 driver supports the following extra DSN options: |
* + charset The character set to be used on the connection. |
* Only used if PHP is at version 5.0.0 or greater |
* and the Oracle server is at 9.2 or greater. |
* Available since PEAR DB 1.7.0. |
* + new_link If set to true, causes subsequent calls to |
* connect() to return a new connection link |
* instead of the existing one. WARNING: this is |
* not portable to other DBMS's. |
* Available since PEAR DB 1.7.0. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('oci8')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
// Backwards compatibility with DB < 1.7.0 |
if (empty($dsn['database']) && !empty($dsn['hostspec'])) { |
$db = $dsn['hostspec']; |
} else { |
$db = $dsn['database']; |
} |
if (function_exists('oci_connect')) { |
if (isset($dsn['new_link']) |
&& ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) |
{ |
$connect_function = 'oci_new_connect'; |
} else { |
$connect_function = $persistent ? 'oci_pconnect' |
: 'oci_connect'; |
} |
if (isset($this->dsn['port']) && $this->dsn['port']) { |
$db = '//'.$db.':'.$this->dsn['port']; |
} |
$char = empty($dsn['charset']) ? null : $dsn['charset']; |
$this->connection = @$connect_function($dsn['username'], |
$dsn['password'], |
$db, |
$char); |
$error = OCIError(); |
if (!empty($error) && $error['code'] == 12541) { |
// Couldn't find TNS listener. Try direct connection. |
$this->connection = @$connect_function($dsn['username'], |
$dsn['password'], |
null, |
$char); |
} |
} else { |
$connect_function = $persistent ? 'OCIPLogon' : 'OCILogon'; |
if ($db) { |
$this->connection = @$connect_function($dsn['username'], |
$dsn['password'], |
$db); |
} elseif ($dsn['username'] || $dsn['password']) { |
$this->connection = @$connect_function($dsn['username'], |
$dsn['password']); |
} |
} |
if (!$this->connection) { |
$error = OCIError(); |
$error = (is_array($error)) ? $error['message'] : null; |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$error); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
if (function_exists('oci_close')) { |
$ret = @oci_close($this->connection); |
} else { |
$ret = @OCILogOff($this->connection); |
} |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* To determine how many rows of a result set get buffered using |
* ocisetprefetch(), see the "result_buffering" option in setOptions(). |
* This option was added in Release 1.7.0. |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$this->_data = array(); |
$this->last_parameters = array(); |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
$result = @OCIParse($this->connection, $query); |
if (!$result) { |
return $this->oci8RaiseError(); |
} |
if ($this->autocommit) { |
$success = @OCIExecute($result,OCI_COMMIT_ON_SUCCESS); |
} else { |
$success = @OCIExecute($result,OCI_DEFAULT); |
} |
if (!$success) { |
return $this->oci8RaiseError($result); |
} |
$this->last_stmt = $result; |
if ($this->_checkManip($query)) { |
return DB_OK; |
} else { |
@ocisetprefetch($result, $this->options['result_buffering']); |
return $result; |
} |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal oracle result pointer to the next available result |
* |
* @param a valid oci8 result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$moredata = @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && |
$moredata) |
{ |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$moredata = OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS); |
} |
if (!$moredata) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? OCIFreeStatement($result) : false; |
} |
/** |
* Frees the internal resources associated with a prepared query |
* |
* @param resource $stmt the prepared statement's resource |
* @param bool $free_resource should the PHP resource be freed too? |
* Use false if you need to get data |
* from the result set later. |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_oci8::prepare() |
*/ |
function freePrepared($stmt, $free_resource = true) |
{ |
if (!is_resource($stmt)) { |
return false; |
} |
if ($free_resource) { |
@ocifreestatement($stmt); |
} |
if (isset($this->prepare_types[(int)$stmt])) { |
unset($this->prepare_types[(int)$stmt]); |
unset($this->manip_query[(int)$stmt]); |
} else { |
return false; |
} |
return true; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* Only works if the DB_PORTABILITY_NUMROWS portability option |
* is turned on. |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows(), DB_common::setOption() |
*/ |
function numRows($result) |
{ |
// emulate numRows for Oracle. yuck. |
if ($this->options['portability'] & DB_PORTABILITY_NUMROWS && |
$result === $this->last_stmt) |
{ |
$countquery = 'SELECT COUNT(*) FROM ('.$this->last_query.')'; |
$save_query = $this->last_query; |
$save_stmt = $this->last_stmt; |
$count = $this->query($countquery); |
// Restore the last query and statement. |
$this->last_query = $save_query; |
$this->last_stmt = $save_stmt; |
if (DB::isError($count) || |
DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED))) |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
return $row[0]; |
} |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @OCINumCols($result); |
if (!$cols) { |
return $this->oci8RaiseError($result); |
} |
return $cols; |
} |
// }}} |
// {{{ prepare() |
/** |
* Prepares a query for multiple execution with execute(). |
* |
* With oci8, this is emulated. |
* |
* prepare() requires a generic query as string like <code> |
* INSERT INTO numbers VALUES (?, ?, ?) |
* </code>. The <kbd>?</kbd> characters are placeholders. |
* |
* Three types of placeholders can be used: |
* + <kbd>?</kbd> a quoted scalar value, i.e. strings, integers |
* + <kbd>!</kbd> value is inserted 'as is' |
* + <kbd>&</kbd> requires a file name. The file's contents get |
* inserted into the query (i.e. saving binary |
* data in a db) |
* |
* Use backslashes to escape placeholder characters if you don't want |
* them to be interpreted as placeholders. Example: <code> |
* "UPDATE foo SET col=? WHERE col='over \& under'" |
* </code> |
* |
* @param string $query the query to be prepared |
* |
* @return mixed DB statement resource on success. DB_Error on failure. |
* |
* @see DB_oci8::execute() |
*/ |
function prepare($query) |
{ |
$tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, |
PREG_SPLIT_DELIM_CAPTURE); |
$binds = count($tokens) - 1; |
$token = 0; |
$types = array(); |
$newquery = ''; |
foreach ($tokens as $key => $val) { |
switch ($val) { |
case '?': |
$types[$token++] = DB_PARAM_SCALAR; |
unset($tokens[$key]); |
break; |
case '&': |
$types[$token++] = DB_PARAM_OPAQUE; |
unset($tokens[$key]); |
break; |
case '!': |
$types[$token++] = DB_PARAM_MISC; |
unset($tokens[$key]); |
break; |
default: |
$tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val); |
if ($key != $binds) { |
$newquery .= $tokens[$key] . ':bind' . $token; |
} else { |
$newquery .= $tokens[$key]; |
} |
} |
} |
$this->last_query = $query; |
$newquery = $this->modifyQuery($newquery); |
if (!$stmt = @OCIParse($this->connection, $newquery)) { |
return $this->oci8RaiseError(); |
} |
$this->prepare_types[(int)$stmt] = $types; |
$this->manip_query[(int)$stmt] = DB::isManip($query); |
$this->_prepared_queries[(int)$stmt] = $newquery; |
return $stmt; |
} |
// }}} |
// {{{ execute() |
/** |
* Executes a DB statement prepared with prepare(). |
* |
* To determine how many rows of a result set get buffered using |
* ocisetprefetch(), see the "result_buffering" option in setOptions(). |
* This option was added in Release 1.7.0. |
* |
* @param resource $stmt a DB statement resource returned from prepare() |
* @param mixed $data array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 for non-array items or the |
* quantity of elements in the array. |
* |
* @return mixed returns an oic8 result resource for successful SELECT |
* queries, DB_OK for other successful queries. |
* A DB error object is returned on failure. |
* |
* @see DB_oci8::prepare() |
*/ |
function &execute($stmt, $data = array()) |
{ |
$data = (array)$data; |
$this->last_parameters = $data; |
$this->last_query = $this->_prepared_queries[(int)$stmt]; |
$this->_data = $data; |
$types = $this->prepare_types[(int)$stmt]; |
if (count($types) != count($data)) { |
$tmp = $this->raiseError(DB_ERROR_MISMATCH); |
return $tmp; |
} |
$i = 0; |
foreach ($data as $key => $value) { |
if ($types[$i] == DB_PARAM_MISC) { |
/* |
* Oracle doesn't seem to have the ability to pass a |
* parameter along unchanged, so strip off quotes from start |
* and end, plus turn two single quotes to one single quote, |
* in order to avoid the quotes getting escaped by |
* Oracle and ending up in the database. |
*/ |
$data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]); |
$data[$key] = str_replace("''", "'", $data[$key]); |
} elseif ($types[$i] == DB_PARAM_OPAQUE) { |
$fp = @fopen($data[$key], 'rb'); |
if (!$fp) { |
$tmp = $this->raiseError(DB_ERROR_ACCESS_VIOLATION); |
return $tmp; |
} |
$data[$key] = fread($fp, filesize($data[$key])); |
fclose($fp); |
} elseif ($types[$i] == DB_PARAM_SCALAR) { |
// Floats have to be converted to a locale-neutral |
// representation. |
if (is_float($data[$key])) { |
$data[$key] = $this->quoteFloat($data[$key]); |
} |
} |
if (!@OCIBindByName($stmt, ':bind' . $i, $data[$key], -1)) { |
$tmp = $this->oci8RaiseError($stmt); |
return $tmp; |
} |
$this->last_query = str_replace(':bind'.$i, $this->quoteSmart($data[$key]), $this->last_query); |
$i++; |
} |
if ($this->autocommit) { |
$success = @OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS); |
} else { |
$success = @OCIExecute($stmt, OCI_DEFAULT); |
} |
if (!$success) { |
$tmp = $this->oci8RaiseError($stmt); |
return $tmp; |
} |
$this->last_stmt = $stmt; |
if ($this->manip_query[(int)$stmt] || $this->_next_query_manip) { |
$this->_last_query_manip = true; |
$this->_next_query_manip = false; |
$tmp = DB_OK; |
} else { |
$this->_last_query_manip = false; |
@ocisetprefetch($stmt, $this->options['result_buffering']); |
$tmp = new DB_result($this, $stmt); |
} |
return $tmp; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
$this->autocommit = (bool)$onoff;; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
$result = @OCICommit($this->connection); |
if (!$result) { |
return $this->oci8RaiseError(); |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
$result = @OCIRollback($this->connection); |
if (!$result) { |
return $this->oci8RaiseError(); |
} |
return DB_OK; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->last_stmt === false) { |
return $this->oci8RaiseError(); |
} |
$result = @OCIRowCount($this->last_stmt); |
if ($result === false) { |
return $this->oci8RaiseError($this->last_stmt); |
} |
return $result; |
} |
// }}} |
// {{{ modifyQuery() |
/** |
* Changes a query string for various DBMS specific reasons |
* |
* "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle. |
* |
* @param string $query the query string to modify |
* |
* @return string the modified query string |
* |
* @access protected |
*/ |
function modifyQuery($query) |
{ |
if (preg_match('/^\s*SELECT/i', $query) && |
!preg_match('/\sFROM\s/i', $query)) { |
$query .= ' FROM dual'; |
} |
return $query; |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
// Let Oracle return the name of the columns instead of |
// coding a "home" SQL parser |
if (count($params)) { |
$result = $this->prepare("SELECT * FROM ($query) " |
. 'WHERE NULL = NULL'); |
$tmp = $this->execute($result, $params); |
} else { |
$q_fields = "SELECT * FROM ($query) WHERE NULL = NULL"; |
if (!$result = @OCIParse($this->connection, $q_fields)) { |
$this->last_query = $q_fields; |
return $this->oci8RaiseError(); |
} |
if (!@OCIExecute($result, OCI_DEFAULT)) { |
$this->last_query = $q_fields; |
return $this->oci8RaiseError($result); |
} |
} |
$ncols = OCINumCols($result); |
$cols = array(); |
for ( $i = 1; $i <= $ncols; $i++ ) { |
$cols[] = '"' . OCIColumnName($result, $i) . '"'; |
} |
$fields = implode(', ', $cols); |
// XXX Test that (tip by John Lim) |
//if (preg_match('/^\s*SELECT\s+/is', $query, $match)) { |
// // Introduce the FIRST_ROWS Oracle query optimizer |
// $query = substr($query, strlen($match[0]), strlen($query)); |
// $query = "SELECT /* +FIRST_ROWS */ " . $query; |
//} |
// Construct the query |
// more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2 |
// Perhaps this could be optimized with the use of Unions |
$query = "SELECT $fields FROM". |
" (SELECT rownum as linenum, $fields FROM". |
" ($query)". |
' WHERE rownum <= '. ($from + $count) . |
') WHERE linenum >= ' . ++$from; |
return $query; |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_oci8::createSequence(), DB_oci8::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$repeat = 0; |
do { |
$this->expectError(DB_ERROR_NOSUCHTABLE); |
$result = $this->query("SELECT ${seqname}.nextval FROM dual"); |
$this->popExpect(); |
if ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) { |
$repeat = 1; |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
} else { |
$repeat = 0; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED); |
return $arr[0]; |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_oci8::nextID(), DB_oci8::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
return $this->query('CREATE SEQUENCE ' |
. $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_oci8::nextID(), DB_oci8::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP SEQUENCE ' |
. $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ oci8RaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_oci8::errorNative(), DB_oci8::errorCode() |
*/ |
function oci8RaiseError($errno = null) |
{ |
if ($errno === null) { |
$error = @OCIError($this->connection); |
return $this->raiseError($this->errorCode($error['code']), |
null, null, null, $error['message']); |
} elseif (is_resource($errno)) { |
$error = @OCIError($errno); |
return $this->raiseError($this->errorCode($error['code']), |
null, null, null, $error['message']); |
} |
return $this->raiseError($this->errorCode($errno)); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return int the DBMS' error code. FALSE if the code could not be |
* determined |
*/ |
function errorNative() |
{ |
if (is_resource($this->last_stmt)) { |
$error = @OCIError($this->last_stmt); |
} else { |
$error = @OCIError($this->connection); |
} |
if (is_array($error)) { |
return $error['code']; |
} |
return false; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* NOTE: only supports 'table' and 'flags' if <var>$result</var> |
* is a table name. |
* |
* NOTE: flags won't contain index information. |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$res = array(); |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$result = strtoupper($result); |
$q_fields = 'SELECT column_name, data_type, data_length, ' |
. 'nullable ' |
. 'FROM user_tab_columns ' |
. "WHERE table_name='$result' ORDER BY column_id"; |
$this->last_query = $q_fields; |
if (!$stmt = @OCIParse($this->connection, $q_fields)) { |
return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if (!@OCIExecute($stmt, OCI_DEFAULT)) { |
return $this->oci8RaiseError($stmt); |
} |
$i = 0; |
while (@OCIFetch($stmt)) { |
$res[$i] = array( |
'table' => $case_func($result), |
'name' => $case_func(@OCIResult($stmt, 1)), |
'type' => @OCIResult($stmt, 2), |
'len' => @OCIResult($stmt, 3), |
'flags' => (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '', |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
$i++; |
} |
if ($mode) { |
$res['num_fields'] = $i; |
} |
@OCIFreeStatement($stmt); |
} else { |
if (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$result = $result->result; |
} |
$res = array(); |
if ($result === $this->last_stmt) { |
$count = @OCINumCols($result); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$res[$i] = array( |
'table' => '', |
'name' => $case_func(@OCIColumnName($result, $i+1)), |
'type' => @OCIColumnType($result, $i+1), |
'len' => @OCIColumnSize($result, $i+1), |
'flags' => '', |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
} else { |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SELECT table_name FROM user_tables'; |
case 'synonyms': |
return 'SELECT synonym_name FROM user_synonyms'; |
case 'views': |
return 'SELECT view_name FROM user_views'; |
default: |
return null; |
} |
} |
// }}} |
// {{{ quoteFloat() |
/** |
* Formats a float value for use within a query in a locale-independent |
* manner. |
* |
* @param float the float value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteFloat($float) { |
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/ibase.php |
---|
Новый файл |
0,0 → 1,1082 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's interbase extension |
* for interacting with Interbase and Firebird databases |
* |
* While this class works with PHP 4, PHP's InterBase extension is |
* unstable in PHP 4. Use PHP 5. |
* |
* 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 Sterling Hughes <sterling@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: ibase.php,v 1.116 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's interbase extension |
* for interacting with Interbase and Firebird databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* While this class works with PHP 4, PHP's InterBase extension is |
* unstable in PHP 4. Use PHP 5. |
* |
* NOTICE: limitQuery() only works for Firebird. |
* |
* @category Database |
* @package DB |
* @author Sterling Hughes <sterling@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
* @since Class became stable in Release 1.7.0 |
*/ |
class DB_ibase extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'ibase'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'ibase'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* NOTE: only firebird supports limit. |
* |
* @var array |
*/ |
var $features = array( |
'limit' => false, |
'new_link' => false, |
'numrows' => 'emulate', |
'pconnect' => true, |
'prepare' => true, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
-104 => DB_ERROR_SYNTAX, |
-150 => DB_ERROR_ACCESS_VIOLATION, |
-151 => DB_ERROR_ACCESS_VIOLATION, |
-155 => DB_ERROR_NOSUCHTABLE, |
-157 => DB_ERROR_NOSUCHFIELD, |
-158 => DB_ERROR_VALUE_COUNT_ON_ROW, |
-170 => DB_ERROR_MISMATCH, |
-171 => DB_ERROR_MISMATCH, |
-172 => DB_ERROR_INVALID, |
// -204 => // Covers too many errors, need to use regex on msg |
-205 => DB_ERROR_NOSUCHFIELD, |
-206 => DB_ERROR_NOSUCHFIELD, |
-208 => DB_ERROR_INVALID, |
-219 => DB_ERROR_NOSUCHTABLE, |
-297 => DB_ERROR_CONSTRAINT, |
-303 => DB_ERROR_INVALID, |
-413 => DB_ERROR_INVALID_NUMBER, |
-530 => DB_ERROR_CONSTRAINT, |
-551 => DB_ERROR_ACCESS_VIOLATION, |
-552 => DB_ERROR_ACCESS_VIOLATION, |
// -607 => // Covers too many errors, need to use regex on msg |
-625 => DB_ERROR_CONSTRAINT_NOT_NULL, |
-803 => DB_ERROR_CONSTRAINT, |
-804 => DB_ERROR_VALUE_COUNT_ON_ROW, |
// -902 => // Covers too many errors, need to use regex on msg |
-904 => DB_ERROR_CONNECT_FAILED, |
-922 => DB_ERROR_NOSUCHDB, |
-923 => DB_ERROR_CONNECT_FAILED, |
-924 => DB_ERROR_CONNECT_FAILED |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* The number of rows affected by a data manipulation query |
* @var integer |
* @access private |
*/ |
var $affected = 0; |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The prepared statement handle from the most recently executed statement |
* |
* {@internal Mainly here because the InterBase/Firebird API is only |
* able to retrieve data from result sets if the statemnt handle is |
* still in scope.}} |
* |
* @var resource |
*/ |
var $last_stmt; |
/** |
* Is the given prepared statement a data manipulation query? |
* @var array |
* @access private |
*/ |
var $manip_query = array(); |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_ibase() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's ibase driver supports the following extra DSN options: |
* + buffers The number of database buffers to allocate for the |
* server-side cache. |
* + charset The default character set for a database. |
* + dialect The default SQL dialect for any statement |
* executed within a connection. Defaults to the |
* highest one supported by client libraries. |
* Functional only with InterBase 6 and up. |
* + role Functional only with InterBase 5 and up. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('interbase')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
if ($this->dbsyntax == 'firebird') { |
$this->features['limit'] = 'alter'; |
} |
$params = array( |
$dsn['hostspec'] |
? ($dsn['hostspec'] . ':' . $dsn['database']) |
: $dsn['database'], |
$dsn['username'] ? $dsn['username'] : null, |
$dsn['password'] ? $dsn['password'] : null, |
isset($dsn['charset']) ? $dsn['charset'] : null, |
isset($dsn['buffers']) ? $dsn['buffers'] : null, |
isset($dsn['dialect']) ? $dsn['dialect'] : null, |
isset($dsn['role']) ? $dsn['role'] : null, |
); |
$connect_function = $persistent ? 'ibase_pconnect' : 'ibase_connect'; |
$this->connection = @call_user_func_array($connect_function, $params); |
if (!$this->connection) { |
return $this->ibaseRaiseError(DB_ERROR_CONNECT_FAILED); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @ibase_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
$result = @ibase_query($this->connection, $query); |
if (!$result) { |
return $this->ibaseRaiseError(); |
} |
if ($this->autocommit && $ismanip) { |
@ibase_commit($this->connection); |
} |
if ($ismanip) { |
$this->affected = $result; |
return DB_OK; |
} else { |
$this->affected = 0; |
return $result; |
} |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* Only works with Firebird. |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
if ($this->dsn['dbsyntax'] == 'firebird') { |
$query = preg_replace('/^([\s(])*SELECT/i', |
"SELECT FIRST $count SKIP $from", $query); |
} |
return $query; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal ibase result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE); |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
if (function_exists('ibase_fetch_assoc')) { |
$arr = @ibase_fetch_assoc($result); |
} else { |
$arr = get_object_vars(ibase_fetch_object($result)); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @ibase_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? ibase_free_result($result) : false; |
} |
// }}} |
// {{{ freeQuery() |
function freeQuery($query) |
{ |
return is_resource($query) ? ibase_free_query($query) : false; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if (is_integer($this->affected)) { |
return $this->affected; |
} |
return $this->ibaseRaiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @ibase_num_fields($result); |
if (!$cols) { |
return $this->ibaseRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ prepare() |
/** |
* Prepares a query for multiple execution with execute(). |
* |
* prepare() requires a generic query as string like <code> |
* INSERT INTO numbers VALUES (?, ?, ?) |
* </code>. The <kbd>?</kbd> characters are placeholders. |
* |
* Three types of placeholders can be used: |
* + <kbd>?</kbd> a quoted scalar value, i.e. strings, integers |
* + <kbd>!</kbd> value is inserted 'as is' |
* + <kbd>&</kbd> requires a file name. The file's contents get |
* inserted into the query (i.e. saving binary |
* data in a db) |
* |
* Use backslashes to escape placeholder characters if you don't want |
* them to be interpreted as placeholders. Example: <code> |
* "UPDATE foo SET col=? WHERE col='over \& under'" |
* </code> |
* |
* @param string $query query to be prepared |
* @return mixed DB statement resource on success. DB_Error on failure. |
*/ |
function prepare($query) |
{ |
$tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, |
PREG_SPLIT_DELIM_CAPTURE); |
$token = 0; |
$types = array(); |
$newquery = ''; |
foreach ($tokens as $key => $val) { |
switch ($val) { |
case '?': |
$types[$token++] = DB_PARAM_SCALAR; |
break; |
case '&': |
$types[$token++] = DB_PARAM_OPAQUE; |
break; |
case '!': |
$types[$token++] = DB_PARAM_MISC; |
break; |
default: |
$tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val); |
$newquery .= $tokens[$key] . '?'; |
} |
} |
$newquery = substr($newquery, 0, -1); |
$this->last_query = $query; |
$newquery = $this->modifyQuery($newquery); |
$stmt = @ibase_prepare($this->connection, $newquery); |
if ($stmt === false) { |
$stmt = $this->ibaseRaiseError(); |
} else { |
$this->prepare_types[(int)$stmt] = $types; |
$this->manip_query[(int)$stmt] = DB::isManip($query); |
} |
return $stmt; |
} |
// }}} |
// {{{ execute() |
/** |
* Executes a DB statement prepared with prepare(). |
* |
* @param resource $stmt a DB statement resource returned from prepare() |
* @param mixed $data array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 for non-array items or the |
* quantity of elements in the array. |
* @return object a new DB_Result or a DB_Error when fail |
* @see DB_ibase::prepare() |
* @access public |
*/ |
function &execute($stmt, $data = array()) |
{ |
$data = (array)$data; |
$this->last_parameters = $data; |
$types = $this->prepare_types[(int)$stmt]; |
if (count($types) != count($data)) { |
$tmp = $this->raiseError(DB_ERROR_MISMATCH); |
return $tmp; |
} |
$i = 0; |
foreach ($data as $key => $value) { |
if ($types[$i] == DB_PARAM_MISC) { |
/* |
* ibase doesn't seem to have the ability to pass a |
* parameter along unchanged, so strip off quotes from start |
* and end, plus turn two single quotes to one single quote, |
* in order to avoid the quotes getting escaped by |
* ibase and ending up in the database. |
*/ |
$data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]); |
$data[$key] = str_replace("''", "'", $data[$key]); |
} elseif ($types[$i] == DB_PARAM_OPAQUE) { |
$fp = @fopen($data[$key], 'rb'); |
if (!$fp) { |
$tmp = $this->raiseError(DB_ERROR_ACCESS_VIOLATION); |
return $tmp; |
} |
$data[$key] = fread($fp, filesize($data[$key])); |
fclose($fp); |
} |
$i++; |
} |
array_unshift($data, $stmt); |
$res = call_user_func_array('ibase_execute', $data); |
if (!$res) { |
$tmp = $this->ibaseRaiseError(); |
return $tmp; |
} |
/* XXX need this? |
if ($this->autocommit && $this->manip_query[(int)$stmt]) { |
@ibase_commit($this->connection); |
}*/ |
$this->last_stmt = $stmt; |
if ($this->manip_query[(int)$stmt] || $this->_next_query_manip) { |
$this->_last_query_manip = true; |
$this->_next_query_manip = false; |
$tmp = DB_OK; |
} else { |
$this->_last_query_manip = false; |
$tmp = new DB_result($this, $res); |
} |
return $tmp; |
} |
/** |
* Frees the internal resources associated with a prepared query |
* |
* @param resource $stmt the prepared statement's PHP resource |
* @param bool $free_resource should the PHP resource be freed too? |
* Use false if you need to get data |
* from the result set later. |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_ibase::prepare() |
*/ |
function freePrepared($stmt, $free_resource = true) |
{ |
if (!is_resource($stmt)) { |
return false; |
} |
if ($free_resource) { |
@ibase_free_query($stmt); |
} |
unset($this->prepare_tokens[(int)$stmt]); |
unset($this->prepare_types[(int)$stmt]); |
unset($this->manip_query[(int)$stmt]); |
return true; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
$this->autocommit = $onoff ? 1 : 0; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
return @ibase_commit($this->connection); |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
return @ibase_rollback($this->connection); |
} |
// }}} |
// {{{ transactionInit() |
function transactionInit($trans_args = 0) |
{ |
return $trans_args |
? @ibase_trans($trans_args, $this->connection) |
: @ibase_trans(); |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_ibase::createSequence(), DB_ibase::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$sqn = strtoupper($this->getSequenceName($seq_name)); |
$repeat = 0; |
do { |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("SELECT GEN_ID(${sqn}, 1) " |
. 'FROM RDB$GENERATORS ' |
. "WHERE RDB\$GENERATOR_NAME='${sqn}'"); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result)) { |
$repeat = 1; |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $result; |
} |
} else { |
$repeat = 0; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED); |
$result->free(); |
return $arr[0]; |
} |
// }}} |
// {{{ createSequence() |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_ibase::nextID(), DB_ibase::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$sqn = strtoupper($this->getSequenceName($seq_name)); |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("CREATE GENERATOR ${sqn}"); |
$this->popErrorHandling(); |
return $result; |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_ibase::nextID(), DB_ibase::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DELETE FROM RDB$GENERATORS ' |
. "WHERE RDB\$GENERATOR_NAME='" |
. strtoupper($this->getSequenceName($seq_name)) |
. "'"); |
} |
// }}} |
// {{{ _ibaseFieldFlags() |
/** |
* Get the column's flags |
* |
* Supports "primary_key", "unique_key", "not_null", "default", |
* "computed" and "blob". |
* |
* @param string $field_name the name of the field |
* @param string $table_name the name of the table |
* |
* @return string the flags |
* |
* @access private |
*/ |
function _ibaseFieldFlags($field_name, $table_name) |
{ |
$sql = 'SELECT R.RDB$CONSTRAINT_TYPE CTYPE' |
.' FROM RDB$INDEX_SEGMENTS I' |
.' JOIN RDB$RELATION_CONSTRAINTS R ON I.RDB$INDEX_NAME=R.RDB$INDEX_NAME' |
.' WHERE I.RDB$FIELD_NAME=\'' . $field_name . '\'' |
.' AND UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\''; |
$result = @ibase_query($this->connection, $sql); |
if (!$result) { |
return $this->ibaseRaiseError(); |
} |
$flags = ''; |
if ($obj = @ibase_fetch_object($result)) { |
@ibase_free_result($result); |
if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'PRIMARY KEY') { |
$flags .= 'primary_key '; |
} |
if (isset($obj->CTYPE) && trim($obj->CTYPE) == 'UNIQUE') { |
$flags .= 'unique_key '; |
} |
} |
$sql = 'SELECT R.RDB$NULL_FLAG AS NFLAG,' |
.' R.RDB$DEFAULT_SOURCE AS DSOURCE,' |
.' F.RDB$FIELD_TYPE AS FTYPE,' |
.' F.RDB$COMPUTED_SOURCE AS CSOURCE' |
.' FROM RDB$RELATION_FIELDS R ' |
.' JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME' |
.' WHERE UPPER(R.RDB$RELATION_NAME)=\'' . strtoupper($table_name) . '\'' |
.' AND R.RDB$FIELD_NAME=\'' . $field_name . '\''; |
$result = @ibase_query($this->connection, $sql); |
if (!$result) { |
return $this->ibaseRaiseError(); |
} |
if ($obj = @ibase_fetch_object($result)) { |
@ibase_free_result($result); |
if (isset($obj->NFLAG)) { |
$flags .= 'not_null '; |
} |
if (isset($obj->DSOURCE)) { |
$flags .= 'default '; |
} |
if (isset($obj->CSOURCE)) { |
$flags .= 'computed '; |
} |
if (isset($obj->FTYPE) && $obj->FTYPE == 261) { |
$flags .= 'blob '; |
} |
} |
return trim($flags); |
} |
// }}} |
// {{{ ibaseRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_ibase::errorNative(), DB_ibase::errorCode() |
*/ |
function &ibaseRaiseError($errno = null) |
{ |
if ($errno === null) { |
$errno = $this->errorCode($this->errorNative()); |
} |
$tmp = $this->raiseError($errno, null, null, null, @ibase_errmsg()); |
return $tmp; |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return int the DBMS' error code. NULL if there is no error code. |
* |
* @since Method available since Release 1.7.0 |
*/ |
function errorNative() |
{ |
if (function_exists('ibase_errcode')) { |
return @ibase_errcode(); |
} |
if (preg_match('/^Dynamic SQL Error SQL error code = ([0-9-]+)/i', |
@ibase_errmsg(), $m)) { |
return (int)$m[1]; |
} |
return null; |
} |
// }}} |
// {{{ errorCode() |
/** |
* Maps native error codes to DB's portable ones |
* |
* @param int $nativecode the error code returned by the DBMS |
* |
* @return int the portable DB error code. Return DB_ERROR if the |
* current driver doesn't have a mapping for the |
* $nativecode submitted. |
* |
* @since Method available since Release 1.7.0 |
*/ |
function errorCode($nativecode = null) |
{ |
if (isset($this->errorcode_map[$nativecode])) { |
return $this->errorcode_map[$nativecode]; |
} |
static $error_regexps; |
if (!isset($error_regexps)) { |
$error_regexps = array( |
'/generator .* is not defined/' |
=> DB_ERROR_SYNTAX, // for compat. w ibase_errcode() |
'/table.*(not exist|not found|unknown)/i' |
=> DB_ERROR_NOSUCHTABLE, |
'/table .* already exists/i' |
=> DB_ERROR_ALREADY_EXISTS, |
'/unsuccessful metadata update .* failed attempt to store duplicate value/i' |
=> DB_ERROR_ALREADY_EXISTS, |
'/unsuccessful metadata update .* not found/i' |
=> DB_ERROR_NOT_FOUND, |
'/validation error for column .* value "\*\*\* null/i' |
=> DB_ERROR_CONSTRAINT_NOT_NULL, |
'/violation of [\w ]+ constraint/i' |
=> DB_ERROR_CONSTRAINT, |
'/conversion error from string/i' |
=> DB_ERROR_INVALID_NUMBER, |
'/no permission for/i' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/arithmetic exception, numeric overflow, or string truncation/i' |
=> DB_ERROR_INVALID, |
'/feature is not supported/i' |
=> DB_ERROR_NOT_CAPABLE, |
); |
} |
$errormsg = @ibase_errmsg(); |
foreach ($error_regexps as $regexp => $code) { |
if (preg_match($regexp, $errormsg)) { |
return $code; |
} |
} |
return DB_ERROR; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* NOTE: only supports 'table' and 'flags' if <var>$result</var> |
* is a table name. |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @ibase_query($this->connection, |
"SELECT * FROM $result WHERE 1=0"); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->ibaseRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @ibase_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$info = @ibase_field_info($id, $i); |
$res[$i] = array( |
'table' => $got_string ? $case_func($result) : '', |
'name' => $case_func($info['name']), |
'type' => $info['type'], |
'len' => $info['length'], |
'flags' => ($got_string) |
? $this->_ibaseFieldFlags($info['name'], $result) |
: '', |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@ibase_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SELECT DISTINCT R.RDB$RELATION_NAME FROM ' |
. 'RDB$RELATION_FIELDS R WHERE R.RDB$SYSTEM_FLAG=0'; |
case 'views': |
return 'SELECT DISTINCT RDB$VIEW_NAME from RDB$VIEW_RELATIONS'; |
case 'users': |
return 'SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES'; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/storage.php |
---|
Новый файл |
0,0 → 1,506 |
<?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-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: storage.php,v 1.24 2007/08/12 05:27:25 aharvey 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-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @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() |
{ |
$params = array(); |
$vars = array(); |
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: |
*/ |
?> |
/tags/0.1/lib/DB/mysql.php |
---|
Новый файл |
0,0 → 1,1045 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's mysql extension |
* for interacting with MySQL databases |
* |
* 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 <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: mysql.php,v 1.126 2007/09/21 13:32:52 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's mysql extension |
* for interacting with MySQL databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_mysql extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'mysql'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'mysql'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'alter', |
'new_link' => '4.2.0', |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
1004 => DB_ERROR_CANNOT_CREATE, |
1005 => DB_ERROR_CANNOT_CREATE, |
1006 => DB_ERROR_CANNOT_CREATE, |
1007 => DB_ERROR_ALREADY_EXISTS, |
1008 => DB_ERROR_CANNOT_DROP, |
1022 => DB_ERROR_ALREADY_EXISTS, |
1044 => DB_ERROR_ACCESS_VIOLATION, |
1046 => DB_ERROR_NODBSELECTED, |
1048 => DB_ERROR_CONSTRAINT, |
1049 => DB_ERROR_NOSUCHDB, |
1050 => DB_ERROR_ALREADY_EXISTS, |
1051 => DB_ERROR_NOSUCHTABLE, |
1054 => DB_ERROR_NOSUCHFIELD, |
1061 => DB_ERROR_ALREADY_EXISTS, |
1062 => DB_ERROR_ALREADY_EXISTS, |
1064 => DB_ERROR_SYNTAX, |
1091 => DB_ERROR_NOT_FOUND, |
1100 => DB_ERROR_NOT_LOCKED, |
1136 => DB_ERROR_VALUE_COUNT_ON_ROW, |
1142 => DB_ERROR_ACCESS_VIOLATION, |
1146 => DB_ERROR_NOSUCHTABLE, |
1216 => DB_ERROR_CONSTRAINT, |
1217 => DB_ERROR_CONSTRAINT, |
1356 => DB_ERROR_DIVZERO, |
1451 => DB_ERROR_CONSTRAINT, |
1452 => DB_ERROR_CONSTRAINT, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The quantity of transactions begun |
* |
* {@internal While this is private, it can't actually be designated |
* private in PHP 5 because it is directly accessed in the test suite.}} |
* |
* @var integer |
* @access private |
*/ |
var $transaction_opcount = 0; |
/** |
* The database specified in the DSN |
* |
* It's a fix to allow calls to different databases in the same script. |
* |
* @var string |
* @access private |
*/ |
var $_db = ''; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_mysql() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's mysql driver supports the following extra DSN options: |
* + new_link If set to true, causes subsequent calls to connect() |
* to return a new connection link instead of the |
* existing one. WARNING: this is not portable to |
* other DBMS's. Available since PEAR DB 1.7.0. |
* + client_flags Any combination of MYSQL_CLIENT_* constants. |
* Only used if PHP is at version 4.3.0 or greater. |
* Available since PEAR DB 1.7.0. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('mysql')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$params = array(); |
if ($dsn['protocol'] && $dsn['protocol'] == 'unix') { |
$params[0] = ':' . $dsn['socket']; |
} else { |
$params[0] = $dsn['hostspec'] ? $dsn['hostspec'] |
: 'localhost'; |
if ($dsn['port']) { |
$params[0] .= ':' . $dsn['port']; |
} |
} |
$params[] = $dsn['username'] ? $dsn['username'] : null; |
$params[] = $dsn['password'] ? $dsn['password'] : null; |
if (!$persistent) { |
if (isset($dsn['new_link']) |
&& ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) |
{ |
$params[] = true; |
} else { |
$params[] = false; |
} |
} |
if (version_compare(phpversion(), '4.3.0', '>=')) { |
$params[] = isset($dsn['client_flags']) |
? $dsn['client_flags'] : null; |
} |
$connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect'; |
$ini = ini_get('track_errors'); |
$php_errormsg = ''; |
if ($ini) { |
$this->connection = @call_user_func_array($connect_function, |
$params); |
} else { |
@ini_set('track_errors', 1); |
$this->connection = @call_user_func_array($connect_function, |
$params); |
@ini_set('track_errors', $ini); |
} |
if (!$this->connection) { |
if (($err = @mysql_error()) != '') { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$err); |
} else { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
} |
if ($dsn['database']) { |
if (!@mysql_select_db($dsn['database'], $this->connection)) { |
return $this->mysqlRaiseError(); |
} |
$this->_db = $dsn['database']; |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @mysql_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* Generally uses mysql_query(). If you want to use |
* mysql_unbuffered_query() set the "result_buffering" option to 0 using |
* setOptions(). This option was added in Release 1.7.0. |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
if ($this->_db) { |
if (!@mysql_select_db($this->_db, $this->connection)) { |
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
if (!$this->autocommit && $ismanip) { |
if ($this->transaction_opcount == 0) { |
$result = @mysql_query('SET AUTOCOMMIT=0', $this->connection); |
$result = @mysql_query('BEGIN', $this->connection); |
if (!$result) { |
return $this->mysqlRaiseError(); |
} |
} |
$this->transaction_opcount++; |
} |
if (!$this->options['result_buffering']) { |
$result = @mysql_unbuffered_query($query, $this->connection); |
} else { |
$result = @mysql_query($query, $this->connection); |
} |
if (!$result) { |
return $this->mysqlRaiseError(); |
} |
if (is_resource($result)) { |
return $result; |
} |
return DB_OK; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal mysql result pointer to the next available result |
* |
* This method has not been implemented yet. |
* |
* @param a valid sql result resource |
* |
* @return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@mysql_data_seek($result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @mysql_fetch_array($result, MYSQL_ASSOC); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @mysql_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
/* |
* Even though this DBMS already trims output, we do this because |
* a field might have intentional whitespace at the end that |
* gets removed by DB_PORTABILITY_RTRIM under another driver. |
*/ |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? mysql_free_result($result) : false; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @mysql_num_fields($result); |
if (!$cols) { |
return $this->mysqlRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @mysql_num_rows($result); |
if ($rows === null) { |
return $this->mysqlRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
// XXX if $this->transaction_opcount > 0, we should probably |
// issue a warning here. |
$this->autocommit = $onoff ? true : false; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if ($this->transaction_opcount > 0) { |
if ($this->_db) { |
if (!@mysql_select_db($this->_db, $this->connection)) { |
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
$result = @mysql_query('COMMIT', $this->connection); |
$result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->mysqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if ($this->transaction_opcount > 0) { |
if ($this->_db) { |
if (!@mysql_select_db($this->_db, $this->connection)) { |
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
$result = @mysql_query('ROLLBACK', $this->connection); |
$result = @mysql_query('SET AUTOCOMMIT=1', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->mysqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->_last_query_manip) { |
return @mysql_affected_rows($this->connection); |
} else { |
return 0; |
} |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_mysql::createSequence(), DB_mysql::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
do { |
$repeat = 0; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("UPDATE ${seqname} ". |
'SET id=LAST_INSERT_ID(id+1)'); |
$this->popErrorHandling(); |
if ($result === DB_OK) { |
// COMMON CASE |
$id = @mysql_insert_id($this->connection); |
if ($id != 0) { |
return $id; |
} |
// EMPTY SEQ TABLE |
// Sequence table must be empty for some reason, so fill |
// it and return 1 and obtain a user-level lock |
$result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
if ($result == 0) { |
// Failed to get the lock |
return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); |
} |
// add the default value |
$result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)"); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
// Release the lock |
$result = $this->getOne('SELECT RELEASE_LOCK(' |
. "'${seqname}_lock')"); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
// We know what the result will be, so no need to try again |
return 1; |
} elseif ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) |
{ |
// ONDEMAND TABLE CREATION |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} else { |
$repeat = 1; |
} |
} elseif (DB::isError($result) && |
$result->getCode() == DB_ERROR_ALREADY_EXISTS) |
{ |
// BACKWARDS COMPAT |
// see _BCsequence() comment |
$result = $this->_BCsequence($seqname); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$repeat = 1; |
} |
} while ($repeat); |
return $this->raiseError($result); |
} |
// }}} |
// {{{ createSequence() |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_mysql::nextID(), DB_mysql::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$res = $this->query('CREATE TABLE ' . $seqname |
. ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' |
. ' PRIMARY KEY(id))'); |
if (DB::isError($res)) { |
return $res; |
} |
// insert yields value 1, nextId call will generate ID 2 |
$res = $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); |
if (DB::isError($res)) { |
return $res; |
} |
// so reset to zero |
return $this->query("UPDATE ${seqname} SET id = 0"); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_mysql::nextID(), DB_mysql::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ _BCsequence() |
/** |
* Backwards compatibility with old sequence emulation implementation |
* (clean up the dupes) |
* |
* @param string $seqname the sequence name to clean up |
* |
* @return bool true on success. A DB_Error object on failure. |
* |
* @access private |
*/ |
function _BCsequence($seqname) |
{ |
// Obtain a user-level lock... this will release any previous |
// application locks, but unlike LOCK TABLES, it does not abort |
// the current transaction and is much less frequently used. |
$result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); |
if (DB::isError($result)) { |
return $result; |
} |
if ($result == 0) { |
// Failed to get the lock, can't do the conversion, bail |
// with a DB_ERROR_NOT_LOCKED error |
return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED); |
} |
$highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); |
if (DB::isError($highest_id)) { |
return $highest_id; |
} |
// This should kill all rows except the highest |
// We should probably do something if $highest_id isn't |
// numeric, but I'm at a loss as how to handle that... |
$result = $this->query('DELETE FROM ' . $seqname |
. " WHERE id <> $highest_id"); |
if (DB::isError($result)) { |
return $result; |
} |
// If another thread has been waiting for this lock, |
// it will go thru the above procedure, but will have no |
// real effect |
$result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); |
if (DB::isError($result)) { |
return $result; |
} |
return true; |
} |
// }}} |
// {{{ quoteIdentifier() |
/** |
* Quotes a string so it can be safely used as a table or column name |
* (WARNING: using names that require this is a REALLY BAD IDEA) |
* |
* WARNING: Older versions of MySQL can't handle the backtick |
* character (<kbd>`</kbd>) in table or column names. |
* |
* @param string $str identifier name to be quoted |
* |
* @return string quoted identifier string |
* |
* @see DB_common::quoteIdentifier() |
* @since Method available since Release 1.6.0 |
*/ |
function quoteIdentifier($str) |
{ |
return '`' . str_replace('`', '``', $str) . '`'; |
} |
// }}} |
// {{{ quote() |
/** |
* @deprecated Deprecated in release 1.6.0 |
*/ |
function quote($str) |
{ |
return $this->quoteSmart($str); |
} |
// }}} |
// {{{ escapeSimple() |
/** |
* Escapes a string according to the current DBMS's standards |
* |
* @param string $str the string to be escaped |
* |
* @return string the escaped string |
* |
* @see DB_common::quoteSmart() |
* @since Method available since Release 1.6.0 |
*/ |
function escapeSimple($str) |
{ |
if (function_exists('mysql_real_escape_string')) { |
return @mysql_real_escape_string($str, $this->connection); |
} else { |
return @mysql_escape_string($str); |
} |
} |
// }}} |
// {{{ modifyQuery() |
/** |
* Changes a query string for various DBMS specific reasons |
* |
* This little hack lets you know how many rows were deleted |
* when running a "DELETE FROM table" query. Only implemented |
* if the DB_PORTABILITY_DELETE_COUNT portability option is on. |
* |
* @param string $query the query string to modify |
* |
* @return string the modified query string |
* |
* @access protected |
* @see DB_common::setOption() |
*/ |
function modifyQuery($query) |
{ |
if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) { |
// "DELETE FROM table" gives 0 affected rows in MySQL. |
// This little hack lets you know how many rows were deleted. |
if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) { |
$query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/', |
'DELETE FROM \1 WHERE 1=1', $query); |
} |
} |
return $query; |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
if (DB::isManip($query) || $this->_next_query_manip) { |
return $query . " LIMIT $count"; |
} else { |
return $query . " LIMIT $from, $count"; |
} |
} |
// }}} |
// {{{ mysqlRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_mysql::errorNative(), DB_common::errorCode() |
*/ |
function mysqlRaiseError($errno = null) |
{ |
if ($errno === null) { |
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { |
$this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; |
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; |
$this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; |
} else { |
// Doing this in case mode changes during runtime. |
$this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; |
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; |
$this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; |
} |
$errno = $this->errorCode(mysql_errno($this->connection)); |
} |
return $this->raiseError($errno, null, null, null, |
@mysql_errno($this->connection) . ' ** ' . |
@mysql_error($this->connection)); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return int the DBMS' error code |
*/ |
function errorNative() |
{ |
return @mysql_errno($this->connection); |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
// Fix for bug #11580. |
if ($this->_db) { |
if (!@mysql_select_db($this->_db, $this->connection)) { |
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @mysql_query("SELECT * FROM $result LIMIT 0", |
$this->connection); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @mysql_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
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), |
'len' => @mysql_field_len($id, $i), |
'flags' => @mysql_field_flags($id, $i), |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@mysql_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SHOW TABLES'; |
case 'users': |
return 'SELECT DISTINCT User FROM mysql.user'; |
case 'databases': |
return 'SHOW DATABASES'; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/ifx.php |
---|
Новый файл |
0,0 → 1,683 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's ifx extension |
* for interacting with Informix databases |
* |
* 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 Tomas V.V.Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: ifx.php,v 1.75 2007/07/06 05:19:21 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's ifx extension |
* for interacting with Informix databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* More info on Informix errors can be found at: |
* http://www.informix.com/answers/english/ierrors.htm |
* |
* TODO: |
* - set needed env Informix vars on connect |
* - implement native prepare/execute |
* |
* @category Database |
* @package DB |
* @author Tomas V.V.Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_ifx extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'ifx'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'ifx'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'emulate', |
'new_link' => false, |
'numrows' => 'emulate', |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
'-201' => DB_ERROR_SYNTAX, |
'-206' => DB_ERROR_NOSUCHTABLE, |
'-217' => DB_ERROR_NOSUCHFIELD, |
'-236' => DB_ERROR_VALUE_COUNT_ON_ROW, |
'-239' => DB_ERROR_CONSTRAINT, |
'-253' => DB_ERROR_SYNTAX, |
'-268' => DB_ERROR_CONSTRAINT, |
'-292' => DB_ERROR_CONSTRAINT_NOT_NULL, |
'-310' => DB_ERROR_ALREADY_EXISTS, |
'-316' => DB_ERROR_ALREADY_EXISTS, |
'-319' => DB_ERROR_NOT_FOUND, |
'-329' => DB_ERROR_NODBSELECTED, |
'-346' => DB_ERROR_CONSTRAINT, |
'-386' => DB_ERROR_CONSTRAINT_NOT_NULL, |
'-391' => DB_ERROR_CONSTRAINT_NOT_NULL, |
'-554' => DB_ERROR_SYNTAX, |
'-691' => DB_ERROR_CONSTRAINT, |
'-692' => DB_ERROR_CONSTRAINT, |
'-703' => DB_ERROR_CONSTRAINT_NOT_NULL, |
'-1202' => DB_ERROR_DIVZERO, |
'-1204' => DB_ERROR_INVALID_DATE, |
'-1205' => DB_ERROR_INVALID_DATE, |
'-1206' => DB_ERROR_INVALID_DATE, |
'-1209' => DB_ERROR_INVALID_DATE, |
'-1210' => DB_ERROR_INVALID_DATE, |
'-1212' => DB_ERROR_INVALID_DATE, |
'-1213' => DB_ERROR_INVALID_NUMBER, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The quantity of transactions begun |
* |
* {@internal While this is private, it can't actually be designated |
* private in PHP 5 because it is directly accessed in the test suite.}} |
* |
* @var integer |
* @access private |
*/ |
var $transaction_opcount = 0; |
/** |
* The number of rows affected by a data manipulation query |
* @var integer |
* @access private |
*/ |
var $affected = 0; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_ifx() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('informix') && |
!PEAR::loadExtension('Informix')) |
{ |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$dbhost = $dsn['hostspec'] ? '@' . $dsn['hostspec'] : ''; |
$dbname = $dsn['database'] ? $dsn['database'] . $dbhost : ''; |
$user = $dsn['username'] ? $dsn['username'] : ''; |
$pw = $dsn['password'] ? $dsn['password'] : ''; |
$connect_function = $persistent ? 'ifx_pconnect' : 'ifx_connect'; |
$this->connection = @$connect_function($dbname, $user, $pw); |
if (!is_resource($this->connection)) { |
return $this->ifxRaiseError(DB_ERROR_CONNECT_FAILED); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @ifx_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
$this->affected = null; |
if (preg_match('/(SELECT|EXECUTE)/i', $query)) { //TESTME: Use !DB::isManip()? |
// the scroll is needed for fetching absolute row numbers |
// in a select query result |
$result = @ifx_query($query, $this->connection, IFX_SCROLL); |
} else { |
if (!$this->autocommit && $ismanip) { |
if ($this->transaction_opcount == 0) { |
$result = @ifx_query('BEGIN WORK', $this->connection); |
if (!$result) { |
return $this->ifxRaiseError(); |
} |
} |
$this->transaction_opcount++; |
} |
$result = @ifx_query($query, $this->connection); |
} |
if (!$result) { |
return $this->ifxRaiseError(); |
} |
$this->affected = @ifx_affected_rows($result); |
// Determine which queries should return data, and which |
// should return an error code only. |
if (preg_match('/(SELECT|EXECUTE)/i', $query)) { |
return $result; |
} |
// XXX Testme: free results inside a transaction |
// may cause to stop it and commit the work? |
// Result has to be freed even with a insert or update |
@ifx_free_result($result); |
return DB_OK; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal ifx result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->_last_query_manip) { |
return $this->affected; |
} else { |
return 0; |
} |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if (($rownum !== null) && ($rownum < 0)) { |
return null; |
} |
if ($rownum === null) { |
/* |
* Even though fetch_row() should return the next row if |
* $rownum is null, it doesn't in all cases. Bug 598. |
*/ |
$rownum = 'NEXT'; |
} else { |
// Index starts at row 1, unlike most DBMS's starting at 0. |
$rownum++; |
} |
if (!$arr = @ifx_fetch_row($result, $rownum)) { |
return null; |
} |
if ($fetchmode !== DB_FETCHMODE_ASSOC) { |
$i=0; |
$order = array(); |
foreach ($arr as $val) { |
$order[$i++] = $val; |
} |
$arr = $order; |
} elseif ($fetchmode == DB_FETCHMODE_ASSOC && |
$this->options['portability'] & DB_PORTABILITY_LOWERCASE) |
{ |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
if (!$cols = @ifx_num_fields($result)) { |
return $this->ifxRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? ifx_free_result($result) : false; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = true) |
{ |
// XXX if $this->transaction_opcount > 0, we should probably |
// issue a warning here. |
$this->autocommit = $onoff ? true : false; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if ($this->transaction_opcount > 0) { |
$result = @ifx_query('COMMIT WORK', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->ifxRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if ($this->transaction_opcount > 0) { |
$result = @ifx_query('ROLLBACK WORK', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->ifxRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ ifxRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_ifx::errorNative(), DB_ifx::errorCode() |
*/ |
function ifxRaiseError($errno = null) |
{ |
if ($errno === null) { |
$errno = $this->errorCode(ifx_error()); |
} |
return $this->raiseError($errno, null, null, null, |
$this->errorNative()); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code and message produced by the last query |
* |
* @return string the DBMS' error code and message |
*/ |
function errorNative() |
{ |
return @ifx_error() . ' ' . @ifx_errormsg(); |
} |
// }}} |
// {{{ errorCode() |
/** |
* Maps native error codes to DB's portable ones. |
* |
* Requires that the DB implementation's constructor fills |
* in the <var>$errorcode_map</var> property. |
* |
* @param string $nativecode error code returned by the database |
* @return int a portable DB error code, or DB_ERROR if this DB |
* implementation has no mapping for the given error code. |
*/ |
function errorCode($nativecode) |
{ |
if (ereg('SQLCODE=(.*)]', $nativecode, $match)) { |
$code = $match[1]; |
if (isset($this->errorcode_map[$code])) { |
return $this->errorcode_map[$code]; |
} |
} |
return DB_ERROR; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* NOTE: only supports 'table' if <var>$result</var> is a table name. |
* |
* If analyzing a query result and the result has duplicate field names, |
* an error will be raised saying |
* <samp>can't distinguish duplicate field names</samp>. |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
* @since Method available since Release 1.6.0 |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @ifx_query("SELECT * FROM $result WHERE 1=0", |
$this->connection); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->ifxRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
$flds = @ifx_fieldproperties($id); |
$count = @ifx_num_fields($id); |
if (count($flds) != $count) { |
return $this->raiseError("can't distinguish duplicate field names"); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$i = 0; |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
foreach ($flds as $key => $value) { |
$props = explode(';', $value); |
$res[$i] = array( |
'table' => $got_string ? $case_func($result) : '', |
'name' => $case_func($key), |
'type' => $props[0], |
'len' => $props[1], |
'flags' => $props[4] == 'N' ? 'not_null' : '', |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
$i++; |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@ifx_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SELECT tabname FROM systables WHERE tabid >= 100'; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/pgsql.php |
---|
Новый файл |
0,0 → 1,1116 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's pgsql extension |
* for interacting with PostgreSQL databases |
* |
* 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 Rui Hirokawa <hirokawa@php.net> |
* @author Stig Bakken <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: pgsql.php,v 1.138 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's pgsql extension |
* for interacting with PostgreSQL databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Rui Hirokawa <hirokawa@php.net> |
* @author Stig Bakken <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_pgsql extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'pgsql'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'pgsql'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'alter', |
'new_link' => '4.3.0', |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => true, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The quantity of transactions begun |
* |
* {@internal While this is private, it can't actually be designated |
* private in PHP 5 because it is directly accessed in the test suite.}} |
* |
* @var integer |
* @access private |
*/ |
var $transaction_opcount = 0; |
/** |
* The number of rows affected by a data manipulation query |
* @var integer |
*/ |
var $affected = 0; |
/** |
* The current row being looked at in fetchInto() |
* @var array |
* @access private |
*/ |
var $row = array(); |
/** |
* The number of rows in a given result set |
* @var array |
* @access private |
*/ |
var $_num_rows = array(); |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_pgsql() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's pgsql driver supports the following extra DSN options: |
* + connect_timeout How many seconds to wait for a connection to |
* be established. Available since PEAR DB 1.7.0. |
* + new_link If set to true, causes subsequent calls to |
* connect() to return a new connection link |
* instead of the existing one. WARNING: this is |
* not portable to other DBMS's. Available only |
* if PHP is >= 4.3.0 and PEAR DB is >= 1.7.0. |
* + options Command line options to be sent to the server. |
* Available since PEAR DB 1.6.4. |
* + service Specifies a service name in pg_service.conf that |
* holds additional connection parameters. |
* Available since PEAR DB 1.7.0. |
* + sslmode How should SSL be used when connecting? Values: |
* disable, allow, prefer or require. |
* Available since PEAR DB 1.7.0. |
* + tty This was used to specify where to send server |
* debug output. Available since PEAR DB 1.6.4. |
* |
* Example of connecting to a new link via a socket: |
* <code> |
* require_once 'DB.php'; |
* |
* $dsn = 'pgsql://user:pass@unix(/tmp)/dbname?new_link=true'; |
* $options = array( |
* 'portability' => DB_PORTABILITY_ALL, |
* ); |
* |
* $db = DB::connect($dsn, $options); |
* if (PEAR::isError($db)) { |
* die($db->getMessage()); |
* } |
* </code> |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @link http://www.postgresql.org/docs/current/static/libpq.html#LIBPQ-CONNECT |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('pgsql')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$protocol = $dsn['protocol'] ? $dsn['protocol'] : 'tcp'; |
$params = array(''); |
if ($protocol == 'tcp') { |
if ($dsn['hostspec']) { |
$params[0] .= 'host=' . $dsn['hostspec']; |
} |
if ($dsn['port']) { |
$params[0] .= ' port=' . $dsn['port']; |
} |
} elseif ($protocol == 'unix') { |
// Allow for pg socket in non-standard locations. |
if ($dsn['socket']) { |
$params[0] .= 'host=' . $dsn['socket']; |
} |
if ($dsn['port']) { |
$params[0] .= ' port=' . $dsn['port']; |
} |
} |
if ($dsn['database']) { |
$params[0] .= ' dbname=\'' . addslashes($dsn['database']) . '\''; |
} |
if ($dsn['username']) { |
$params[0] .= ' user=\'' . addslashes($dsn['username']) . '\''; |
} |
if ($dsn['password']) { |
$params[0] .= ' password=\'' . addslashes($dsn['password']) . '\''; |
} |
if (!empty($dsn['options'])) { |
$params[0] .= ' options=' . $dsn['options']; |
} |
if (!empty($dsn['tty'])) { |
$params[0] .= ' tty=' . $dsn['tty']; |
} |
if (!empty($dsn['connect_timeout'])) { |
$params[0] .= ' connect_timeout=' . $dsn['connect_timeout']; |
} |
if (!empty($dsn['sslmode'])) { |
$params[0] .= ' sslmode=' . $dsn['sslmode']; |
} |
if (!empty($dsn['service'])) { |
$params[0] .= ' service=' . $dsn['service']; |
} |
if (isset($dsn['new_link']) |
&& ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) |
{ |
if (version_compare(phpversion(), '4.3.0', '>=')) { |
$params[] = PGSQL_CONNECT_FORCE_NEW; |
} |
} |
$connect_function = $persistent ? 'pg_pconnect' : 'pg_connect'; |
$ini = ini_get('track_errors'); |
$php_errormsg = ''; |
if ($ini) { |
$this->connection = @call_user_func_array($connect_function, |
$params); |
} else { |
@ini_set('track_errors', 1); |
$this->connection = @call_user_func_array($connect_function, |
$params); |
@ini_set('track_errors', $ini); |
} |
if (!$this->connection) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @pg_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
if (!$this->autocommit && $ismanip) { |
if ($this->transaction_opcount == 0) { |
$result = @pg_exec($this->connection, 'begin;'); |
if (!$result) { |
return $this->pgsqlRaiseError(); |
} |
} |
$this->transaction_opcount++; |
} |
$result = @pg_exec($this->connection, $query); |
if (!$result) { |
return $this->pgsqlRaiseError(); |
} |
/* |
* Determine whether queries produce affected rows, result or nothing. |
* |
* This logic was introduced in version 1.1 of the file by ssb, |
* though the regex has been modified slightly since then. |
* |
* PostgreSQL commands: |
* ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, |
* CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, |
* GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, |
* REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, |
* UNLISTEN, UPDATE, VACUUM |
*/ |
if ($ismanip) { |
$this->affected = @pg_affected_rows($result); |
return DB_OK; |
} elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si', |
$query)) |
{ |
$this->row[(int)$result] = 0; // reset the row counter. |
$numrows = $this->numRows($result); |
if (is_object($numrows)) { |
return $numrows; |
} |
$this->_num_rows[(int)$result] = $numrows; |
$this->affected = 0; |
return $result; |
} else { |
$this->affected = 0; |
return DB_OK; |
} |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal pgsql result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
$result_int = (int)$result; |
$rownum = ($rownum !== null) ? $rownum : $this->row[$result_int]; |
if ($rownum >= $this->_num_rows[$result_int]) { |
return null; |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @pg_fetch_array($result, $rownum, PGSQL_ASSOC); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @pg_fetch_row($result, $rownum); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
$this->row[$result_int] = ++$rownum; |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
if (is_resource($result)) { |
unset($this->row[(int)$result]); |
unset($this->_num_rows[(int)$result]); |
$this->affected = 0; |
return @pg_freeresult($result); |
} |
return false; |
} |
// }}} |
// {{{ quote() |
/** |
* @deprecated Deprecated in release 1.6.0 |
* @internal |
*/ |
function quote($str) |
{ |
return $this->quoteSmart($str); |
} |
// }}} |
// {{{ quoteBoolean() |
/** |
* Formats a boolean value for use within a query in a locale-independent |
* manner. |
* |
* @param boolean the boolean value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteBoolean($boolean) { |
return $boolean ? 'TRUE' : 'FALSE'; |
} |
// }}} |
// {{{ escapeSimple() |
/** |
* Escapes a string according to the current DBMS's standards |
* |
* {@internal PostgreSQL treats a backslash as an escape character, |
* so they are escaped as well. |
* |
* @param string $str the string to be escaped |
* |
* @return string the escaped string |
* |
* @see DB_common::quoteSmart() |
* @since Method available since Release 1.6.0 |
*/ |
function escapeSimple($str) |
{ |
if (function_exists('pg_escape_string')) { |
/* This fixes an undocumented BC break in PHP 5.2.0 which changed |
* the prototype of pg_escape_string. I'm not thrilled about having |
* to sniff the PHP version, quite frankly, but it's the only way |
* to deal with the problem. Revision 1.331.2.13.2.10 on |
* php-src/ext/pgsql/pgsql.c (PHP_5_2 branch) is to blame, for the |
* record. */ |
if (version_compare(PHP_VERSION, '5.2.0', '>=')) { |
return pg_escape_string($this->connection, $str); |
} else { |
return pg_escape_string($str); |
} |
} else { |
return str_replace("'", "''", str_replace('\\', '\\\\', $str)); |
} |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @pg_numfields($result); |
if (!$cols) { |
return $this->pgsqlRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @pg_numrows($result); |
if ($rows === null) { |
return $this->pgsqlRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
// XXX if $this->transaction_opcount > 0, we should probably |
// issue a warning here. |
$this->autocommit = $onoff ? true : false; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if ($this->transaction_opcount > 0) { |
// (disabled) hack to shut up error messages from libpq.a |
//@fclose(@fopen("php://stderr", "w")); |
$result = @pg_exec($this->connection, 'end;'); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->pgsqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if ($this->transaction_opcount > 0) { |
$result = @pg_exec($this->connection, 'abort;'); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->pgsqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
return $this->affected; |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_pgsql::createSequence(), DB_pgsql::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$repeat = false; |
do { |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("SELECT NEXTVAL('${seqname}')"); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) { |
$repeat = true; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->createSequence($seq_name); |
$this->popErrorHandling(); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
} else { |
$repeat = false; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED); |
$result->free(); |
return $arr[0]; |
} |
// }}} |
// {{{ createSequence() |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_pgsql::nextID(), DB_pgsql::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$result = $this->query("CREATE SEQUENCE ${seqname}"); |
return $result; |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_pgsql::nextID(), DB_pgsql::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP SEQUENCE ' |
. $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
return "$query LIMIT $count OFFSET $from"; |
} |
// }}} |
// {{{ pgsqlRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_pgsql::errorNative(), DB_pgsql::errorCode() |
*/ |
function pgsqlRaiseError($errno = null) |
{ |
$native = $this->errorNative(); |
if (!$native) { |
$native = 'Database connection has been lost.'; |
$errno = DB_ERROR_CONNECT_FAILED; |
} |
if ($errno === null) { |
$errno = $this->errorCode($native); |
} |
return $this->raiseError($errno, null, null, null, $native); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error message produced by the last query |
* |
* {@internal Error messages are used instead of error codes |
* in order to support older versions of PostgreSQL.}} |
* |
* @return string the DBMS' error message |
*/ |
function errorNative() |
{ |
return @pg_errormessage($this->connection); |
} |
// }}} |
// {{{ errorCode() |
/** |
* Determines PEAR::DB error code from the database's text error message. |
* |
* @param string $errormsg error message returned from the database |
* @return integer an error number from a DB error constant |
*/ |
function errorCode($errormsg) |
{ |
static $error_regexps; |
if (!isset($error_regexps)) { |
$error_regexps = array( |
'/column .* (of relation .*)?does not exist/i' |
=> DB_ERROR_NOSUCHFIELD, |
'/(relation|sequence|table).*does not exist|class .* not found/i' |
=> DB_ERROR_NOSUCHTABLE, |
'/index .* does not exist/' |
=> DB_ERROR_NOT_FOUND, |
'/relation .* already exists/i' |
=> DB_ERROR_ALREADY_EXISTS, |
'/(divide|division) by zero$/i' |
=> DB_ERROR_DIVZERO, |
'/pg_atoi: error in .*: can\'t parse /i' |
=> DB_ERROR_INVALID_NUMBER, |
'/invalid input syntax for( type)? (integer|numeric)/i' |
=> DB_ERROR_INVALID_NUMBER, |
'/value .* is out of range for type \w*int/i' |
=> DB_ERROR_INVALID_NUMBER, |
'/integer out of range/i' |
=> DB_ERROR_INVALID_NUMBER, |
'/value too long for type character/i' |
=> DB_ERROR_INVALID, |
'/attribute .* not found|relation .* does not have attribute/i' |
=> DB_ERROR_NOSUCHFIELD, |
'/column .* specified in USING clause does not exist in (left|right) table/i' |
=> DB_ERROR_NOSUCHFIELD, |
'/parser: parse error at or near/i' |
=> DB_ERROR_SYNTAX, |
'/syntax error at/' |
=> DB_ERROR_SYNTAX, |
'/column reference .* is ambiguous/i' |
=> DB_ERROR_SYNTAX, |
'/permission denied/' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/violates not-null constraint/' |
=> DB_ERROR_CONSTRAINT_NOT_NULL, |
'/violates [\w ]+ constraint/' |
=> DB_ERROR_CONSTRAINT, |
'/referential integrity violation/' |
=> DB_ERROR_CONSTRAINT, |
'/more expressions than target columns/i' |
=> DB_ERROR_VALUE_COUNT_ON_ROW, |
); |
} |
foreach ($error_regexps as $regexp => $code) { |
if (preg_match($regexp, $errormsg)) { |
return $code; |
} |
} |
// Fall back to DB_ERROR if there was no mapping. |
return DB_ERROR; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* NOTE: only supports 'table' and 'flags' if <var>$result</var> |
* is a table name. |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @pg_exec($this->connection, "SELECT * FROM $result LIMIT 0"); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->pgsqlRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @pg_numfields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$res[$i] = array( |
'table' => $got_string ? $case_func($result) : '', |
'name' => $case_func(@pg_fieldname($id, $i)), |
'type' => @pg_fieldtype($id, $i), |
'len' => @pg_fieldsize($id, $i), |
'flags' => $got_string |
? $this->_pgFieldFlags($id, $i, $result) |
: '', |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@pg_freeresult($id); |
} |
return $res; |
} |
// }}} |
// {{{ _pgFieldFlags() |
/** |
* Get a column's flags |
* |
* Supports "not_null", "default_value", "primary_key", "unique_key" |
* and "multiple_key". The default value is passed through |
* rawurlencode() in case there are spaces in it. |
* |
* @param int $resource the PostgreSQL result identifier |
* @param int $num_field the field number |
* |
* @return string the flags |
* |
* @access private |
*/ |
function _pgFieldFlags($resource, $num_field, $table_name) |
{ |
$field_name = @pg_fieldname($resource, $num_field); |
// Check if there's a schema in $table_name and update things |
// accordingly. |
$from = 'pg_attribute f, pg_class tab, pg_type typ'; |
if (strpos($table_name, '.') !== false) { |
$from .= ', pg_namespace nsp'; |
list($schema, $table) = explode('.', $table_name); |
$tableWhere = "tab.relname = '$table' AND tab.relnamespace = nsp.oid AND nsp.nspname = '$schema'"; |
} else { |
$tableWhere = "tab.relname = '$table_name'"; |
} |
$result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef |
FROM $from |
WHERE tab.relname = typ.typname |
AND typ.typrelid = f.attrelid |
AND f.attname = '$field_name' |
AND $tableWhere"); |
if (@pg_numrows($result) > 0) { |
$row = @pg_fetch_row($result, 0); |
$flags = ($row[0] == 't') ? 'not_null ' : ''; |
if ($row[1] == 't') { |
$result = @pg_exec($this->connection, "SELECT a.adsrc |
FROM $from, pg_attrdef a |
WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid |
AND f.attrelid = a.adrelid AND f.attname = '$field_name' |
AND $tableWhere AND f.attnum = a.adnum"); |
$row = @pg_fetch_row($result, 0); |
$num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); |
$flags .= 'default_' . rawurlencode($num) . ' '; |
} |
} else { |
$flags = ''; |
} |
$result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey |
FROM $from, pg_index i |
WHERE tab.relname = typ.typname |
AND typ.typrelid = f.attrelid |
AND f.attrelid = i.indrelid |
AND f.attname = '$field_name' |
AND $tableWhere"); |
$count = @pg_numrows($result); |
for ($i = 0; $i < $count ; $i++) { |
$row = @pg_fetch_row($result, $i); |
$keys = explode(' ', $row[2]); |
if (in_array($num_field + 1, $keys)) { |
$flags .= ($row[0] == 't' && $row[1] == 'f') ? 'unique_key ' : ''; |
$flags .= ($row[1] == 't') ? 'primary_key ' : ''; |
if (count($keys) > 1) |
$flags .= 'multiple_key '; |
} |
} |
return trim($flags); |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SELECT c.relname AS "Name"' |
. ' FROM pg_class c, pg_user u' |
. ' WHERE c.relowner = u.usesysid' |
. " AND c.relkind = 'r'" |
. ' AND NOT EXISTS' |
. ' (SELECT 1 FROM pg_views' |
. ' WHERE viewname = c.relname)' |
. " AND c.relname !~ '^(pg_|sql_)'" |
. ' UNION' |
. ' SELECT c.relname AS "Name"' |
. ' FROM pg_class c' |
. " WHERE c.relkind = 'r'" |
. ' AND NOT EXISTS' |
. ' (SELECT 1 FROM pg_views' |
. ' WHERE viewname = c.relname)' |
. ' AND NOT EXISTS' |
. ' (SELECT 1 FROM pg_user' |
. ' WHERE usesysid = c.relowner)' |
. " AND c.relname !~ '^pg_'"; |
case 'schema.tables': |
return "SELECT schemaname || '.' || tablename" |
. ' AS "Name"' |
. ' FROM pg_catalog.pg_tables' |
. ' WHERE schemaname NOT IN' |
. " ('pg_catalog', 'information_schema', 'pg_toast')"; |
case 'schema.views': |
return "SELECT schemaname || '.' || viewname from pg_views WHERE schemaname" |
. " NOT IN ('information_schema', 'pg_catalog')"; |
case 'views': |
// Table cols: viewname | viewowner | definition |
return 'SELECT viewname from pg_views WHERE schemaname' |
. " NOT IN ('information_schema', 'pg_catalog')"; |
case 'users': |
// cols: usename |usesysid|usecreatedb|usetrace|usesuper|usecatupd|passwd |valuntil |
return 'SELECT usename FROM pg_user'; |
case 'databases': |
return 'SELECT datname FROM pg_database'; |
case 'functions': |
case 'procedures': |
return 'SELECT proname FROM pg_proc WHERE proowner <> 1'; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/sybase.php |
---|
Новый файл |
0,0 → 1,942 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's sybase extension |
* for interacting with Sybase databases |
* |
* 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 Sterling Hughes <sterling@php.net> |
* @author Antônio Carlos Venâncio Júnior <floripa@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: sybase.php,v 1.87 2007/09/21 13:40:42 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's sybase extension |
* for interacting with Sybase databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* WARNING: This driver may fail with multiple connections under the |
* same user/pass/host and different databases. |
* |
* @category Database |
* @package DB |
* @author Sterling Hughes <sterling@php.net> |
* @author Antônio Carlos Venâncio Júnior <floripa@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_sybase extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'sybase'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'sybase'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'emulate', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The quantity of transactions begun |
* |
* {@internal While this is private, it can't actually be designated |
* private in PHP 5 because it is directly accessed in the test suite.}} |
* |
* @var integer |
* @access private |
*/ |
var $transaction_opcount = 0; |
/** |
* The database specified in the DSN |
* |
* It's a fix to allow calls to different databases in the same script. |
* |
* @var string |
* @access private |
*/ |
var $_db = ''; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_sybase() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's sybase driver supports the following extra DSN options: |
* + appname The application name to use on this connection. |
* Available since PEAR DB 1.7.0. |
* + charset The character set to use on this connection. |
* Available since PEAR DB 1.7.0. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('sybase') && |
!PEAR::loadExtension('sybase_ct')) |
{ |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$dsn['hostspec'] = $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost'; |
$dsn['password'] = !empty($dsn['password']) ? $dsn['password'] : false; |
$dsn['charset'] = isset($dsn['charset']) ? $dsn['charset'] : false; |
$dsn['appname'] = isset($dsn['appname']) ? $dsn['appname'] : false; |
$connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect'; |
if ($dsn['username']) { |
$this->connection = @$connect_function($dsn['hostspec'], |
$dsn['username'], |
$dsn['password'], |
$dsn['charset'], |
$dsn['appname']); |
} else { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
'The DSN did not contain a username.'); |
} |
if (!$this->connection) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
@sybase_get_last_message()); |
} |
if ($dsn['database']) { |
if (!@sybase_select_db($dsn['database'], $this->connection)) { |
return $this->raiseError(DB_ERROR_NODBSELECTED, |
null, null, null, |
@sybase_get_last_message()); |
} |
$this->_db = $dsn['database']; |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @sybase_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { |
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); |
} |
$query = $this->modifyQuery($query); |
if (!$this->autocommit && $ismanip) { |
if ($this->transaction_opcount == 0) { |
$result = @sybase_query('BEGIN TRANSACTION', $this->connection); |
if (!$result) { |
return $this->sybaseRaiseError(); |
} |
} |
$this->transaction_opcount++; |
} |
$result = @sybase_query($query, $this->connection); |
if (!$result) { |
return $this->sybaseRaiseError(); |
} |
if (is_resource($result)) { |
return $result; |
} |
// Determine which queries that should return data, and which |
// should return an error code only. |
return $ismanip ? DB_OK : $result; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal sybase result pointer to the next available result |
* |
* @param a valid sybase result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@sybase_data_seek($result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
if (function_exists('sybase_fetch_assoc')) { |
$arr = @sybase_fetch_assoc($result); |
} else { |
if ($arr = @sybase_fetch_array($result)) { |
foreach ($arr as $key => $value) { |
if (is_int($key)) { |
unset($arr[$key]); |
} |
} |
} |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @sybase_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? sybase_free_result($result) : false; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @sybase_num_fields($result); |
if (!$cols) { |
return $this->sybaseRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @sybase_num_rows($result); |
if ($rows === false) { |
return $this->sybaseRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->_last_query_manip) { |
$result = @sybase_affected_rows($this->connection); |
} else { |
$result = 0; |
} |
return $result; |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_sybase::createSequence(), DB_sybase::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { |
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); |
} |
$repeat = 0; |
do { |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)"); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result) && |
($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) |
{ |
$repeat = 1; |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
} elseif (!DB::isError($result)) { |
$result = $this->query("SELECT @@IDENTITY FROM $seqname"); |
$repeat = 0; |
} else { |
$repeat = false; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$result = $result->fetchRow(DB_FETCHMODE_ORDERED); |
return $result[0]; |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_sybase::nextID(), DB_sybase::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
return $this->query('CREATE TABLE ' |
. $this->getSequenceName($seq_name) |
. ' (id numeric(10, 0) IDENTITY NOT NULL,' |
. ' vapor int NULL)'); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_sybase::nextID(), DB_sybase::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ quoteFloat() |
/** |
* Formats a float value for use within a query in a locale-independent |
* manner. |
* |
* @param float the float value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteFloat($float) { |
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
// XXX if $this->transaction_opcount > 0, we should probably |
// issue a warning here. |
$this->autocommit = $onoff ? true : false; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if ($this->transaction_opcount > 0) { |
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { |
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); |
} |
$result = @sybase_query('COMMIT', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->sybaseRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if ($this->transaction_opcount > 0) { |
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { |
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); |
} |
$result = @sybase_query('ROLLBACK', $this->connection); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->sybaseRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ sybaseRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_sybase::errorNative(), DB_sybase::errorCode() |
*/ |
function sybaseRaiseError($errno = null) |
{ |
$native = $this->errorNative(); |
if ($errno === null) { |
$errno = $this->errorCode($native); |
} |
return $this->raiseError($errno, null, null, null, $native); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error message produced by the last query |
* |
* @return string the DBMS' error message |
*/ |
function errorNative() |
{ |
return @sybase_get_last_message(); |
} |
// }}} |
// {{{ errorCode() |
/** |
* Determines PEAR::DB error code from the database's text error message. |
* |
* @param string $errormsg error message returned from the database |
* @return integer an error number from a DB error constant |
*/ |
function errorCode($errormsg) |
{ |
static $error_regexps; |
// PHP 5.2+ prepends the function name to $php_errormsg, so we need |
// this hack to work around it, per bug #9599. |
$errormsg = preg_replace('/^sybase[a-z_]+\(\): /', '', $errormsg); |
if (!isset($error_regexps)) { |
$error_regexps = array( |
'/Incorrect syntax near/' |
=> DB_ERROR_SYNTAX, |
'/^Unclosed quote before the character string [\"\'].*[\"\']\./' |
=> DB_ERROR_SYNTAX, |
'/Implicit conversion (from datatype|of NUMERIC value)/i' |
=> DB_ERROR_INVALID_NUMBER, |
'/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./' |
=> DB_ERROR_NOSUCHTABLE, |
'/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/^.+ permission denied on object .+, database .+, owner .+/' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/^.* permission denied, database .+, owner .+/' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/[^.*] not found\./' |
=> DB_ERROR_NOSUCHTABLE, |
'/There is already an object named/' |
=> DB_ERROR_ALREADY_EXISTS, |
'/Invalid column name/' |
=> DB_ERROR_NOSUCHFIELD, |
'/does not allow null values/' |
=> DB_ERROR_CONSTRAINT_NOT_NULL, |
'/Command has been aborted/' |
=> DB_ERROR_CONSTRAINT, |
'/^Cannot drop the index .* because it doesn\'t exist/i' |
=> DB_ERROR_NOT_FOUND, |
'/^There is already an index/i' |
=> DB_ERROR_ALREADY_EXISTS, |
'/^There are fewer columns in the INSERT statement than values specified/i' |
=> DB_ERROR_VALUE_COUNT_ON_ROW, |
'/Divide by zero/i' |
=> DB_ERROR_DIVZERO, |
); |
} |
foreach ($error_regexps as $regexp => $code) { |
if (preg_match($regexp, $errormsg)) { |
return $code; |
} |
} |
return DB_ERROR; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* NOTE: only supports 'table' and 'flags' if <var>$result</var> |
* is a table name. |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
* @since Method available since Release 1.6.0 |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { |
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); |
} |
$id = @sybase_query("SELECT * FROM $result WHERE 1=0", |
$this->connection); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @sybase_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$f = @sybase_fetch_field($id, $i); |
// column_source is often blank |
$res[$i] = array( |
'table' => $got_string |
? $case_func($result) |
: $case_func($f->column_source), |
'name' => $case_func($f->name), |
'type' => $f->type, |
'len' => $f->max_length, |
'flags' => '', |
); |
if ($res[$i]['table']) { |
$res[$i]['flags'] = $this->_sybase_field_flags( |
$res[$i]['table'], $res[$i]['name']); |
} |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@sybase_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ _sybase_field_flags() |
/** |
* Get the flags for a field |
* |
* Currently supports: |
* + <samp>unique_key</samp> (unique index, unique check or primary_key) |
* + <samp>multiple_key</samp> (multi-key index) |
* |
* @param string $table the table name |
* @param string $column the field name |
* |
* @return string space delimited string of flags. Empty string if none. |
* |
* @access private |
*/ |
function _sybase_field_flags($table, $column) |
{ |
static $tableName = null; |
static $flags = array(); |
if ($table != $tableName) { |
$flags = array(); |
$tableName = $table; |
/* We're running sp_helpindex directly because it doesn't exist in |
* older versions of ASE -- unfortunately, we can't just use |
* DB::isError() because the user may be using callback error |
* handling. */ |
$res = @sybase_query("sp_helpindex $table", $this->connection); |
if ($res === false || $res === true) { |
// Fake a valid response for BC reasons. |
return ''; |
} |
while (($val = sybase_fetch_assoc($res)) !== false) { |
if (!isset($val['index_keys'])) { |
/* No useful information returned. Break and be done with |
* it, which preserves the pre-1.7.9 behaviour. */ |
break; |
} |
$keys = explode(', ', trim($val['index_keys'])); |
if (sizeof($keys) > 1) { |
foreach ($keys as $key) { |
$this->_add_flag($flags[$key], 'multiple_key'); |
} |
} |
if (strpos($val['index_description'], 'unique')) { |
foreach ($keys as $key) { |
$this->_add_flag($flags[$key], 'unique_key'); |
} |
} |
} |
sybase_free_result($res); |
} |
if (array_key_exists($column, $flags)) { |
return(implode(' ', $flags[$column])); |
} |
return ''; |
} |
// }}} |
// {{{ _add_flag() |
/** |
* Adds a string to the flags array if the flag is not yet in there |
* - if there is no flag present the array is created |
* |
* @param array $array reference of flags array to add a value to |
* @param mixed $value value to add to the flag array |
* |
* @return void |
* |
* @access private |
*/ |
function _add_flag(&$array, $value) |
{ |
if (!is_array($array)) { |
$array = array($value); |
} elseif (!in_array($value, $array)) { |
array_push($array, $value); |
} |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return "SELECT name FROM sysobjects WHERE type = 'U'" |
. ' ORDER BY name'; |
case 'views': |
return "SELECT name FROM sysobjects WHERE type = 'V'"; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/fbsql.php |
---|
Новый файл |
0,0 → 1,769 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's fbsql extension |
* for interacting with FrontBase databases |
* |
* 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 Frank M. Kromann <frank@frontbase.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: fbsql.php,v 1.88 2007/07/06 05:19:21 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's fbsql extension |
* for interacting with FrontBase databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Frank M. Kromann <frank@frontbase.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
* @since Class functional since Release 1.7.0 |
*/ |
class DB_fbsql extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'fbsql'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'fbsql'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'alter', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
22 => DB_ERROR_SYNTAX, |
85 => DB_ERROR_ALREADY_EXISTS, |
108 => DB_ERROR_SYNTAX, |
116 => DB_ERROR_NOSUCHTABLE, |
124 => DB_ERROR_VALUE_COUNT_ON_ROW, |
215 => DB_ERROR_NOSUCHFIELD, |
217 => DB_ERROR_INVALID_NUMBER, |
226 => DB_ERROR_NOSUCHFIELD, |
231 => DB_ERROR_INVALID, |
239 => DB_ERROR_TRUNCATED, |
251 => DB_ERROR_SYNTAX, |
266 => DB_ERROR_NOT_FOUND, |
357 => DB_ERROR_CONSTRAINT_NOT_NULL, |
358 => DB_ERROR_CONSTRAINT, |
360 => DB_ERROR_CONSTRAINT, |
361 => DB_ERROR_CONSTRAINT, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_fbsql() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('fbsql')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$params = array( |
$dsn['hostspec'] ? $dsn['hostspec'] : 'localhost', |
$dsn['username'] ? $dsn['username'] : null, |
$dsn['password'] ? $dsn['password'] : null, |
); |
$connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect'; |
$ini = ini_get('track_errors'); |
$php_errormsg = ''; |
if ($ini) { |
$this->connection = @call_user_func_array($connect_function, |
$params); |
} else { |
@ini_set('track_errors', 1); |
$this->connection = @call_user_func_array($connect_function, |
$params); |
@ini_set('track_errors', $ini); |
} |
if (!$this->connection) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
if ($dsn['database']) { |
if (!@fbsql_select_db($dsn['database'], $this->connection)) { |
return $this->fbsqlRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @fbsql_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
$result = @fbsql_query("$query;", $this->connection); |
if (!$result) { |
return $this->fbsqlRaiseError(); |
} |
// Determine which queries that should return data, and which |
// should return an error code only. |
if ($this->_checkManip($query)) { |
return DB_OK; |
} |
return $result; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal fbsql result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return @fbsql_next_result($result); |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@fbsql_data_seek($result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @fbsql_fetch_array($result, FBSQL_ASSOC); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @fbsql_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? fbsql_free_result($result) : false; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff=false) |
{ |
if ($onoff) { |
$this->query("SET COMMIT TRUE"); |
} else { |
$this->query("SET COMMIT FALSE"); |
} |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
@fbsql_commit($this->connection); |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
@fbsql_rollback($this->connection); |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @fbsql_num_fields($result); |
if (!$cols) { |
return $this->fbsqlRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @fbsql_num_rows($result); |
if ($rows === null) { |
return $this->fbsqlRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->_last_query_manip) { |
$result = @fbsql_affected_rows($this->connection); |
} else { |
$result = 0; |
} |
return $result; |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_fbsql::createSequence(), DB_fbsql::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
do { |
$repeat = 0; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query('SELECT UNIQUE FROM ' . $seqname); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) { |
$repeat = 1; |
$result = $this->createSequence($seq_name); |
if (DB::isError($result)) { |
return $result; |
} |
} else { |
$repeat = 0; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->fbsqlRaiseError(); |
} |
$result->fetchInto($tmp, DB_FETCHMODE_ORDERED); |
return $tmp[0]; |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_fbsql::nextID(), DB_fbsql::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$res = $this->query('CREATE TABLE ' . $seqname |
. ' (id INTEGER NOT NULL,' |
. ' PRIMARY KEY(id))'); |
if ($res) { |
$res = $this->query('SET UNIQUE = 0 FOR ' . $seqname); |
} |
return $res; |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_fbsql::nextID(), DB_fbsql::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name) |
. ' RESTRICT'); |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
if (DB::isManip($query) || $this->_next_query_manip) { |
return preg_replace('/^([\s(])*SELECT/i', |
"\\1SELECT TOP($count)", $query); |
} else { |
return preg_replace('/([\s(])*SELECT/i', |
"\\1SELECT TOP($from, $count)", $query); |
} |
} |
// }}} |
// {{{ quoteBoolean() |
/** |
* Formats a boolean value for use within a query in a locale-independent |
* manner. |
* |
* @param boolean the boolean value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteBoolean($boolean) { |
return $boolean ? 'TRUE' : 'FALSE'; |
} |
// }}} |
// {{{ quoteFloat() |
/** |
* Formats a float value for use within a query in a locale-independent |
* manner. |
* |
* @param float the float value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteFloat($float) { |
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); |
} |
// }}} |
// {{{ fbsqlRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_fbsql::errorNative(), DB_common::errorCode() |
*/ |
function fbsqlRaiseError($errno = null) |
{ |
if ($errno === null) { |
$errno = $this->errorCode(fbsql_errno($this->connection)); |
} |
return $this->raiseError($errno, null, null, null, |
@fbsql_error($this->connection)); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return int the DBMS' error code |
*/ |
function errorNative() |
{ |
return @fbsql_errno($this->connection); |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @fbsql_list_fields($this->dsn['database'], |
$result, $this->connection); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @fbsql_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$res[$i] = array( |
'table' => $case_func(@fbsql_field_table($id, $i)), |
'name' => $case_func(@fbsql_field_name($id, $i)), |
'type' => @fbsql_field_type($id, $i), |
'len' => @fbsql_field_len($id, $i), |
'flags' => @fbsql_field_flags($id, $i), |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@fbsql_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SELECT "table_name" FROM information_schema.tables' |
. ' t0, information_schema.schemata t1' |
. ' WHERE t0.schema_pk=t1.schema_pk AND' |
. ' "table_type" = \'BASE TABLE\'' |
. ' AND "schema_name" = current_schema'; |
case 'views': |
return 'SELECT "table_name" FROM information_schema.tables' |
. ' t0, information_schema.schemata t1' |
. ' WHERE t0.schema_pk=t1.schema_pk AND' |
. ' "table_type" = \'VIEW\'' |
. ' AND "schema_name" = current_schema'; |
case 'users': |
return 'SELECT "user_name" from information_schema.users'; |
case 'functions': |
return 'SELECT "routine_name" FROM' |
. ' information_schema.psm_routines' |
. ' t0, information_schema.schemata t1' |
. ' WHERE t0.schema_pk=t1.schema_pk' |
. ' AND "routine_kind"=\'FUNCTION\'' |
. ' AND "schema_name" = current_schema'; |
case 'procedures': |
return 'SELECT "routine_name" FROM' |
. ' information_schema.psm_routines' |
. ' t0, information_schema.schemata t1' |
. ' WHERE t0.schema_pk=t1.schema_pk' |
. ' AND "routine_kind"=\'PROCEDURE\'' |
. ' AND "schema_name" = current_schema'; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/odbc.php |
---|
Новый файл |
0,0 → 1,883 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's odbc extension |
* for interacting with databases via ODBC connections |
* |
* 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 <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: odbc.php,v 1.81 2007/07/06 05:19:21 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's odbc extension |
* for interacting with databases via ODBC connections |
* |
* These methods overload the ones declared in DB_common. |
* |
* More info on ODBC errors could be found here: |
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_odbc extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'odbc'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'sql92'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* NOTE: The feature set of the following drivers are different than |
* the default: |
* + solid: 'transactions' = true |
* + navision: 'limit' = false |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'emulate', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => false, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
'01004' => DB_ERROR_TRUNCATED, |
'07001' => DB_ERROR_MISMATCH, |
'21S01' => DB_ERROR_VALUE_COUNT_ON_ROW, |
'21S02' => DB_ERROR_MISMATCH, |
'22001' => DB_ERROR_INVALID, |
'22003' => DB_ERROR_INVALID_NUMBER, |
'22005' => DB_ERROR_INVALID_NUMBER, |
'22008' => DB_ERROR_INVALID_DATE, |
'22012' => DB_ERROR_DIVZERO, |
'23000' => DB_ERROR_CONSTRAINT, |
'23502' => DB_ERROR_CONSTRAINT_NOT_NULL, |
'23503' => DB_ERROR_CONSTRAINT, |
'23504' => DB_ERROR_CONSTRAINT, |
'23505' => DB_ERROR_CONSTRAINT, |
'24000' => DB_ERROR_INVALID, |
'34000' => DB_ERROR_INVALID, |
'37000' => DB_ERROR_SYNTAX, |
'42000' => DB_ERROR_SYNTAX, |
'42601' => DB_ERROR_SYNTAX, |
'IM001' => DB_ERROR_UNSUPPORTED, |
'S0000' => DB_ERROR_NOSUCHTABLE, |
'S0001' => DB_ERROR_ALREADY_EXISTS, |
'S0002' => DB_ERROR_NOSUCHTABLE, |
'S0011' => DB_ERROR_ALREADY_EXISTS, |
'S0012' => DB_ERROR_NOT_FOUND, |
'S0021' => DB_ERROR_ALREADY_EXISTS, |
'S0022' => DB_ERROR_NOSUCHFIELD, |
'S1009' => DB_ERROR_INVALID, |
'S1090' => DB_ERROR_INVALID, |
'S1C00' => DB_ERROR_NOT_CAPABLE, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* The number of rows affected by a data manipulation query |
* @var integer |
* @access private |
*/ |
var $affected = 0; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_odbc() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's odbc driver supports the following extra DSN options: |
* + cursor The type of cursor to be used for this connection. |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('odbc')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
switch ($this->dbsyntax) { |
case 'access': |
case 'db2': |
case 'solid': |
$this->features['transactions'] = true; |
break; |
case 'navision': |
$this->features['limit'] = false; |
} |
/* |
* This is hear for backwards compatibility. Should have been using |
* 'database' all along, but prior to 1.6.0RC3 'hostspec' was used. |
*/ |
if ($dsn['database']) { |
$odbcdsn = $dsn['database']; |
} elseif ($dsn['hostspec']) { |
$odbcdsn = $dsn['hostspec']; |
} else { |
$odbcdsn = 'localhost'; |
} |
$connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect'; |
if (empty($dsn['cursor'])) { |
$this->connection = @$connect_function($odbcdsn, $dsn['username'], |
$dsn['password']); |
} else { |
$this->connection = @$connect_function($odbcdsn, $dsn['username'], |
$dsn['password'], |
$dsn['cursor']); |
} |
if (!is_resource($this->connection)) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$this->errorNative()); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$err = @odbc_close($this->connection); |
$this->connection = null; |
return $err; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
$result = @odbc_exec($this->connection, $query); |
if (!$result) { |
return $this->odbcRaiseError(); // XXX ERRORMSG |
} |
// Determine which queries that should return data, and which |
// should return an error code only. |
if ($this->_checkManip($query)) { |
$this->affected = $result; // For affectedRows() |
return DB_OK; |
} |
$this->affected = 0; |
return $result; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal odbc result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return @odbc_next_result($result); |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
$arr = array(); |
if ($rownum !== null) { |
$rownum++; // ODBC first row is 1 |
if (version_compare(phpversion(), '4.2.0', 'ge')) { |
$cols = @odbc_fetch_into($result, $arr, $rownum); |
} else { |
$cols = @odbc_fetch_into($result, $rownum, $arr); |
} |
} else { |
$cols = @odbc_fetch_into($result, $arr); |
} |
if (!$cols) { |
return null; |
} |
if ($fetchmode !== DB_FETCHMODE_ORDERED) { |
for ($i = 0; $i < count($arr); $i++) { |
$colName = @odbc_field_name($result, $i+1); |
$a[$colName] = $arr[$i]; |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$a = array_change_key_case($a, CASE_LOWER); |
} |
$arr = $a; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? odbc_free_result($result) : false; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @odbc_num_fields($result); |
if (!$cols) { |
return $this->odbcRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if (empty($this->affected)) { // In case of SELECT stms |
return 0; |
} |
$nrows = @odbc_num_rows($this->affected); |
if ($nrows == -1) { |
return $this->odbcRaiseError(); |
} |
return $nrows; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* Not all ODBC drivers support this functionality. If they don't |
* a DB_Error object for DB_ERROR_UNSUPPORTED is returned. |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$nrows = @odbc_num_rows($result); |
if ($nrows == -1) { |
return $this->odbcRaiseError(DB_ERROR_UNSUPPORTED); |
} |
if ($nrows === false) { |
return $this->odbcRaiseError(); |
} |
return $nrows; |
} |
// }}} |
// {{{ quoteIdentifier() |
/** |
* Quotes a string so it can be safely used as a table or column name |
* |
* Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked |
* "Use ANSI quoted identifiers" when setting up the ODBC data source. |
* |
* @param string $str identifier name to be quoted |
* |
* @return string quoted identifier string |
* |
* @see DB_common::quoteIdentifier() |
* @since Method available since Release 1.6.0 |
*/ |
function quoteIdentifier($str) |
{ |
switch ($this->dsn['dbsyntax']) { |
case 'access': |
return '[' . $str . ']'; |
case 'mssql': |
case 'sybase': |
return '[' . str_replace(']', ']]', $str) . ']'; |
case 'mysql': |
case 'mysqli': |
return '`' . $str . '`'; |
default: |
return '"' . str_replace('"', '""', $str) . '"'; |
} |
} |
// }}} |
// {{{ quote() |
/** |
* @deprecated Deprecated in release 1.6.0 |
* @internal |
*/ |
function quote($str) |
{ |
return $this->quoteSmart($str); |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_odbc::createSequence(), DB_odbc::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$repeat = 0; |
do { |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("update ${seqname} set id = id + 1"); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) { |
$repeat = 1; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->createSequence($seq_name); |
$this->popErrorHandling(); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$result = $this->query("insert into ${seqname} (id) values(0)"); |
} else { |
$repeat = 0; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$result = $this->query("select id from ${seqname}"); |
if (DB::isError($result)) { |
return $result; |
} |
$row = $result->fetchRow(DB_FETCHMODE_ORDERED); |
if (DB::isError($row || !$row)) { |
return $row; |
} |
return $row[0]; |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_odbc::nextID(), DB_odbc::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
return $this->query('CREATE TABLE ' |
. $this->getSequenceName($seq_name) |
. ' (id integer NOT NULL,' |
. ' PRIMARY KEY(id))'); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_odbc::nextID(), DB_odbc::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
if (!@odbc_autocommit($this->connection, $onoff)) { |
return $this->odbcRaiseError(); |
} |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if (!@odbc_commit($this->connection)) { |
return $this->odbcRaiseError(); |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if (!@odbc_rollback($this->connection)) { |
return $this->odbcRaiseError(); |
} |
return DB_OK; |
} |
// }}} |
// {{{ odbcRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_odbc::errorNative(), DB_common::errorCode() |
*/ |
function odbcRaiseError($errno = null) |
{ |
if ($errno === null) { |
switch ($this->dbsyntax) { |
case 'access': |
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { |
$this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD; |
} else { |
// Doing this in case mode changes during runtime. |
$this->errorcode_map['07001'] = DB_ERROR_MISMATCH; |
} |
$native_code = odbc_error($this->connection); |
// S1000 is for "General Error." Let's be more specific. |
if ($native_code == 'S1000') { |
$errormsg = odbc_errormsg($this->connection); |
static $error_regexps; |
if (!isset($error_regexps)) { |
$error_regexps = array( |
'/includes related records.$/i' => DB_ERROR_CONSTRAINT, |
'/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL, |
); |
} |
foreach ($error_regexps as $regexp => $code) { |
if (preg_match($regexp, $errormsg)) { |
return $this->raiseError($code, |
null, null, null, |
$native_code . ' ' . $errormsg); |
} |
} |
$errno = DB_ERROR; |
} else { |
$errno = $this->errorCode($native_code); |
} |
break; |
default: |
$errno = $this->errorCode(odbc_error($this->connection)); |
} |
} |
return $this->raiseError($errno, null, null, null, |
$this->errorNative()); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code and message produced by the last query |
* |
* @return string the DBMS' error code and message |
*/ |
function errorNative() |
{ |
if (!is_resource($this->connection)) { |
return @odbc_error() . ' ' . @odbc_errormsg(); |
} |
return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection); |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
* @since Method available since Release 1.7.0 |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @odbc_exec($this->connection, "SELECT * FROM $result"); |
if (!$id) { |
return $this->odbcRaiseError(); |
} |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->odbcRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @odbc_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$col = $i + 1; |
$res[$i] = array( |
'table' => $got_string ? $case_func($result) : '', |
'name' => $case_func(@odbc_field_name($id, $col)), |
'type' => @odbc_field_type($id, $col), |
'len' => @odbc_field_len($id, $col), |
'flags' => '', |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@odbc_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* Thanks to symbol1@gmail.com and Philippe.Jausions@11abacus.com. |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the list of objects requested |
* |
* @access protected |
* @see DB_common::getListOf() |
* @since Method available since Release 1.7.0 |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'databases': |
if (!function_exists('odbc_data_source')) { |
return null; |
} |
$res = @odbc_data_source($this->connection, SQL_FETCH_FIRST); |
if (is_array($res)) { |
$out = array($res['server']); |
while($res = @odbc_data_source($this->connection, |
SQL_FETCH_NEXT)) |
{ |
$out[] = $res['server']; |
} |
return $out; |
} else { |
return $this->odbcRaiseError(); |
} |
break; |
case 'tables': |
case 'schema.tables': |
$keep = 'TABLE'; |
break; |
case 'views': |
$keep = 'VIEW'; |
break; |
default: |
return null; |
} |
/* |
* Removing non-conforming items in the while loop rather than |
* in the odbc_tables() call because some backends choke on this: |
* odbc_tables($this->connection, '', '', '', 'TABLE') |
*/ |
$res = @odbc_tables($this->connection); |
if (!$res) { |
return $this->odbcRaiseError(); |
} |
$out = array(); |
while ($row = odbc_fetch_array($res)) { |
if ($row['TABLE_TYPE'] != $keep) { |
continue; |
} |
if ($type == 'schema.tables') { |
$out[] = $row['TABLE_SCHEM'] . '.' . $row['TABLE_NAME']; |
} else { |
$out[] = $row['TABLE_NAME']; |
} |
} |
return $out; |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/common.php |
---|
Новый файл |
0,0 → 1,2257 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Contains the DB_common base class |
* |
* 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 <ssb@php.net> |
* @author Tomas V.V. Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: common.php,v 1.143 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the PEAR class so it can be extended from |
*/ |
require_once 'PEAR.php'; |
/** |
* DB_common is the base class from which each database driver class extends |
* |
* All common methods are declared here. If a given DBMS driver contains |
* a particular method, that method will overload the one here. |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @author Tomas V.V. Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_common extends PEAR |
{ |
// {{{ properties |
/** |
* The current default fetch mode |
* @var integer |
*/ |
var $fetchmode = DB_FETCHMODE_ORDERED; |
/** |
* The name of the class into which results should be fetched when |
* DB_FETCHMODE_OBJECT is in effect |
* |
* @var string |
*/ |
var $fetchmode_object_class = 'stdClass'; |
/** |
* Was a connection present when the object was serialized()? |
* @var bool |
* @see DB_common::__sleep(), DB_common::__wake() |
*/ |
var $was_connected = null; |
/** |
* The most recently executed query |
* @var string |
*/ |
var $last_query = ''; |
/** |
* Run-time configuration options |
* |
* The 'optimize' option has been deprecated. Use the 'portability' |
* option instead. |
* |
* @var array |
* @see DB_common::setOption() |
*/ |
var $options = array( |
'result_buffering' => 500, |
'persistent' => false, |
'ssl' => false, |
'debug' => 0, |
'seqname_format' => '%s_seq', |
'autofree' => false, |
'portability' => DB_PORTABILITY_NONE, |
'optimize' => 'performance', // Deprecated. Use 'portability'. |
); |
/** |
* The parameters from the most recently executed query |
* @var array |
* @since Property available since Release 1.7.0 |
*/ |
var $last_parameters = array(); |
/** |
* The elements from each prepared statement |
* @var array |
*/ |
var $prepare_tokens = array(); |
/** |
* The data types of the various elements in each prepared statement |
* @var array |
*/ |
var $prepare_types = array(); |
/** |
* The prepared queries |
* @var array |
*/ |
var $prepared_queries = array(); |
/** |
* Flag indicating that the last query was a manipulation query. |
* @access protected |
* @var boolean |
*/ |
var $_last_query_manip = false; |
/** |
* Flag indicating that the next query <em>must</em> be a manipulation |
* query. |
* @access protected |
* @var boolean |
*/ |
var $_next_query_manip = false; |
// }}} |
// {{{ DB_common |
/** |
* This constructor calls <kbd>$this->PEAR('DB_Error')</kbd> |
* |
* @return void |
*/ |
function DB_common() |
{ |
$this->PEAR('DB_Error'); |
} |
// }}} |
// {{{ __sleep() |
/** |
* Automatically indicates which properties should be saved |
* when PHP's serialize() function is called |
* |
* @return array the array of properties names that should be saved |
*/ |
function __sleep() |
{ |
if ($this->connection) { |
// Don't disconnect(), people use serialize() for many reasons |
$this->was_connected = true; |
} else { |
$this->was_connected = false; |
} |
if (isset($this->autocommit)) { |
return array('autocommit', |
'dbsyntax', |
'dsn', |
'features', |
'fetchmode', |
'fetchmode_object_class', |
'options', |
'was_connected', |
); |
} else { |
return array('dbsyntax', |
'dsn', |
'features', |
'fetchmode', |
'fetchmode_object_class', |
'options', |
'was_connected', |
); |
} |
} |
// }}} |
// {{{ __wakeup() |
/** |
* Automatically reconnects to the database when PHP's unserialize() |
* function is called |
* |
* The reconnection attempt is only performed if the object was connected |
* at the time PHP's serialize() function was run. |
* |
* @return void |
*/ |
function __wakeup() |
{ |
if ($this->was_connected) { |
$this->connect($this->dsn, $this->options); |
} |
} |
// }}} |
// {{{ __toString() |
/** |
* Automatic string conversion for PHP 5 |
* |
* @return string a string describing the current PEAR DB object |
* |
* @since Method available since Release 1.7.0 |
*/ |
function __toString() |
{ |
$info = strtolower(get_class($this)); |
$info .= ': (phptype=' . $this->phptype . |
', dbsyntax=' . $this->dbsyntax . |
')'; |
if ($this->connection) { |
$info .= ' [connected]'; |
} |
return $info; |
} |
// }}} |
// {{{ toString() |
/** |
* DEPRECATED: String conversion method |
* |
* @return string a string describing the current PEAR DB object |
* |
* @deprecated Method deprecated in Release 1.7.0 |
*/ |
function toString() |
{ |
return $this->__toString(); |
} |
// }}} |
// {{{ quoteString() |
/** |
* DEPRECATED: Quotes a string so it can be safely used within string |
* delimiters in a query |
* |
* @param string $string the string to be quoted |
* |
* @return string the quoted string |
* |
* @see DB_common::quoteSmart(), DB_common::escapeSimple() |
* @deprecated Method deprecated some time before Release 1.2 |
*/ |
function quoteString($string) |
{ |
$string = $this->quote($string); |
if ($string{0} == "'") { |
return substr($string, 1, -1); |
} |
return $string; |
} |
// }}} |
// {{{ quote() |
/** |
* DEPRECATED: Quotes a string so it can be safely used in a query |
* |
* @param string $string the string to quote |
* |
* @return string the quoted string or the string <samp>NULL</samp> |
* if the value submitted is <kbd>null</kbd>. |
* |
* @see DB_common::quoteSmart(), DB_common::escapeSimple() |
* @deprecated Deprecated in release 1.6.0 |
*/ |
function quote($string = null) |
{ |
return ($string === null) ? 'NULL' |
: "'" . str_replace("'", "''", $string) . "'"; |
} |
// }}} |
// {{{ quoteIdentifier() |
/** |
* Quotes a string so it can be safely used as a table or column name |
* |
* Delimiting style depends on which database driver is being used. |
* |
* NOTE: just because you CAN use delimited identifiers doesn't mean |
* you SHOULD use them. In general, they end up causing way more |
* problems than they solve. |
* |
* Portability is broken by using the following characters inside |
* delimited identifiers: |
* + backtick (<kbd>`</kbd>) -- due to MySQL |
* + double quote (<kbd>"</kbd>) -- due to Oracle |
* + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access |
* |
* Delimited identifiers are known to generally work correctly under |
* the following drivers: |
* + mssql |
* + mysql |
* + mysqli |
* + oci8 |
* + odbc(access) |
* + odbc(db2) |
* + pgsql |
* + sqlite |
* + sybase (must execute <kbd>set quoted_identifier on</kbd> sometime |
* prior to use) |
* |
* InterBase doesn't seem to be able to use delimited identifiers |
* via PHP 4. They work fine under PHP 5. |
* |
* @param string $str the identifier name to be quoted |
* |
* @return string the quoted identifier |
* |
* @since Method available since Release 1.6.0 |
*/ |
function quoteIdentifier($str) |
{ |
return '"' . str_replace('"', '""', $str) . '"'; |
} |
// }}} |
// {{{ quoteSmart() |
/** |
* Formats input so it can be safely used in a query |
* |
* The output depends on the PHP data type of input and the database |
* type being used. |
* |
* @param mixed $in the data to be formatted |
* |
* @return mixed the formatted data. The format depends on the input's |
* PHP type: |
* <ul> |
* <li> |
* <kbd>input</kbd> -> <samp>returns</samp> |
* </li> |
* <li> |
* <kbd>null</kbd> -> the string <samp>NULL</samp> |
* </li> |
* <li> |
* <kbd>integer</kbd> or <kbd>double</kbd> -> the unquoted number |
* </li> |
* <li> |
* <kbd>bool</kbd> -> output depends on the driver in use |
* Most drivers return integers: <samp>1</samp> if |
* <kbd>true</kbd> or <samp>0</samp> if |
* <kbd>false</kbd>. |
* Some return strings: <samp>TRUE</samp> if |
* <kbd>true</kbd> or <samp>FALSE</samp> if |
* <kbd>false</kbd>. |
* Finally one returns strings: <samp>T</samp> if |
* <kbd>true</kbd> or <samp>F</samp> if |
* <kbd>false</kbd>. Here is a list of each DBMS, |
* the values returned and the suggested column type: |
* <ul> |
* <li> |
* <kbd>dbase</kbd> -> <samp>T/F</samp> |
* (<kbd>Logical</kbd>) |
* </li> |
* <li> |
* <kbd>fbase</kbd> -> <samp>TRUE/FALSE</samp> |
* (<kbd>BOOLEAN</kbd>) |
* </li> |
* <li> |
* <kbd>ibase</kbd> -> <samp>1/0</samp> |
* (<kbd>SMALLINT</kbd>) [1] |
* </li> |
* <li> |
* <kbd>ifx</kbd> -> <samp>1/0</samp> |
* (<kbd>SMALLINT</kbd>) [1] |
* </li> |
* <li> |
* <kbd>msql</kbd> -> <samp>1/0</samp> |
* (<kbd>INTEGER</kbd>) |
* </li> |
* <li> |
* <kbd>mssql</kbd> -> <samp>1/0</samp> |
* (<kbd>BIT</kbd>) |
* </li> |
* <li> |
* <kbd>mysql</kbd> -> <samp>1/0</samp> |
* (<kbd>TINYINT(1)</kbd>) |
* </li> |
* <li> |
* <kbd>mysqli</kbd> -> <samp>1/0</samp> |
* (<kbd>TINYINT(1)</kbd>) |
* </li> |
* <li> |
* <kbd>oci8</kbd> -> <samp>1/0</samp> |
* (<kbd>NUMBER(1)</kbd>) |
* </li> |
* <li> |
* <kbd>odbc</kbd> -> <samp>1/0</samp> |
* (<kbd>SMALLINT</kbd>) [1] |
* </li> |
* <li> |
* <kbd>pgsql</kbd> -> <samp>TRUE/FALSE</samp> |
* (<kbd>BOOLEAN</kbd>) |
* </li> |
* <li> |
* <kbd>sqlite</kbd> -> <samp>1/0</samp> |
* (<kbd>INTEGER</kbd>) |
* </li> |
* <li> |
* <kbd>sybase</kbd> -> <samp>1/0</samp> |
* (<kbd>TINYINT(1)</kbd>) |
* </li> |
* </ul> |
* [1] Accommodate the lowest common denominator because not all |
* versions of have <kbd>BOOLEAN</kbd>. |
* </li> |
* <li> |
* other (including strings and numeric strings) -> |
* the data with single quotes escaped by preceeding |
* single quotes, backslashes are escaped by preceeding |
* backslashes, then the whole string is encapsulated |
* between single quotes |
* </li> |
* </ul> |
* |
* @see DB_common::escapeSimple() |
* @since Method available since Release 1.6.0 |
*/ |
function quoteSmart($in) |
{ |
if (is_int($in)) { |
return $in; |
} elseif (is_float($in)) { |
return $this->quoteFloat($in); |
} elseif (is_bool($in)) { |
return $this->quoteBoolean($in); |
} elseif (is_null($in)) { |
return 'NULL'; |
} else { |
if ($this->dbsyntax == 'access' |
&& preg_match('/^#.+#$/', $in)) |
{ |
return $this->escapeSimple($in); |
} |
return "'" . $this->escapeSimple($in) . "'"; |
} |
} |
// }}} |
// {{{ quoteBoolean() |
/** |
* Formats a boolean value for use within a query in a locale-independent |
* manner. |
* |
* @param boolean the boolean value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteBoolean($boolean) { |
return $boolean ? '1' : '0'; |
} |
// }}} |
// {{{ quoteFloat() |
/** |
* Formats a float value for use within a query in a locale-independent |
* manner. |
* |
* @param float the float value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteFloat($float) { |
return "'".$this->escapeSimple(str_replace(',', '.', strval(floatval($float))))."'"; |
} |
// }}} |
// {{{ escapeSimple() |
/** |
* Escapes a string according to the current DBMS's standards |
* |
* In SQLite, this makes things safe for inserts/updates, but may |
* cause problems when performing text comparisons against columns |
* containing binary data. See the |
* {@link http://php.net/sqlite_escape_string PHP manual} for more info. |
* |
* @param string $str the string to be escaped |
* |
* @return string the escaped string |
* |
* @see DB_common::quoteSmart() |
* @since Method available since Release 1.6.0 |
*/ |
function escapeSimple($str) |
{ |
return str_replace("'", "''", $str); |
} |
// }}} |
// {{{ provides() |
/** |
* Tells whether the present driver supports a given feature |
* |
* @param string $feature the feature you're curious about |
* |
* @return bool whether this driver supports $feature |
*/ |
function provides($feature) |
{ |
return $this->features[$feature]; |
} |
// }}} |
// {{{ setFetchMode() |
/** |
* Sets the fetch mode that should be used by default for query results |
* |
* @param integer $fetchmode DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC |
* or DB_FETCHMODE_OBJECT |
* @param string $object_class the class name of the object to be returned |
* by the fetch methods when the |
* DB_FETCHMODE_OBJECT mode is selected. |
* If no class is specified by default a cast |
* to object from the assoc array row will be |
* done. There is also the posibility to use |
* and extend the 'DB_row' class. |
* |
* @see DB_FETCHMODE_ORDERED, DB_FETCHMODE_ASSOC, DB_FETCHMODE_OBJECT |
*/ |
function setFetchMode($fetchmode, $object_class = 'stdClass') |
{ |
switch ($fetchmode) { |
case DB_FETCHMODE_OBJECT: |
$this->fetchmode_object_class = $object_class; |
case DB_FETCHMODE_ORDERED: |
case DB_FETCHMODE_ASSOC: |
$this->fetchmode = $fetchmode; |
break; |
default: |
return $this->raiseError('invalid fetchmode mode'); |
} |
} |
// }}} |
// {{{ setOption() |
/** |
* Sets run-time configuration options for PEAR DB |
* |
* Options, their data types, default values and description: |
* <ul> |
* <li> |
* <var>autofree</var> <kbd>boolean</kbd> = <samp>false</samp> |
* <br />should results be freed automatically when there are no |
* more rows? |
* </li><li> |
* <var>result_buffering</var> <kbd>integer</kbd> = <samp>500</samp> |
* <br />how many rows of the result set should be buffered? |
* <br />In mysql: mysql_unbuffered_query() is used instead of |
* mysql_query() if this value is 0. (Release 1.7.0) |
* <br />In oci8: this value is passed to ocisetprefetch(). |
* (Release 1.7.0) |
* </li><li> |
* <var>debug</var> <kbd>integer</kbd> = <samp>0</samp> |
* <br />debug level |
* </li><li> |
* <var>persistent</var> <kbd>boolean</kbd> = <samp>false</samp> |
* <br />should the connection be persistent? |
* </li><li> |
* <var>portability</var> <kbd>integer</kbd> = <samp>DB_PORTABILITY_NONE</samp> |
* <br />portability mode constant (see below) |
* </li><li> |
* <var>seqname_format</var> <kbd>string</kbd> = <samp>%s_seq</samp> |
* <br />the sprintf() format string used on sequence names. This |
* format is applied to sequence names passed to |
* createSequence(), nextID() and dropSequence(). |
* </li><li> |
* <var>ssl</var> <kbd>boolean</kbd> = <samp>false</samp> |
* <br />use ssl to connect? |
* </li> |
* </ul> |
* |
* ----------------------------------------- |
* |
* PORTABILITY MODES |
* |
* These modes are bitwised, so they can be combined using <kbd>|</kbd> |
* and removed using <kbd>^</kbd>. See the examples section below on how |
* to do this. |
* |
* <samp>DB_PORTABILITY_NONE</samp> |
* turn off all portability features |
* |
* This mode gets automatically turned on if the deprecated |
* <var>optimize</var> option gets set to <samp>performance</samp>. |
* |
* |
* <samp>DB_PORTABILITY_LOWERCASE</samp> |
* convert names of tables and fields to lower case when using |
* <kbd>get*()</kbd>, <kbd>fetch*()</kbd> and <kbd>tableInfo()</kbd> |
* |
* This mode gets automatically turned on in the following databases |
* if the deprecated option <var>optimize</var> gets set to |
* <samp>portability</samp>: |
* + oci8 |
* |
* |
* <samp>DB_PORTABILITY_RTRIM</samp> |
* right trim the data output by <kbd>get*()</kbd> <kbd>fetch*()</kbd> |
* |
* |
* <samp>DB_PORTABILITY_DELETE_COUNT</samp> |
* force reporting the number of rows deleted |
* |
* Some DBMS's don't count the number of rows deleted when performing |
* simple <kbd>DELETE FROM tablename</kbd> queries. This portability |
* mode tricks such DBMS's into telling the count by adding |
* <samp>WHERE 1=1</samp> to the end of <kbd>DELETE</kbd> queries. |
* |
* This mode gets automatically turned on in the following databases |
* if the deprecated option <var>optimize</var> gets set to |
* <samp>portability</samp>: |
* + fbsql |
* + mysql |
* + mysqli |
* + sqlite |
* |
* |
* <samp>DB_PORTABILITY_NUMROWS</samp> |
* enable hack that makes <kbd>numRows()</kbd> work in Oracle |
* |
* This mode gets automatically turned on in the following databases |
* if the deprecated option <var>optimize</var> gets set to |
* <samp>portability</samp>: |
* + oci8 |
* |
* |
* <samp>DB_PORTABILITY_ERRORS</samp> |
* makes certain error messages in certain drivers compatible |
* with those from other DBMS's |
* |
* + mysql, mysqli: change unique/primary key constraints |
* DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT |
* |
* + odbc(access): MS's ODBC driver reports 'no such field' as code |
* 07001, which means 'too few parameters.' When this option is on |
* that code gets mapped to DB_ERROR_NOSUCHFIELD. |
* DB_ERROR_MISMATCH -> DB_ERROR_NOSUCHFIELD |
* |
* <samp>DB_PORTABILITY_NULL_TO_EMPTY</samp> |
* convert null values to empty strings in data output by get*() and |
* fetch*(). Needed because Oracle considers empty strings to be null, |
* while most other DBMS's know the difference between empty and null. |
* |
* |
* <samp>DB_PORTABILITY_ALL</samp> |
* turn on all portability features |
* |
* ----------------------------------------- |
* |
* Example 1. Simple setOption() example |
* <code> |
* $db->setOption('autofree', true); |
* </code> |
* |
* Example 2. Portability for lowercasing and trimming |
* <code> |
* $db->setOption('portability', |
* DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_RTRIM); |
* </code> |
* |
* Example 3. All portability options except trimming |
* <code> |
* $db->setOption('portability', |
* DB_PORTABILITY_ALL ^ DB_PORTABILITY_RTRIM); |
* </code> |
* |
* @param string $option option name |
* @param mixed $value value for the option |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::$options |
*/ |
function setOption($option, $value) |
{ |
if (isset($this->options[$option])) { |
$this->options[$option] = $value; |
/* |
* Backwards compatibility check for the deprecated 'optimize' |
* option. Done here in case settings change after connecting. |
*/ |
if ($option == 'optimize') { |
if ($value == 'portability') { |
switch ($this->phptype) { |
case 'oci8': |
$this->options['portability'] = |
DB_PORTABILITY_LOWERCASE | |
DB_PORTABILITY_NUMROWS; |
break; |
case 'fbsql': |
case 'mysql': |
case 'mysqli': |
case 'sqlite': |
$this->options['portability'] = |
DB_PORTABILITY_DELETE_COUNT; |
break; |
} |
} else { |
$this->options['portability'] = DB_PORTABILITY_NONE; |
} |
} |
return DB_OK; |
} |
return $this->raiseError("unknown option $option"); |
} |
// }}} |
// {{{ getOption() |
/** |
* Returns the value of an option |
* |
* @param string $option the option name you're curious about |
* |
* @return mixed the option's value |
*/ |
function getOption($option) |
{ |
if (isset($this->options[$option])) { |
return $this->options[$option]; |
} |
return $this->raiseError("unknown option $option"); |
} |
// }}} |
// {{{ prepare() |
/** |
* Prepares a query for multiple execution with execute() |
* |
* Creates a query that can be run multiple times. Each time it is run, |
* the placeholders, if any, will be replaced by the contents of |
* execute()'s $data argument. |
* |
* Three types of placeholders can be used: |
* + <kbd>?</kbd> scalar value (i.e. strings, integers). The system |
* will automatically quote and escape the data. |
* + <kbd>!</kbd> value is inserted 'as is' |
* + <kbd>&</kbd> requires a file name. The file's contents get |
* inserted into the query (i.e. saving binary |
* data in a db) |
* |
* Example 1. |
* <code> |
* $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); |
* $data = array( |
* "John's text", |
* "'it''s good'", |
* 'filename.txt' |
* ); |
* $res = $db->execute($sth, $data); |
* </code> |
* |
* Use backslashes to escape placeholder characters if you don't want |
* them to be interpreted as placeholders: |
* <pre> |
* "UPDATE foo SET col=? WHERE col='over \& under'" |
* </pre> |
* |
* With some database backends, this is emulated. |
* |
* {@internal ibase and oci8 have their own prepare() methods.}} |
* |
* @param string $query the query to be prepared |
* |
* @return mixed DB statement resource on success. A DB_Error object |
* on failure. |
* |
* @see DB_common::execute() |
*/ |
function prepare($query) |
{ |
$tokens = preg_split('/((?<!\\\)[&?!])/', $query, -1, |
PREG_SPLIT_DELIM_CAPTURE); |
$token = 0; |
$types = array(); |
$newtokens = array(); |
foreach ($tokens as $val) { |
switch ($val) { |
case '?': |
$types[$token++] = DB_PARAM_SCALAR; |
break; |
case '&': |
$types[$token++] = DB_PARAM_OPAQUE; |
break; |
case '!': |
$types[$token++] = DB_PARAM_MISC; |
break; |
default: |
$newtokens[] = preg_replace('/\\\([&?!])/', "\\1", $val); |
} |
} |
$this->prepare_tokens[] = &$newtokens; |
end($this->prepare_tokens); |
$k = key($this->prepare_tokens); |
$this->prepare_types[$k] = $types; |
$this->prepared_queries[$k] = implode(' ', $newtokens); |
return $k; |
} |
// }}} |
// {{{ autoPrepare() |
/** |
* Automaticaly generates an insert or update query and pass it to prepare() |
* |
* @param string $table the table name |
* @param array $table_fields the array of field names |
* @param int $mode a type of query to make: |
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE |
* @param string $where for update queries: the WHERE clause to |
* append to the SQL statement. Don't |
* include the "WHERE" keyword. |
* |
* @return resource the query handle |
* |
* @uses DB_common::prepare(), DB_common::buildManipSQL() |
*/ |
function autoPrepare($table, $table_fields, $mode = DB_AUTOQUERY_INSERT, |
$where = false) |
{ |
$query = $this->buildManipSQL($table, $table_fields, $mode, $where); |
if (DB::isError($query)) { |
return $query; |
} |
return $this->prepare($query); |
} |
// }}} |
// {{{ autoExecute() |
/** |
* Automaticaly generates an insert or update query and call prepare() |
* and execute() with it |
* |
* @param string $table the table name |
* @param array $fields_values the associative array where $key is a |
* field name and $value its value |
* @param int $mode a type of query to make: |
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE |
* @param string $where for update queries: the WHERE clause to |
* append to the SQL statement. Don't |
* include the "WHERE" keyword. |
* |
* @return mixed a new DB_result object for successful SELECT queries |
* or DB_OK for successul data manipulation queries. |
* A DB_Error object on failure. |
* |
* @uses DB_common::autoPrepare(), DB_common::execute() |
*/ |
function autoExecute($table, $fields_values, $mode = DB_AUTOQUERY_INSERT, |
$where = false) |
{ |
$sth = $this->autoPrepare($table, array_keys($fields_values), $mode, |
$where); |
if (DB::isError($sth)) { |
return $sth; |
} |
$ret = $this->execute($sth, array_values($fields_values)); |
$this->freePrepared($sth); |
return $ret; |
} |
// }}} |
// {{{ buildManipSQL() |
/** |
* Produces an SQL query string for autoPrepare() |
* |
* Example: |
* <pre> |
* buildManipSQL('table_sql', array('field1', 'field2', 'field3'), |
* DB_AUTOQUERY_INSERT); |
* </pre> |
* |
* That returns |
* <samp> |
* INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?) |
* </samp> |
* |
* NOTES: |
* - This belongs more to a SQL Builder class, but this is a simple |
* facility. |
* - Be carefull! If you don't give a $where param with an UPDATE |
* query, all the records of the table will be updated! |
* |
* @param string $table the table name |
* @param array $table_fields the array of field names |
* @param int $mode a type of query to make: |
* DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE |
* @param string $where for update queries: the WHERE clause to |
* append to the SQL statement. Don't |
* include the "WHERE" keyword. |
* |
* @return string the sql query for autoPrepare() |
*/ |
function buildManipSQL($table, $table_fields, $mode, $where = false) |
{ |
if (count($table_fields) == 0) { |
return $this->raiseError(DB_ERROR_NEED_MORE_DATA); |
} |
$first = true; |
switch ($mode) { |
case DB_AUTOQUERY_INSERT: |
$values = ''; |
$names = ''; |
foreach ($table_fields as $value) { |
if ($first) { |
$first = false; |
} else { |
$names .= ','; |
$values .= ','; |
} |
$names .= $value; |
$values .= '?'; |
} |
return "INSERT INTO $table ($names) VALUES ($values)"; |
case DB_AUTOQUERY_UPDATE: |
$set = ''; |
foreach ($table_fields as $value) { |
if ($first) { |
$first = false; |
} else { |
$set .= ','; |
} |
$set .= "$value = ?"; |
} |
$sql = "UPDATE $table SET $set"; |
if ($where) { |
$sql .= " WHERE $where"; |
} |
return $sql; |
default: |
return $this->raiseError(DB_ERROR_SYNTAX); |
} |
} |
// }}} |
// {{{ execute() |
/** |
* Executes a DB statement prepared with prepare() |
* |
* Example 1. |
* <code> |
* $sth = $db->prepare('INSERT INTO tbl (a, b, c) VALUES (?, !, &)'); |
* $data = array( |
* "John's text", |
* "'it''s good'", |
* 'filename.txt' |
* ); |
* $res = $db->execute($sth, $data); |
* </code> |
* |
* @param resource $stmt a DB statement resource returned from prepare() |
* @param mixed $data array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return mixed a new DB_result object for successful SELECT queries |
* or DB_OK for successul data manipulation queries. |
* A DB_Error object on failure. |
* |
* {@internal ibase and oci8 have their own execute() methods.}} |
* |
* @see DB_common::prepare() |
*/ |
function &execute($stmt, $data = array()) |
{ |
$realquery = $this->executeEmulateQuery($stmt, $data); |
if (DB::isError($realquery)) { |
return $realquery; |
} |
$result = $this->simpleQuery($realquery); |
if ($result === DB_OK || DB::isError($result)) { |
return $result; |
} else { |
$tmp = new DB_result($this, $result); |
return $tmp; |
} |
} |
// }}} |
// {{{ executeEmulateQuery() |
/** |
* Emulates executing prepared statements if the DBMS not support them |
* |
* @param resource $stmt a DB statement resource returned from execute() |
* @param mixed $data array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return mixed a string containing the real query run when emulating |
* prepare/execute. A DB_Error object on failure. |
* |
* @access protected |
* @see DB_common::execute() |
*/ |
function executeEmulateQuery($stmt, $data = array()) |
{ |
$stmt = (int)$stmt; |
$data = (array)$data; |
$this->last_parameters = $data; |
if (count($this->prepare_types[$stmt]) != count($data)) { |
$this->last_query = $this->prepared_queries[$stmt]; |
return $this->raiseError(DB_ERROR_MISMATCH); |
} |
$realquery = $this->prepare_tokens[$stmt][0]; |
$i = 0; |
foreach ($data as $value) { |
if ($this->prepare_types[$stmt][$i] == DB_PARAM_SCALAR) { |
$realquery .= $this->quoteSmart($value); |
} elseif ($this->prepare_types[$stmt][$i] == DB_PARAM_OPAQUE) { |
$fp = @fopen($value, 'rb'); |
if (!$fp) { |
return $this->raiseError(DB_ERROR_ACCESS_VIOLATION); |
} |
$realquery .= $this->quoteSmart(fread($fp, filesize($value))); |
fclose($fp); |
} else { |
$realquery .= $value; |
} |
$realquery .= $this->prepare_tokens[$stmt][++$i]; |
} |
return $realquery; |
} |
// }}} |
// {{{ executeMultiple() |
/** |
* Performs several execute() calls on the same statement handle |
* |
* $data 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 $stmt query handle from prepare() |
* @param array $data numeric array containing the |
* data to insert into the query |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::prepare(), DB_common::execute() |
*/ |
function executeMultiple($stmt, $data) |
{ |
foreach ($data as $value) { |
$res = $this->execute($stmt, $value); |
if (DB::isError($res)) { |
return $res; |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ freePrepared() |
/** |
* Frees the internal resources associated with a prepared query |
* |
* @param resource $stmt the prepared statement's PHP resource |
* @param bool $free_resource should the PHP resource be freed too? |
* Use false if you need to get data |
* from the result set later. |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_common::prepare() |
*/ |
function freePrepared($stmt, $free_resource = true) |
{ |
$stmt = (int)$stmt; |
if (isset($this->prepare_tokens[$stmt])) { |
unset($this->prepare_tokens[$stmt]); |
unset($this->prepare_types[$stmt]); |
unset($this->prepared_queries[$stmt]); |
return true; |
} |
return false; |
} |
// }}} |
// {{{ modifyQuery() |
/** |
* Changes a query string for various DBMS specific reasons |
* |
* It is defined here to ensure all drivers have this method available. |
* |
* @param string $query the query string to modify |
* |
* @return string the modified query string |
* |
* @access protected |
* @see DB_mysql::modifyQuery(), DB_oci8::modifyQuery(), |
* DB_sqlite::modifyQuery() |
*/ |
function modifyQuery($query) |
{ |
return $query; |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* It is defined here to assure that all implementations |
* have this method defined. |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
return $query; |
} |
// }}} |
// {{{ query() |
/** |
* Sends a query to the database server |
* |
* The query string can be either a normal statement to be sent directly |
* to the server OR if <var>$params</var> are passed the query can have |
* placeholders and it will be passed through prepare() and execute(). |
* |
* @param string $query the SQL query or the statement to prepare |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return mixed a new DB_result object for successful SELECT queries |
* or DB_OK for successul data manipulation queries. |
* A DB_Error object on failure. |
* |
* @see DB_result, DB_common::prepare(), DB_common::execute() |
*/ |
function &query($query, $params = array()) |
{ |
if (sizeof($params) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
$ret = $this->execute($sth, $params); |
$this->freePrepared($sth, false); |
return $ret; |
} else { |
$this->last_parameters = array(); |
$result = $this->simpleQuery($query); |
if ($result === DB_OK || DB::isError($result)) { |
return $result; |
} else { |
$tmp = new DB_result($this, $result); |
return $tmp; |
} |
} |
} |
// }}} |
// {{{ limitQuery() |
/** |
* Generates and executes a LIMIT query |
* |
* @param string $query the query |
* @param intr $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return mixed a new DB_result object for successful SELECT queries |
* or DB_OK for successul data manipulation queries. |
* A DB_Error object on failure. |
*/ |
function &limitQuery($query, $from, $count, $params = array()) |
{ |
$query = $this->modifyLimitQuery($query, $from, $count, $params); |
if (DB::isError($query)){ |
return $query; |
} |
$result = $this->query($query, $params); |
if (is_a($result, 'DB_result')) { |
$result->setOption('limit_from', $from); |
$result->setOption('limit_count', $count); |
} |
return $result; |
} |
// }}} |
// {{{ getOne() |
/** |
* Fetches the first column of the first row from a query result |
* |
* Takes care of doing the query and freeing the results when finished. |
* |
* @param string $query the SQL query |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return mixed the returned value of the query. |
* A DB_Error object on failure. |
*/ |
function &getOne($query, $params = array()) |
{ |
$params = (array)$params; |
// modifyLimitQuery() would be nice here, but it causes BC issues |
if (sizeof($params) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
$res = $this->execute($sth, $params); |
$this->freePrepared($sth); |
} else { |
$res = $this->query($query); |
} |
if (DB::isError($res)) { |
return $res; |
} |
$err = $res->fetchInto($row, DB_FETCHMODE_ORDERED); |
$res->free(); |
if ($err !== DB_OK) { |
return $err; |
} |
return $row[0]; |
} |
// }}} |
// {{{ getRow() |
/** |
* Fetches the first row of data returned from a query result |
* |
* Takes care of doing the query and freeing the results when finished. |
* |
* @param string $query the SQL query |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* @param int $fetchmode the fetch mode to use |
* |
* @return array the first row of results as an array. |
* A DB_Error object on failure. |
*/ |
function &getRow($query, $params = array(), |
$fetchmode = DB_FETCHMODE_DEFAULT) |
{ |
// compat check, the params and fetchmode parameters used to |
// have the opposite order |
if (!is_array($params)) { |
if (is_array($fetchmode)) { |
if ($params === null) { |
$tmp = DB_FETCHMODE_DEFAULT; |
} else { |
$tmp = $params; |
} |
$params = $fetchmode; |
$fetchmode = $tmp; |
} elseif ($params !== null) { |
$fetchmode = $params; |
$params = array(); |
} |
} |
// modifyLimitQuery() would be nice here, but it causes BC issues |
if (sizeof($params) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
$res = $this->execute($sth, $params); |
$this->freePrepared($sth); |
} else { |
$res = $this->query($query); |
} |
if (DB::isError($res)) { |
return $res; |
} |
$err = $res->fetchInto($row, $fetchmode); |
$res->free(); |
if ($err !== DB_OK) { |
return $err; |
} |
return $row; |
} |
// }}} |
// {{{ getCol() |
/** |
* Fetches a single column from a query result and returns it as an |
* indexed array |
* |
* @param string $query the SQL query |
* @param mixed $col which column to return (integer [column number, |
* starting at 0] or string [column name]) |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return array the results as an array. A DB_Error object on failure. |
* |
* @see DB_common::query() |
*/ |
function &getCol($query, $col = 0, $params = array()) |
{ |
$params = (array)$params; |
if (sizeof($params) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
$res = $this->execute($sth, $params); |
$this->freePrepared($sth); |
} else { |
$res = $this->query($query); |
} |
if (DB::isError($res)) { |
return $res; |
} |
$fetchmode = is_int($col) ? DB_FETCHMODE_ORDERED : DB_FETCHMODE_ASSOC; |
if (!is_array($row = $res->fetchRow($fetchmode))) { |
$ret = array(); |
} else { |
if (!array_key_exists($col, $row)) { |
$ret = $this->raiseError(DB_ERROR_NOSUCHFIELD); |
} else { |
$ret = array($row[$col]); |
while (is_array($row = $res->fetchRow($fetchmode))) { |
$ret[] = $row[$col]; |
} |
} |
} |
$res->free(); |
if (DB::isError($row)) { |
$ret = $row; |
} |
return $ret; |
} |
// }}} |
// {{{ getAssoc() |
/** |
* Fetches an entire query result and returns 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 DB error code is |
* returned on errors. If the result set contains fewer than two |
* columns, a DB_ERROR_TRUNCATED error is returned. |
* |
* For example, if the table "mytable" contains: |
* |
* <pre> |
* ID TEXT DATE |
* -------------------------------- |
* 1 'one' 944679408 |
* 2 'two' 944679408 |
* 3 'three' 944679408 |
* </pre> |
* |
* Then the call getAssoc('SELECT id,text FROM mytable') returns: |
* <pre> |
* array( |
* '1' => 'one', |
* '2' => 'two', |
* '3' => 'three', |
* ) |
* </pre> |
* |
* ...while the call getAssoc('SELECT id,text,date FROM mytable') returns: |
* <pre> |
* array( |
* '1' => array('one', '944679408'), |
* '2' => array('two', '944679408'), |
* '3' => array('three', '944679408') |
* ) |
* </pre> |
* |
* 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: |
* |
* <pre> |
* getAssoc('SELECT category,id,name FROM mytable', false, null, |
* DB_FETCHMODE_ASSOC, 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') |
* ) |
* ) |
* </pre> |
* |
* Keep in mind that database functions in PHP usually return string |
* values for results regardless of the database's internal type. |
* |
* @param string $query the SQL query |
* @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 mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of |
* items passed must match quantity of |
* placeholders in query: meaning 1 |
* placeholder for non-array parameters or |
* 1 placeholder per array element. |
* @param int $fetchmode the fetch mode to use |
* @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 the associative array containing the query results. |
* A DB_Error object on failure. |
*/ |
function &getAssoc($query, $force_array = false, $params = array(), |
$fetchmode = DB_FETCHMODE_DEFAULT, $group = false) |
{ |
$params = (array)$params; |
if (sizeof($params) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
$res = $this->execute($sth, $params); |
$this->freePrepared($sth); |
} else { |
$res = $this->query($query); |
} |
if (DB::isError($res)) { |
return $res; |
} |
if ($fetchmode == DB_FETCHMODE_DEFAULT) { |
$fetchmode = $this->fetchmode; |
} |
$cols = $res->numCols(); |
if ($cols < 2) { |
$tmp = $this->raiseError(DB_ERROR_TRUNCATED); |
return $tmp; |
} |
$results = array(); |
if ($cols > 2 || $force_array) { |
// return array values |
// XXX this part can be optimized |
if ($fetchmode == DB_FETCHMODE_ASSOC) { |
while (is_array($row = $res->fetchRow(DB_FETCHMODE_ASSOC))) { |
reset($row); |
$key = current($row); |
unset($row[key($row)]); |
if ($group) { |
$results[$key][] = $row; |
} else { |
$results[$key] = $row; |
} |
} |
} elseif ($fetchmode == DB_FETCHMODE_OBJECT) { |
while ($row = $res->fetchRow(DB_FETCHMODE_OBJECT)) { |
$arr = get_object_vars($row); |
$key = current($arr); |
if ($group) { |
$results[$key][] = $row; |
} else { |
$results[$key] = $row; |
} |
} |
} else { |
while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { |
// we shift away the first element to get |
// indices running from 0 again |
$key = array_shift($row); |
if ($group) { |
$results[$key][] = $row; |
} else { |
$results[$key] = $row; |
} |
} |
} |
if (DB::isError($row)) { |
$results = $row; |
} |
} else { |
// return scalar values |
while (is_array($row = $res->fetchRow(DB_FETCHMODE_ORDERED))) { |
if ($group) { |
$results[$row[0]][] = $row[1]; |
} else { |
$results[$row[0]] = $row[1]; |
} |
} |
if (DB::isError($row)) { |
$results = $row; |
} |
} |
$res->free(); |
return $results; |
} |
// }}} |
// {{{ getAll() |
/** |
* Fetches all of the rows from a query result |
* |
* @param string $query the SQL query |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of |
* items passed must match quantity of |
* placeholders in query: meaning 1 |
* placeholder for non-array parameters or |
* 1 placeholder per array element. |
* @param int $fetchmode the fetch mode to use: |
* + DB_FETCHMODE_ORDERED |
* + DB_FETCHMODE_ASSOC |
* + DB_FETCHMODE_ORDERED | DB_FETCHMODE_FLIPPED |
* + DB_FETCHMODE_ASSOC | DB_FETCHMODE_FLIPPED |
* |
* @return array the nested array. A DB_Error object on failure. |
*/ |
function &getAll($query, $params = array(), |
$fetchmode = DB_FETCHMODE_DEFAULT) |
{ |
// compat check, the params and fetchmode parameters used to |
// have the opposite order |
if (!is_array($params)) { |
if (is_array($fetchmode)) { |
if ($params === null) { |
$tmp = DB_FETCHMODE_DEFAULT; |
} else { |
$tmp = $params; |
} |
$params = $fetchmode; |
$fetchmode = $tmp; |
} elseif ($params !== null) { |
$fetchmode = $params; |
$params = array(); |
} |
} |
if (sizeof($params) > 0) { |
$sth = $this->prepare($query); |
if (DB::isError($sth)) { |
return $sth; |
} |
$res = $this->execute($sth, $params); |
$this->freePrepared($sth); |
} else { |
$res = $this->query($query); |
} |
if ($res === DB_OK || DB::isError($res)) { |
return $res; |
} |
$results = array(); |
while (DB_OK === $res->fetchInto($row, $fetchmode)) { |
if ($fetchmode & DB_FETCHMODE_FLIPPED) { |
foreach ($row as $key => $val) { |
$results[$key][] = $val; |
} |
} else { |
$results[] = $row; |
} |
} |
$res->free(); |
if (DB::isError($row)) { |
$tmp = $this->raiseError($row); |
return $tmp; |
} |
return $results; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ numRows() |
/** |
* Determines the number of rows in a query result |
* |
* @param resource $result the query result idenifier produced by PHP |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function numRows($result) |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ getSequenceName() |
/** |
* Generates the name used inside the database for a sequence |
* |
* The createSequence() docblock contains notes about storing sequence |
* names. |
* |
* @param string $sqn the sequence's public name |
* |
* @return string the sequence's name in the backend |
* |
* @access protected |
* @see DB_common::createSequence(), DB_common::dropSequence(), |
* DB_common::nextID(), DB_common::setOption() |
*/ |
function getSequenceName($sqn) |
{ |
return sprintf($this->getOption('seqname_format'), |
preg_replace('/[^a-z0-9_.]/i', '_', $sqn)); |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::dropSequence(), |
* DB_common::getSequenceName() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ createSequence() |
/** |
* Creates a new sequence |
* |
* The name of a given sequence is determined by passing the string |
* provided in the <var>$seq_name</var> argument through PHP's sprintf() |
* function using the value from the <var>seqname_format</var> option as |
* the sprintf()'s format argument. |
* |
* <var>seqname_format</var> is set via setOption(). |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_common::nextID() |
*/ |
function createSequence($seq_name) |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_common::nextID() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ raiseError() |
/** |
* Communicates an error and invoke error callbacks, etc |
* |
* Basically a wrapper for PEAR::raiseError without the message string. |
* |
* @param mixed integer error code, or a PEAR error object (all |
* other parameters are ignored if this parameter is |
* an object |
* @param int error mode, see PEAR_Error docs |
* @param mixed if error mode is PEAR_ERROR_TRIGGER, this is the |
* error level (E_USER_NOTICE etc). If error mode is |
* PEAR_ERROR_CALLBACK, this is the callback function, |
* either as a function name, or as an array of an |
* object and method name. For other error modes this |
* parameter is ignored. |
* @param string extra debug information. Defaults to the last |
* query and native error code. |
* @param mixed native error code, integer or string depending the |
* backend |
* |
* @return object the PEAR_Error object |
* |
* @see PEAR_Error |
*/ |
function &raiseError($code = DB_ERROR, $mode = null, $options = null, |
$userinfo = null, $nativecode = null) |
{ |
// The error is yet a DB error object |
if (is_object($code)) { |
// because we the static PEAR::raiseError, our global |
// handler should be used if it is set |
if ($mode === null && !empty($this->_default_error_mode)) { |
$mode = $this->_default_error_mode; |
$options = $this->_default_error_options; |
} |
$tmp = PEAR::raiseError($code, null, $mode, $options, |
null, null, true); |
return $tmp; |
} |
if ($userinfo === null) { |
$userinfo = $this->last_query; |
} |
if ($nativecode) { |
$userinfo .= ' [nativecode=' . trim($nativecode) . ']'; |
} else { |
$userinfo .= ' [DB Error: ' . DB::errorMessage($code) . ']'; |
} |
$tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, |
'DB_Error', true); |
return $tmp; |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return mixed the DBMS' error code. A DB_Error object on failure. |
*/ |
function errorNative() |
{ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ errorCode() |
/** |
* Maps native error codes to DB's portable ones |
* |
* Uses the <var>$errorcode_map</var> property defined in each driver. |
* |
* @param string|int $nativecode the error code returned by the DBMS |
* |
* @return int the portable DB error code. Return DB_ERROR if the |
* current driver doesn't have a mapping for the |
* $nativecode submitted. |
*/ |
function errorCode($nativecode) |
{ |
if (isset($this->errorcode_map[$nativecode])) { |
return $this->errorcode_map[$nativecode]; |
} |
// Fall back to DB_ERROR if there was no mapping. |
return DB_ERROR; |
} |
// }}} |
// {{{ errorMessage() |
/** |
* Maps a DB error code to a textual message |
* |
* @param integer $dbcode the DB error code |
* |
* @return string the error message corresponding to the error code |
* submitted. FALSE if the error code is unknown. |
* |
* @see DB::errorMessage() |
*/ |
function errorMessage($dbcode) |
{ |
return DB::errorMessage($this->errorcode_map[$dbcode]); |
} |
// }}} |
// {{{ 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>DB_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>DB_TABLEINFO_ORDERTABLE</kbd> |
* |
* <p>Similar to <kbd>DB_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>DB_PORTABILITY_LOWERCASE</samp> |
* turned on, the names of tables and fields will be lowercased. |
* |
* @param object|string $result DB_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>DB_TABLEINFO_ORDERTABLE</kbd>, |
* <kbd>DB_TABLEINFO_ORDER</kbd> or |
* <kbd>DB_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 DB_Error object on failure. |
* |
* @see DB_common::setOption() |
*/ |
function tableInfo($result, $mode = null) |
{ |
/* |
* If the DB_<driver> class has a tableInfo() method, that one |
* overrides this one. But, if the driver doesn't have one, |
* this method runs and tells users about that fact. |
*/ |
return $this->raiseError(DB_ERROR_NOT_CAPABLE); |
} |
// }}} |
// {{{ getTables() |
/** |
* Lists the tables in the current database |
* |
* @return array the list of tables. A DB_Error object on failure. |
* |
* @deprecated Method deprecated some time before Release 1.2 |
*/ |
function getTables() |
{ |
return $this->getListOf('tables'); |
} |
// }}} |
// {{{ getListOf() |
/** |
* Lists internal database information |
* |
* @param string $type type of information being sought. |
* Common items being sought are: |
* tables, databases, users, views, functions |
* Each DBMS's has its own capabilities. |
* |
* @return array an array listing the items sought. |
* A DB DB_Error object on failure. |
*/ |
function getListOf($type) |
{ |
$sql = $this->getSpecialQuery($type); |
if ($sql === null) { |
$this->last_query = ''; |
return $this->raiseError(DB_ERROR_UNSUPPORTED); |
} elseif (is_int($sql) || DB::isError($sql)) { |
// Previous error |
return $this->raiseError($sql); |
} elseif (is_array($sql)) { |
// Already the result |
return $sql; |
} |
// Launch this query |
return $this->getCol($sql); |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
return $this->raiseError(DB_ERROR_UNSUPPORTED); |
} |
// }}} |
// {{{ nextQueryIsManip() |
/** |
* Sets (or unsets) a flag indicating that the next query will be a |
* manipulation query, regardless of the usual DB::isManip() heuristics. |
* |
* @param boolean true to set the flag overriding the isManip() behaviour, |
* false to clear it and fall back onto isManip() |
* |
* @return void |
* |
* @access public |
*/ |
function nextQueryIsManip($manip) |
{ |
$this->_next_query_manip = $manip; |
} |
// }}} |
// {{{ _checkManip() |
/** |
* Checks if the given query is a manipulation query. This also takes into |
* account the _next_query_manip flag and sets the _last_query_manip flag |
* (and resets _next_query_manip) according to the result. |
* |
* @param string The query to check. |
* |
* @return boolean true if the query is a manipulation query, false |
* otherwise |
* |
* @access protected |
*/ |
function _checkManip($query) |
{ |
if ($this->_next_query_manip || DB::isManip($query)) { |
$this->_last_query_manip = true; |
} else { |
$this->_last_query_manip = false; |
} |
$this->_next_query_manip = false; |
return $this->_last_query_manip; |
$manip = $this->_next_query_manip; |
} |
// }}} |
// {{{ _rtrimArrayValues() |
/** |
* Right-trims all strings in an array |
* |
* @param array $array the array to be trimmed (passed by reference) |
* |
* @return void |
* |
* @access protected |
*/ |
function _rtrimArrayValues(&$array) |
{ |
foreach ($array as $key => $value) { |
if (is_string($value)) { |
$array[$key] = rtrim($value); |
} |
} |
} |
// }}} |
// {{{ _convertNullArrayValuesToEmpty() |
/** |
* Converts all null values in an array to empty strings |
* |
* @param array $array the array to be de-nullified (passed by reference) |
* |
* @return void |
* |
* @access protected |
*/ |
function _convertNullArrayValuesToEmpty(&$array) |
{ |
foreach ($array as $key => $value) { |
if (is_null($value)) { |
$array[$key] = ''; |
} |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/msql.php |
---|
Новый файл |
0,0 → 1,831 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's msql extension |
* for interacting with Mini SQL databases |
* |
* PHP's mSQL extension did weird things with NULL values prior to PHP |
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds |
* those versions. |
* |
* 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 Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: msql.php,v 1.64 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's msql extension |
* for interacting with Mini SQL databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* PHP's mSQL extension did weird things with NULL values prior to PHP |
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds |
* those versions. |
* |
* @category Database |
* @package DB |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
* @since Class not functional until Release 1.7.0 |
*/ |
class DB_msql extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'msql'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'msql'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'emulate', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => true, |
'prepare' => false, |
'ssl' => false, |
'transactions' => false, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* The query result resource created by PHP |
* |
* Used to make affectedRows() work. Only contains the result for |
* data manipulation queries. Contains false for other queries. |
* |
* @var resource |
* @access private |
*/ |
var $_result; |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_msql() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* Example of how to connect: |
* <code> |
* require_once 'DB.php'; |
* |
* // $dsn = 'msql://hostname/dbname'; // use a TCP connection |
* $dsn = 'msql:///dbname'; // use a socket |
* $options = array( |
* 'portability' => DB_PORTABILITY_ALL, |
* ); |
* |
* $db = DB::connect($dsn, $options); |
* if (PEAR::isError($db)) { |
* die($db->getMessage()); |
* } |
* </code> |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('msql')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$params = array(); |
if ($dsn['hostspec']) { |
$params[] = $dsn['port'] |
? $dsn['hostspec'] . ',' . $dsn['port'] |
: $dsn['hostspec']; |
} |
$connect_function = $persistent ? 'msql_pconnect' : 'msql_connect'; |
$ini = ini_get('track_errors'); |
$php_errormsg = ''; |
if ($ini) { |
$this->connection = @call_user_func_array($connect_function, |
$params); |
} else { |
@ini_set('track_errors', 1); |
$this->connection = @call_user_func_array($connect_function, |
$params); |
@ini_set('track_errors', $ini); |
} |
if (!$this->connection) { |
if (($err = @msql_error()) != '') { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$err); |
} else { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
} |
if (!@msql_select_db($dsn['database'], $this->connection)) { |
return $this->msqlRaiseError(); |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @msql_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
$result = @msql_query($query, $this->connection); |
if (!$result) { |
return $this->msqlRaiseError(); |
} |
// Determine which queries that should return data, and which |
// should return an error code only. |
if ($this->_checkManip($query)) { |
$this->_result = $result; |
return DB_OK; |
} else { |
$this->_result = false; |
return $result; |
} |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal msql result pointer to the next available result |
* |
* @param a valid fbsql result resource |
* |
* @access public |
* |
* @return true if a result is available otherwise return false |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* PHP's mSQL extension did weird things with NULL values prior to PHP |
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds |
* those versions. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@msql_data_seek($result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @msql_fetch_array($result, MSQL_ASSOC); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @msql_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? msql_free_result($result) : false; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @msql_num_fields($result); |
if (!$cols) { |
return $this->msqlRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @msql_num_rows($result); |
if ($rows === false) { |
return $this->msqlRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ affected() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if (!$this->_result) { |
return 0; |
} |
return msql_affected_rows($this->_result); |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_msql::createSequence(), DB_msql::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$repeat = false; |
do { |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query("SELECT _seq FROM ${seqname}"); |
$this->popErrorHandling(); |
if ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) { |
$repeat = true; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->createSequence($seq_name); |
$this->popErrorHandling(); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
} else { |
$repeat = false; |
} |
} while ($repeat); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED); |
$result->free(); |
return $arr[0]; |
} |
// }}} |
// {{{ createSequence() |
/** |
* Creates a new sequence |
* |
* Also creates a new table to associate the sequence with. Uses |
* a separate table to ensure portability with other drivers. |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_msql::nextID(), DB_msql::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$res = $this->query('CREATE TABLE ' . $seqname |
. ' (id INTEGER NOT NULL)'); |
if (DB::isError($res)) { |
return $res; |
} |
$res = $this->query("CREATE SEQUENCE ON ${seqname}"); |
return $res; |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_msql::nextID(), DB_msql::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ quoteIdentifier() |
/** |
* mSQL does not support delimited identifiers |
* |
* @param string $str the identifier name to be quoted |
* |
* @return object a DB_Error object |
* |
* @see DB_common::quoteIdentifier() |
* @since Method available since Release 1.7.0 |
*/ |
function quoteIdentifier($str) |
{ |
return $this->raiseError(DB_ERROR_UNSUPPORTED); |
} |
// }}} |
// {{{ quoteFloat() |
/** |
* Formats a float value for use within a query in a locale-independent |
* manner. |
* |
* @param float the float value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteFloat($float) { |
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); |
} |
// }}} |
// {{{ escapeSimple() |
/** |
* Escapes a string according to the current DBMS's standards |
* |
* @param string $str the string to be escaped |
* |
* @return string the escaped string |
* |
* @see DB_common::quoteSmart() |
* @since Method available since Release 1.7.0 |
*/ |
function escapeSimple($str) |
{ |
return addslashes($str); |
} |
// }}} |
// {{{ msqlRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_msql::errorNative(), DB_msql::errorCode() |
*/ |
function msqlRaiseError($errno = null) |
{ |
$native = $this->errorNative(); |
if ($errno === null) { |
$errno = $this->errorCode($native); |
} |
return $this->raiseError($errno, null, null, null, $native); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error message produced by the last query |
* |
* @return string the DBMS' error message |
*/ |
function errorNative() |
{ |
return @msql_error(); |
} |
// }}} |
// {{{ errorCode() |
/** |
* Determines PEAR::DB error code from the database's text error message |
* |
* @param string $errormsg the error message returned from the database |
* |
* @return integer the error number from a DB_ERROR* constant |
*/ |
function errorCode($errormsg) |
{ |
static $error_regexps; |
// PHP 5.2+ prepends the function name to $php_errormsg, so we need |
// this hack to work around it, per bug #9599. |
$errormsg = preg_replace('/^msql[a-z_]+\(\): /', '', $errormsg); |
if (!isset($error_regexps)) { |
$error_regexps = array( |
'/^Access to database denied/i' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/^Bad index name/i' |
=> DB_ERROR_ALREADY_EXISTS, |
'/^Bad order field/i' |
=> DB_ERROR_SYNTAX, |
'/^Bad type for comparison/i' |
=> DB_ERROR_SYNTAX, |
'/^Can\'t perform LIKE on/i' |
=> DB_ERROR_SYNTAX, |
'/^Can\'t use TEXT fields in LIKE comparison/i' |
=> DB_ERROR_SYNTAX, |
'/^Couldn\'t create temporary table/i' |
=> DB_ERROR_CANNOT_CREATE, |
'/^Error creating table file/i' |
=> DB_ERROR_CANNOT_CREATE, |
'/^Field .* cannot be null$/i' |
=> DB_ERROR_CONSTRAINT_NOT_NULL, |
'/^Index (field|condition) .* cannot be null$/i' |
=> DB_ERROR_SYNTAX, |
'/^Invalid date format/i' |
=> DB_ERROR_INVALID_DATE, |
'/^Invalid time format/i' |
=> DB_ERROR_INVALID, |
'/^Literal value for .* is wrong type$/i' |
=> DB_ERROR_INVALID_NUMBER, |
'/^No Database Selected/i' |
=> DB_ERROR_NODBSELECTED, |
'/^No value specified for field/i' |
=> DB_ERROR_VALUE_COUNT_ON_ROW, |
'/^Non unique value for unique index/i' |
=> DB_ERROR_CONSTRAINT, |
'/^Out of memory for temporary table/i' |
=> DB_ERROR_CANNOT_CREATE, |
'/^Permission denied/i' |
=> DB_ERROR_ACCESS_VIOLATION, |
'/^Reference to un-selected table/i' |
=> DB_ERROR_SYNTAX, |
'/^syntax error/i' |
=> DB_ERROR_SYNTAX, |
'/^Table .* exists$/i' |
=> DB_ERROR_ALREADY_EXISTS, |
'/^Unknown database/i' |
=> DB_ERROR_NOSUCHDB, |
'/^Unknown field/i' |
=> DB_ERROR_NOSUCHFIELD, |
'/^Unknown (index|system variable)/i' |
=> DB_ERROR_NOT_FOUND, |
'/^Unknown table/i' |
=> DB_ERROR_NOSUCHTABLE, |
'/^Unqualified field/i' |
=> DB_ERROR_SYNTAX, |
); |
} |
foreach ($error_regexps as $regexp => $code) { |
if (preg_match($regexp, $errormsg)) { |
return $code; |
} |
} |
return DB_ERROR; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::setOption() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @msql_query("SELECT * FROM $result", |
$this->connection); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_resource($id)) { |
return $this->raiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @msql_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$tmp = @msql_fetch_field($id); |
$flags = ''; |
if ($tmp->not_null) { |
$flags .= 'not_null '; |
} |
if ($tmp->unique) { |
$flags .= 'unique_key '; |
} |
$flags = trim($flags); |
$res[$i] = array( |
'table' => $case_func($tmp->table), |
'name' => $case_func($tmp->name), |
'type' => $tmp->type, |
'len' => msql_field_len($id, $i), |
'flags' => $flags, |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@msql_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtain a list of a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return array the array containing the list of objects requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'databases': |
$id = @msql_list_dbs($this->connection); |
break; |
case 'tables': |
$id = @msql_list_tables($this->dsn['database'], |
$this->connection); |
break; |
default: |
return null; |
} |
if (!$id) { |
return $this->msqlRaiseError(); |
} |
$out = array(); |
while ($row = @msql_fetch_row($id)) { |
$out[] = $row[0]; |
} |
return $out; |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/dbase.php |
---|
Новый файл |
0,0 → 1,510 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's dbase extension |
* for interacting with dBase databases |
* |
* 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 Tomas V.V. Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: dbase.php,v 1.45 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's dbase extension |
* for interacting with dBase databases |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Tomas V.V. Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_dbase extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'dbase'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'dbase'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => false, |
'new_link' => false, |
'numrows' => true, |
'pconnect' => false, |
'prepare' => false, |
'ssl' => false, |
'transactions' => false, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* A means of emulating result resources |
* @var array |
*/ |
var $res_row = array(); |
/** |
* The quantity of results so far |
* |
* For emulating result resources. |
* |
* @var integer |
*/ |
var $result = 0; |
/** |
* Maps dbase data type id's to human readable strings |
* |
* The human readable values are based on the output of PHP's |
* dbase_get_header_info() function. |
* |
* @var array |
* @since Property available since Release 1.7.0 |
*/ |
var $types = array( |
'C' => 'character', |
'D' => 'date', |
'L' => 'boolean', |
'M' => 'memo', |
'N' => 'number', |
); |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_dbase() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database and create it if it doesn't exist |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's dbase driver supports the following extra DSN options: |
* + mode An integer specifying the read/write mode to use |
* (0 = read only, 1 = write only, 2 = read/write). |
* Available since PEAR DB 1.7.0. |
* + fields An array of arrays that PHP's dbase_create() function needs |
* to create a new database. This information is used if the |
* dBase file specified in the "database" segment of the DSN |
* does not exist. For more info, see the PHP manual's |
* {@link http://php.net/dbase_create dbase_create()} page. |
* Available since PEAR DB 1.7.0. |
* |
* Example of how to connect and establish a new dBase file if necessary: |
* <code> |
* require_once 'DB.php'; |
* |
* $dsn = array( |
* 'phptype' => 'dbase', |
* 'database' => '/path/and/name/of/dbase/file', |
* 'mode' => 2, |
* 'fields' => array( |
* array('a', 'N', 5, 0), |
* array('b', 'C', 40), |
* array('c', 'C', 255), |
* array('d', 'C', 20), |
* ), |
* ); |
* $options = array( |
* 'debug' => 2, |
* 'portability' => DB_PORTABILITY_ALL, |
* ); |
* |
* $db = DB::connect($dsn, $options); |
* if (PEAR::isError($db)) { |
* die($db->getMessage()); |
* } |
* </code> |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('dbase')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
/* |
* Turn track_errors on for entire script since $php_errormsg |
* is the only way to find errors from the dbase extension. |
*/ |
@ini_set('track_errors', 1); |
$php_errormsg = ''; |
if (!file_exists($dsn['database'])) { |
$this->dsn['mode'] = 2; |
if (empty($dsn['fields']) || !is_array($dsn['fields'])) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
'the dbase file does not exist and ' |
. 'it could not be created because ' |
. 'the "fields" element of the DSN ' |
. 'is not properly set'); |
} |
$this->connection = @dbase_create($dsn['database'], |
$dsn['fields']); |
if (!$this->connection) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
'the dbase file does not exist and ' |
. 'the attempt to create it failed: ' |
. $php_errormsg); |
} |
} else { |
if (!isset($this->dsn['mode'])) { |
$this->dsn['mode'] = 0; |
} |
$this->connection = @dbase_open($dsn['database'], |
$this->dsn['mode']); |
if (!$this->connection) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @dbase_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ &query() |
function &query($query = null) |
{ |
// emulate result resources |
$this->res_row[(int)$this->result] = 0; |
$tmp = new DB_result($this, $this->result++); |
return $tmp; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum === null) { |
$rownum = $this->res_row[(int)$result]++; |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @dbase_get_record_with_names($this->connection, $rownum); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @dbase_get_record($this->connection, $rownum); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set. |
* |
* This method is a no-op for dbase, as there aren't result resources in |
* the same sense as most other database backends. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return true; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($foo) |
{ |
return @dbase_numfields($this->connection); |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($foo) |
{ |
return @dbase_numrecords($this->connection); |
} |
// }}} |
// {{{ quoteBoolean() |
/** |
* Formats a boolean value for use within a query in a locale-independent |
* manner. |
* |
* @param boolean the boolean value to be quoted. |
* @return string the quoted string. |
* @see DB_common::quoteSmart() |
* @since Method available since release 1.7.8. |
*/ |
function quoteBoolean($boolean) { |
return $boolean ? 'T' : 'F'; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about the current database |
* |
* @param mixed $result THIS IS UNUSED IN DBASE. The current database |
* is examined regardless of what is provided here. |
* @param int $mode a valid tableInfo mode |
* |
* @return array an associative array with the information requested. |
* A DB_Error object on failure. |
* |
* @see DB_common::tableInfo() |
* @since Method available since Release 1.7.0 |
*/ |
function tableInfo($result = null, $mode = null) |
{ |
if (function_exists('dbase_get_header_info')) { |
$id = @dbase_get_header_info($this->connection); |
if (!$id && $php_errormsg) { |
return $this->raiseError(DB_ERROR, |
null, null, null, |
$php_errormsg); |
} |
} else { |
/* |
* This segment for PHP 4 is loosely based on code by |
* Hadi Rusiah <deegos@yahoo.com> in the comments on |
* the dBase reference page in the PHP manual. |
*/ |
$db = @fopen($this->dsn['database'], 'r'); |
if (!$db) { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
$id = array(); |
$i = 0; |
$line = fread($db, 32); |
while (!feof($db)) { |
$line = fread($db, 32); |
if (substr($line, 0, 1) == chr(13)) { |
break; |
} else { |
$pos = strpos(substr($line, 0, 10), chr(0)); |
$pos = ($pos == 0 ? 10 : $pos); |
$id[$i] = array( |
'name' => substr($line, 0, $pos), |
'type' => $this->types[substr($line, 11, 1)], |
'length' => ord(substr($line, 16, 1)), |
'precision' => ord(substr($line, 17, 1)), |
); |
} |
$i++; |
} |
fclose($db); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$res = array(); |
$count = count($id); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$res[$i] = array( |
'table' => $this->dsn['database'], |
'name' => $case_func($id[$i]['name']), |
'type' => $id[$i]['type'], |
'len' => $id[$i]['length'], |
'flags' => '' |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
return $res; |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/DB/mysqli.php |
---|
Новый файл |
0,0 → 1,1092 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* The PEAR DB driver for PHP's mysqli extension |
* for interacting with MySQL databases |
* |
* 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 Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: mysqli.php,v 1.82 2007/09/21 13:40:41 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the DB_common class so it can be extended from |
*/ |
require_once 'DB/common.php'; |
/** |
* The methods PEAR DB uses to interact with PHP's mysqli extension |
* for interacting with MySQL databases |
* |
* This is for MySQL versions 4.1 and above. Requires PHP 5. |
* |
* Note that persistent connections no longer exist. |
* |
* These methods overload the ones declared in DB_common. |
* |
* @category Database |
* @package DB |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
* @since Class functional since Release 1.6.3 |
*/ |
class DB_mysqli extends DB_common |
{ |
// {{{ properties |
/** |
* The DB driver type (mysql, oci8, odbc, etc.) |
* @var string |
*/ |
var $phptype = 'mysqli'; |
/** |
* The database syntax variant to be used (db2, access, etc.), if any |
* @var string |
*/ |
var $dbsyntax = 'mysqli'; |
/** |
* The capabilities of this DB implementation |
* |
* The 'new_link' element contains the PHP version that first provided |
* new_link support for this DBMS. Contains false if it's unsupported. |
* |
* Meaning of the 'limit' element: |
* + 'emulate' = emulate with fetch row by number |
* + 'alter' = alter the query |
* + false = skip rows |
* |
* @var array |
*/ |
var $features = array( |
'limit' => 'alter', |
'new_link' => false, |
'numrows' => true, |
'pconnect' => false, |
'prepare' => false, |
'ssl' => true, |
'transactions' => true, |
); |
/** |
* A mapping of native error codes to DB error codes |
* @var array |
*/ |
var $errorcode_map = array( |
1004 => DB_ERROR_CANNOT_CREATE, |
1005 => DB_ERROR_CANNOT_CREATE, |
1006 => DB_ERROR_CANNOT_CREATE, |
1007 => DB_ERROR_ALREADY_EXISTS, |
1008 => DB_ERROR_CANNOT_DROP, |
1022 => DB_ERROR_ALREADY_EXISTS, |
1044 => DB_ERROR_ACCESS_VIOLATION, |
1046 => DB_ERROR_NODBSELECTED, |
1048 => DB_ERROR_CONSTRAINT, |
1049 => DB_ERROR_NOSUCHDB, |
1050 => DB_ERROR_ALREADY_EXISTS, |
1051 => DB_ERROR_NOSUCHTABLE, |
1054 => DB_ERROR_NOSUCHFIELD, |
1061 => DB_ERROR_ALREADY_EXISTS, |
1062 => DB_ERROR_ALREADY_EXISTS, |
1064 => DB_ERROR_SYNTAX, |
1091 => DB_ERROR_NOT_FOUND, |
1100 => DB_ERROR_NOT_LOCKED, |
1136 => DB_ERROR_VALUE_COUNT_ON_ROW, |
1142 => DB_ERROR_ACCESS_VIOLATION, |
1146 => DB_ERROR_NOSUCHTABLE, |
1216 => DB_ERROR_CONSTRAINT, |
1217 => DB_ERROR_CONSTRAINT, |
1356 => DB_ERROR_DIVZERO, |
1451 => DB_ERROR_CONSTRAINT, |
1452 => DB_ERROR_CONSTRAINT, |
); |
/** |
* The raw database connection created by PHP |
* @var resource |
*/ |
var $connection; |
/** |
* The DSN information for connecting to a database |
* @var array |
*/ |
var $dsn = array(); |
/** |
* Should data manipulation queries be committed automatically? |
* @var bool |
* @access private |
*/ |
var $autocommit = true; |
/** |
* The quantity of transactions begun |
* |
* {@internal While this is private, it can't actually be designated |
* private in PHP 5 because it is directly accessed in the test suite.}} |
* |
* @var integer |
* @access private |
*/ |
var $transaction_opcount = 0; |
/** |
* The database specified in the DSN |
* |
* It's a fix to allow calls to different databases in the same script. |
* |
* @var string |
* @access private |
*/ |
var $_db = ''; |
/** |
* Array for converting MYSQLI_*_FLAG constants to text values |
* @var array |
* @access public |
* @since Property available since Release 1.6.5 |
*/ |
var $mysqli_flags = array( |
MYSQLI_NOT_NULL_FLAG => 'not_null', |
MYSQLI_PRI_KEY_FLAG => 'primary_key', |
MYSQLI_UNIQUE_KEY_FLAG => 'unique_key', |
MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key', |
MYSQLI_BLOB_FLAG => 'blob', |
MYSQLI_UNSIGNED_FLAG => 'unsigned', |
MYSQLI_ZEROFILL_FLAG => 'zerofill', |
MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment', |
MYSQLI_TIMESTAMP_FLAG => 'timestamp', |
MYSQLI_SET_FLAG => 'set', |
// MYSQLI_NUM_FLAG => 'numeric', // unnecessary |
// MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie |
MYSQLI_GROUP_FLAG => 'group_by' |
); |
/** |
* Array for converting MYSQLI_TYPE_* constants to text values |
* @var array |
* @access public |
* @since Property available since Release 1.6.5 |
*/ |
var $mysqli_types = array( |
MYSQLI_TYPE_DECIMAL => 'decimal', |
MYSQLI_TYPE_TINY => 'tinyint', |
MYSQLI_TYPE_SHORT => 'int', |
MYSQLI_TYPE_LONG => 'int', |
MYSQLI_TYPE_FLOAT => 'float', |
MYSQLI_TYPE_DOUBLE => 'double', |
// MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it |
MYSQLI_TYPE_TIMESTAMP => 'timestamp', |
MYSQLI_TYPE_LONGLONG => 'bigint', |
MYSQLI_TYPE_INT24 => 'mediumint', |
MYSQLI_TYPE_DATE => 'date', |
MYSQLI_TYPE_TIME => 'time', |
MYSQLI_TYPE_DATETIME => 'datetime', |
MYSQLI_TYPE_YEAR => 'year', |
MYSQLI_TYPE_NEWDATE => 'date', |
MYSQLI_TYPE_ENUM => 'enum', |
MYSQLI_TYPE_SET => 'set', |
MYSQLI_TYPE_TINY_BLOB => 'tinyblob', |
MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob', |
MYSQLI_TYPE_LONG_BLOB => 'longblob', |
MYSQLI_TYPE_BLOB => 'blob', |
MYSQLI_TYPE_VAR_STRING => 'varchar', |
MYSQLI_TYPE_STRING => 'char', |
MYSQLI_TYPE_GEOMETRY => 'geometry', |
/* These constants are conditionally compiled in ext/mysqli, so we'll |
* define them by number rather than constant. */ |
16 => 'bit', |
246 => 'decimal', |
); |
// }}} |
// {{{ constructor |
/** |
* This constructor calls <kbd>$this->DB_common()</kbd> |
* |
* @return void |
*/ |
function DB_mysqli() |
{ |
$this->DB_common(); |
} |
// }}} |
// {{{ connect() |
/** |
* Connect to the database server, log in and open the database |
* |
* Don't call this method directly. Use DB::connect() instead. |
* |
* PEAR DB's mysqli driver supports the following extra DSN options: |
* + When the 'ssl' $option passed to DB::connect() is true: |
* + key The path to the key file. |
* + cert The path to the certificate file. |
* + ca The path to the certificate authority file. |
* + capath The path to a directory that contains trusted SSL |
* CA certificates in pem format. |
* + cipher The list of allowable ciphers for SSL encryption. |
* |
* Example of how to connect using SSL: |
* <code> |
* require_once 'DB.php'; |
* |
* $dsn = array( |
* 'phptype' => 'mysqli', |
* 'username' => 'someuser', |
* 'password' => 'apasswd', |
* 'hostspec' => 'localhost', |
* 'database' => 'thedb', |
* 'key' => 'client-key.pem', |
* 'cert' => 'client-cert.pem', |
* 'ca' => 'cacert.pem', |
* 'capath' => '/path/to/ca/dir', |
* 'cipher' => 'AES', |
* ); |
* |
* $options = array( |
* 'ssl' => true, |
* ); |
* |
* $db = DB::connect($dsn, $options); |
* if (PEAR::isError($db)) { |
* die($db->getMessage()); |
* } |
* </code> |
* |
* @param array $dsn the data source name |
* @param bool $persistent should the connection be persistent? |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function connect($dsn, $persistent = false) |
{ |
if (!PEAR::loadExtension('mysqli')) { |
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND); |
} |
$this->dsn = $dsn; |
if ($dsn['dbsyntax']) { |
$this->dbsyntax = $dsn['dbsyntax']; |
} |
$ini = ini_get('track_errors'); |
@ini_set('track_errors', 1); |
$php_errormsg = ''; |
if (((int) $this->getOption('ssl')) === 1) { |
$init = mysqli_init(); |
mysqli_ssl_set( |
$init, |
empty($dsn['key']) ? null : $dsn['key'], |
empty($dsn['cert']) ? null : $dsn['cert'], |
empty($dsn['ca']) ? null : $dsn['ca'], |
empty($dsn['capath']) ? null : $dsn['capath'], |
empty($dsn['cipher']) ? null : $dsn['cipher'] |
); |
if ($this->connection = @mysqli_real_connect( |
$init, |
$dsn['hostspec'], |
$dsn['username'], |
$dsn['password'], |
$dsn['database'], |
$dsn['port'], |
$dsn['socket'])) |
{ |
$this->connection = $init; |
} |
} else { |
$this->connection = @mysqli_connect( |
$dsn['hostspec'], |
$dsn['username'], |
$dsn['password'], |
$dsn['database'], |
$dsn['port'], |
$dsn['socket'] |
); |
} |
@ini_set('track_errors', $ini); |
if (!$this->connection) { |
if (($err = @mysqli_connect_error()) != '') { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$err); |
} else { |
return $this->raiseError(DB_ERROR_CONNECT_FAILED, |
null, null, null, |
$php_errormsg); |
} |
} |
if ($dsn['database']) { |
$this->_db = $dsn['database']; |
} |
return DB_OK; |
} |
// }}} |
// {{{ disconnect() |
/** |
* Disconnects from the database server |
* |
* @return bool TRUE on success, FALSE on failure |
*/ |
function disconnect() |
{ |
$ret = @mysqli_close($this->connection); |
$this->connection = null; |
return $ret; |
} |
// }}} |
// {{{ simpleQuery() |
/** |
* Sends a query to the database server |
* |
* @param string the SQL query string |
* |
* @return mixed + a PHP result resrouce for successful SELECT queries |
* + the DB_OK constant for other successful queries |
* + a DB_Error object on failure |
*/ |
function simpleQuery($query) |
{ |
$ismanip = $this->_checkManip($query); |
$this->last_query = $query; |
$query = $this->modifyQuery($query); |
if ($this->_db) { |
if (!@mysqli_select_db($this->connection, $this->_db)) { |
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
if (!$this->autocommit && $ismanip) { |
if ($this->transaction_opcount == 0) { |
$result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=0'); |
$result = @mysqli_query($this->connection, 'BEGIN'); |
if (!$result) { |
return $this->mysqliRaiseError(); |
} |
} |
$this->transaction_opcount++; |
} |
$result = @mysqli_query($this->connection, $query); |
if (!$result) { |
return $this->mysqliRaiseError(); |
} |
if (is_object($result)) { |
return $result; |
} |
return DB_OK; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Move the internal mysql result pointer to the next available result. |
* |
* This method has not been implemented yet. |
* |
* @param resource $result a valid sql result resource |
* @return false |
* @access public |
*/ |
function nextResult($result) |
{ |
return false; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Places a row from the result set into the given array |
* |
* Formating of the array and the data therein are configurable. |
* See DB_result::fetchInto() for more information. |
* |
* This method is not meant to be called directly. Use |
* DB_result::fetchInto() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result the query result resource |
* @param array $arr the referenced array to put the data in |
* @param int $fetchmode how the resulting array should be indexed |
* @param int $rownum the row number to fetch (0 = first row) |
* |
* @return mixed DB_OK on success, NULL when the end of a result set is |
* reached or on failure |
* |
* @see DB_result::fetchInto() |
*/ |
function fetchInto($result, &$arr, $fetchmode, $rownum = null) |
{ |
if ($rownum !== null) { |
if (!@mysqli_data_seek($result, $rownum)) { |
return null; |
} |
} |
if ($fetchmode & DB_FETCHMODE_ASSOC) { |
$arr = @mysqli_fetch_array($result, MYSQLI_ASSOC); |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { |
$arr = array_change_key_case($arr, CASE_LOWER); |
} |
} else { |
$arr = @mysqli_fetch_row($result); |
} |
if (!$arr) { |
return null; |
} |
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) { |
/* |
* Even though this DBMS already trims output, we do this because |
* a field might have intentional whitespace at the end that |
* gets removed by DB_PORTABILITY_RTRIM under another driver. |
*/ |
$this->_rtrimArrayValues($arr); |
} |
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) { |
$this->_convertNullArrayValuesToEmpty($arr); |
} |
return DB_OK; |
} |
// }}} |
// {{{ freeResult() |
/** |
* Deletes the result set and frees the memory occupied by the result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::free() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return bool TRUE on success, FALSE if $result is invalid |
* |
* @see DB_result::free() |
*/ |
function freeResult($result) |
{ |
return is_resource($result) ? mysqli_free_result($result) : false; |
} |
// }}} |
// {{{ numCols() |
/** |
* Gets the number of columns in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numCols() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of columns. A DB_Error object on failure. |
* |
* @see DB_result::numCols() |
*/ |
function numCols($result) |
{ |
$cols = @mysqli_num_fields($result); |
if (!$cols) { |
return $this->mysqliRaiseError(); |
} |
return $cols; |
} |
// }}} |
// {{{ numRows() |
/** |
* Gets the number of rows in a result set |
* |
* This method is not meant to be called directly. Use |
* DB_result::numRows() instead. It can't be declared "protected" |
* because DB_result is a separate object. |
* |
* @param resource $result PHP's query result resource |
* |
* @return int the number of rows. A DB_Error object on failure. |
* |
* @see DB_result::numRows() |
*/ |
function numRows($result) |
{ |
$rows = @mysqli_num_rows($result); |
if ($rows === null) { |
return $this->mysqliRaiseError(); |
} |
return $rows; |
} |
// }}} |
// {{{ autoCommit() |
/** |
* Enables or disables automatic commits |
* |
* @param bool $onoff true turns it on, false turns it off |
* |
* @return int DB_OK on success. A DB_Error object if the driver |
* doesn't support auto-committing transactions. |
*/ |
function autoCommit($onoff = false) |
{ |
// XXX if $this->transaction_opcount > 0, we should probably |
// issue a warning here. |
$this->autocommit = $onoff ? true : false; |
return DB_OK; |
} |
// }}} |
// {{{ commit() |
/** |
* Commits the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function commit() |
{ |
if ($this->transaction_opcount > 0) { |
if ($this->_db) { |
if (!@mysqli_select_db($this->connection, $this->_db)) { |
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
$result = @mysqli_query($this->connection, 'COMMIT'); |
$result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1'); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->mysqliRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ rollback() |
/** |
* Reverts the current transaction |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
*/ |
function rollback() |
{ |
if ($this->transaction_opcount > 0) { |
if ($this->_db) { |
if (!@mysqli_select_db($this->connection, $this->_db)) { |
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
$result = @mysqli_query($this->connection, 'ROLLBACK'); |
$result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1'); |
$this->transaction_opcount = 0; |
if (!$result) { |
return $this->mysqliRaiseError(); |
} |
} |
return DB_OK; |
} |
// }}} |
// {{{ affectedRows() |
/** |
* Determines the number of rows affected by a data maniuplation query |
* |
* 0 is returned for queries that don't manipulate data. |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function affectedRows() |
{ |
if ($this->_last_query_manip) { |
return @mysqli_affected_rows($this->connection); |
} else { |
return 0; |
} |
} |
// }}} |
// {{{ nextId() |
/** |
* Returns the next free id in a sequence |
* |
* @param string $seq_name name of the sequence |
* @param boolean $ondemand when true, the seqence is automatically |
* created if it does not exist |
* |
* @return int the next id number in the sequence. |
* A DB_Error object on failure. |
* |
* @see DB_common::nextID(), DB_common::getSequenceName(), |
* DB_mysqli::createSequence(), DB_mysqli::dropSequence() |
*/ |
function nextId($seq_name, $ondemand = true) |
{ |
$seqname = $this->getSequenceName($seq_name); |
do { |
$repeat = 0; |
$this->pushErrorHandling(PEAR_ERROR_RETURN); |
$result = $this->query('UPDATE ' . $seqname |
. ' SET id = LAST_INSERT_ID(id + 1)'); |
$this->popErrorHandling(); |
if ($result === DB_OK) { |
// COMMON CASE |
$id = @mysqli_insert_id($this->connection); |
if ($id != 0) { |
return $id; |
} |
// EMPTY SEQ TABLE |
// Sequence table must be empty for some reason, |
// so fill it and return 1 |
// Obtain a user-level lock |
$result = $this->getOne('SELECT GET_LOCK(' |
. "'${seqname}_lock', 10)"); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
if ($result == 0) { |
return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED); |
} |
// add the default value |
$result = $this->query('REPLACE INTO ' . $seqname |
. ' (id) VALUES (0)'); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
// Release the lock |
$result = $this->getOne('SELECT RELEASE_LOCK(' |
. "'${seqname}_lock')"); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
// We know what the result will be, so no need to try again |
return 1; |
} elseif ($ondemand && DB::isError($result) && |
$result->getCode() == DB_ERROR_NOSUCHTABLE) |
{ |
// ONDEMAND TABLE CREATION |
$result = $this->createSequence($seq_name); |
// Since createSequence initializes the ID to be 1, |
// we do not need to retrieve the ID again (or we will get 2) |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} else { |
// First ID of a newly created sequence is 1 |
return 1; |
} |
} elseif (DB::isError($result) && |
$result->getCode() == DB_ERROR_ALREADY_EXISTS) |
{ |
// BACKWARDS COMPAT |
// see _BCsequence() comment |
$result = $this->_BCsequence($seqname); |
if (DB::isError($result)) { |
return $this->raiseError($result); |
} |
$repeat = 1; |
} |
} while ($repeat); |
return $this->raiseError($result); |
} |
/** |
* Creates a new sequence |
* |
* @param string $seq_name name of the new sequence |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::createSequence(), DB_common::getSequenceName(), |
* DB_mysqli::nextID(), DB_mysqli::dropSequence() |
*/ |
function createSequence($seq_name) |
{ |
$seqname = $this->getSequenceName($seq_name); |
$res = $this->query('CREATE TABLE ' . $seqname |
. ' (id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,' |
. ' PRIMARY KEY(id))'); |
if (DB::isError($res)) { |
return $res; |
} |
// insert yields value 1, nextId call will generate ID 2 |
return $this->query("INSERT INTO ${seqname} (id) VALUES (0)"); |
} |
// }}} |
// {{{ dropSequence() |
/** |
* Deletes a sequence |
* |
* @param string $seq_name name of the sequence to be deleted |
* |
* @return int DB_OK on success. A DB_Error object on failure. |
* |
* @see DB_common::dropSequence(), DB_common::getSequenceName(), |
* DB_mysql::nextID(), DB_mysql::createSequence() |
*/ |
function dropSequence($seq_name) |
{ |
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
} |
// }}} |
// {{{ _BCsequence() |
/** |
* Backwards compatibility with old sequence emulation implementation |
* (clean up the dupes) |
* |
* @param string $seqname the sequence name to clean up |
* |
* @return bool true on success. A DB_Error object on failure. |
* |
* @access private |
*/ |
function _BCsequence($seqname) |
{ |
// Obtain a user-level lock... this will release any previous |
// application locks, but unlike LOCK TABLES, it does not abort |
// the current transaction and is much less frequently used. |
$result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)"); |
if (DB::isError($result)) { |
return $result; |
} |
if ($result == 0) { |
// Failed to get the lock, can't do the conversion, bail |
// with a DB_ERROR_NOT_LOCKED error |
return $this->mysqliRaiseError(DB_ERROR_NOT_LOCKED); |
} |
$highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}"); |
if (DB::isError($highest_id)) { |
return $highest_id; |
} |
// This should kill all rows except the highest |
// We should probably do something if $highest_id isn't |
// numeric, but I'm at a loss as how to handle that... |
$result = $this->query('DELETE FROM ' . $seqname |
. " WHERE id <> $highest_id"); |
if (DB::isError($result)) { |
return $result; |
} |
// If another thread has been waiting for this lock, |
// it will go thru the above procedure, but will have no |
// real effect |
$result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')"); |
if (DB::isError($result)) { |
return $result; |
} |
return true; |
} |
// }}} |
// {{{ quoteIdentifier() |
/** |
* Quotes a string so it can be safely used as a table or column name |
* (WARNING: using names that require this is a REALLY BAD IDEA) |
* |
* WARNING: Older versions of MySQL can't handle the backtick |
* character (<kbd>`</kbd>) in table or column names. |
* |
* @param string $str identifier name to be quoted |
* |
* @return string quoted identifier string |
* |
* @see DB_common::quoteIdentifier() |
* @since Method available since Release 1.6.0 |
*/ |
function quoteIdentifier($str) |
{ |
return '`' . str_replace('`', '``', $str) . '`'; |
} |
// }}} |
// {{{ escapeSimple() |
/** |
* Escapes a string according to the current DBMS's standards |
* |
* @param string $str the string to be escaped |
* |
* @return string the escaped string |
* |
* @see DB_common::quoteSmart() |
* @since Method available since Release 1.6.0 |
*/ |
function escapeSimple($str) |
{ |
return @mysqli_real_escape_string($this->connection, $str); |
} |
// }}} |
// {{{ modifyLimitQuery() |
/** |
* Adds LIMIT clauses to a query string according to current DBMS standards |
* |
* @param string $query the query to modify |
* @param int $from the row to start to fetching (0 = the first row) |
* @param int $count the numbers of rows to fetch |
* @param mixed $params array, string or numeric data to be used in |
* execution of the statement. Quantity of items |
* passed must match quantity of placeholders in |
* query: meaning 1 placeholder for non-array |
* parameters or 1 placeholder per array element. |
* |
* @return string the query string with LIMIT clauses added |
* |
* @access protected |
*/ |
function modifyLimitQuery($query, $from, $count, $params = array()) |
{ |
if (DB::isManip($query) || $this->_next_query_manip) { |
return $query . " LIMIT $count"; |
} else { |
return $query . " LIMIT $from, $count"; |
} |
} |
// }}} |
// {{{ mysqliRaiseError() |
/** |
* Produces a DB_Error object regarding the current problem |
* |
* @param int $errno if the error is being manually raised pass a |
* DB_ERROR* constant here. If this isn't passed |
* the error information gathered from the DBMS. |
* |
* @return object the DB_Error object |
* |
* @see DB_common::raiseError(), |
* DB_mysqli::errorNative(), DB_common::errorCode() |
*/ |
function mysqliRaiseError($errno = null) |
{ |
if ($errno === null) { |
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) { |
$this->errorcode_map[1022] = DB_ERROR_CONSTRAINT; |
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL; |
$this->errorcode_map[1062] = DB_ERROR_CONSTRAINT; |
} else { |
// Doing this in case mode changes during runtime. |
$this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS; |
$this->errorcode_map[1048] = DB_ERROR_CONSTRAINT; |
$this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS; |
} |
$errno = $this->errorCode(mysqli_errno($this->connection)); |
} |
return $this->raiseError($errno, null, null, null, |
@mysqli_errno($this->connection) . ' ** ' . |
@mysqli_error($this->connection)); |
} |
// }}} |
// {{{ errorNative() |
/** |
* Gets the DBMS' native error code produced by the last query |
* |
* @return int the DBMS' error code |
*/ |
function errorNative() |
{ |
return @mysqli_errno($this->connection); |
} |
// }}} |
// {{{ tableInfo() |
/** |
* Returns information about a table or a result set |
* |
* @param object|string $result DB_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 DB_Error object on failure. |
* |
* @see DB_common::setOption() |
*/ |
function tableInfo($result, $mode = null) |
{ |
if (is_string($result)) { |
// Fix for bug #11580. |
if ($this->_db) { |
if (!@mysqli_select_db($this->connection, $this->_db)) { |
return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); |
} |
} |
/* |
* Probably received a table name. |
* Create a result resource identifier. |
*/ |
$id = @mysqli_query($this->connection, |
"SELECT * FROM $result LIMIT 0"); |
$got_string = true; |
} elseif (isset($result->result)) { |
/* |
* Probably received a result object. |
* Extract the result resource identifier. |
*/ |
$id = $result->result; |
$got_string = false; |
} else { |
/* |
* Probably received a result resource identifier. |
* Copy it. |
* Deprecated. Here for compatibility only. |
*/ |
$id = $result; |
$got_string = false; |
} |
if (!is_a($id, 'mysqli_result')) { |
return $this->mysqliRaiseError(DB_ERROR_NEED_MORE_DATA); |
} |
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) { |
$case_func = 'strtolower'; |
} else { |
$case_func = 'strval'; |
} |
$count = @mysqli_num_fields($id); |
$res = array(); |
if ($mode) { |
$res['num_fields'] = $count; |
} |
for ($i = 0; $i < $count; $i++) { |
$tmp = @mysqli_fetch_field($id); |
$flags = ''; |
foreach ($this->mysqli_flags as $const => $means) { |
if ($tmp->flags & $const) { |
$flags .= $means . ' '; |
} |
} |
if ($tmp->def) { |
$flags .= 'default_' . rawurlencode($tmp->def); |
} |
$flags = trim($flags); |
$res[$i] = array( |
'table' => $case_func($tmp->table), |
'name' => $case_func($tmp->name), |
'type' => isset($this->mysqli_types[$tmp->type]) |
? $this->mysqli_types[$tmp->type] |
: 'unknown', |
// http://bugs.php.net/?id=36579 |
'len' => $tmp->length, |
'flags' => $flags, |
); |
if ($mode & DB_TABLEINFO_ORDER) { |
$res['order'][$res[$i]['name']] = $i; |
} |
if ($mode & DB_TABLEINFO_ORDERTABLE) { |
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; |
} |
} |
// free the result only if we were called on a table |
if ($got_string) { |
@mysqli_free_result($id); |
} |
return $res; |
} |
// }}} |
// {{{ getSpecialQuery() |
/** |
* Obtains the query string needed for listing a given type of objects |
* |
* @param string $type the kind of objects you want to retrieve |
* |
* @return string the SQL query string or null if the driver doesn't |
* support the object type requested |
* |
* @access protected |
* @see DB_common::getListOf() |
*/ |
function getSpecialQuery($type) |
{ |
switch ($type) { |
case 'tables': |
return 'SHOW TABLES'; |
case 'users': |
return 'SELECT DISTINCT User FROM mysql.user'; |
case 'databases': |
return 'SHOW DATABASES'; |
default: |
return null; |
} |
} |
// }}} |
} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/Smarty.class.php |
---|
Новый файл |
0,0 → 1,1960 |
<?php |
/** |
* Project: Smarty: the PHP compiling template engine |
* File: Smarty.class.php |
* |
* 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 |
* |
* For questions, help, comments, discussion, etc., please join the |
* Smarty mailing list. Send a blank e-mail to |
* smarty-discussion-subscribe@googlegroups.com |
* |
* @link http://www.smarty.net/ |
* @copyright 2001-2005 New Digital Group, Inc. |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author Andrei Zmievski <andrei@php.net> |
* @package Smarty |
* @version 2.6.22 |
*/ |
/* $Id: Smarty.class.php 2785 2008-09-18 21:04:12Z Uwe.Tews $ */ |
/** |
* DIR_SEP isn't used anymore, but third party apps might |
*/ |
if(!defined('DIR_SEP')) { |
define('DIR_SEP', DIRECTORY_SEPARATOR); |
} |
/** |
* set SMARTY_DIR to absolute path to Smarty library files. |
* if not defined, include_path will be used. Sets SMARTY_DIR only if user |
* application has not already defined it. |
*/ |
if (!defined('SMARTY_DIR')) { |
define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); |
} |
if (!defined('SMARTY_CORE_DIR')) { |
define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); |
} |
define('SMARTY_PHP_PASSTHRU', 0); |
define('SMARTY_PHP_QUOTE', 1); |
define('SMARTY_PHP_REMOVE', 2); |
define('SMARTY_PHP_ALLOW', 3); |
/** |
* @package Smarty |
*/ |
class Smarty |
{ |
/**#@+ |
* Smarty Configuration Section |
*/ |
/** |
* The name of the directory where templates are located. |
* |
* @var string |
*/ |
var $template_dir = 'templates'; |
/** |
* The directory where compiled templates are located. |
* |
* @var string |
*/ |
var $compile_dir = 'templates_c'; |
/** |
* The directory where config files are located. |
* |
* @var string |
*/ |
var $config_dir = 'configs'; |
/** |
* An array of directories searched for plugins. |
* |
* @var array |
*/ |
var $plugins_dir = array('plugins'); |
/** |
* If debugging is enabled, a debug console window will display |
* when the page loads (make sure your browser allows unrequested |
* popup windows) |
* |
* @var boolean |
*/ |
var $debugging = false; |
/** |
* When set, smarty does uses this value as error_reporting-level. |
* |
* @var boolean |
*/ |
var $error_reporting = null; |
/** |
* This is the path to the debug console template. If not set, |
* the default one will be used. |
* |
* @var string |
*/ |
var $debug_tpl = ''; |
/** |
* This determines if debugging is enable-able from the browser. |
* <ul> |
* <li>NONE => no debugging control allowed</li> |
* <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li> |
* </ul> |
* @link http://www.foo.dom/index.php?SMARTY_DEBUG |
* @var string |
*/ |
var $debugging_ctrl = 'NONE'; |
/** |
* This tells Smarty whether to check for recompiling or not. Recompiling |
* does not need to happen unless a template or config file is changed. |
* Typically you enable this during development, and disable for |
* production. |
* |
* @var boolean |
*/ |
var $compile_check = true; |
/** |
* This forces templates to compile every time. Useful for development |
* or debugging. |
* |
* @var boolean |
*/ |
var $force_compile = false; |
/** |
* This enables template caching. |
* <ul> |
* <li>0 = no caching</li> |
* <li>1 = use class cache_lifetime value</li> |
* <li>2 = use cache_lifetime in cache file</li> |
* </ul> |
* @var integer |
*/ |
var $caching = 0; |
/** |
* The name of the directory for cache files. |
* |
* @var string |
*/ |
var $cache_dir = 'cache'; |
/** |
* This is the number of seconds cached content will persist. |
* <ul> |
* <li>0 = always regenerate cache</li> |
* <li>-1 = never expires</li> |
* </ul> |
* |
* @var integer |
*/ |
var $cache_lifetime = 3600; |
/** |
* Only used when $caching is enabled. If true, then If-Modified-Since headers |
* are respected with cached content, and appropriate HTTP headers are sent. |
* This way repeated hits to a cached page do not send the entire page to the |
* client every time. |
* |
* @var boolean |
*/ |
var $cache_modified_check = false; |
/** |
* This determines how Smarty handles "<?php ... ?>" tags in templates. |
* possible values: |
* <ul> |
* <li>SMARTY_PHP_PASSTHRU -> print tags as plain text</li> |
* <li>SMARTY_PHP_QUOTE -> escape tags as entities</li> |
* <li>SMARTY_PHP_REMOVE -> remove php tags</li> |
* <li>SMARTY_PHP_ALLOW -> execute php tags</li> |
* </ul> |
* |
* @var integer |
*/ |
var $php_handling = SMARTY_PHP_PASSTHRU; |
/** |
* This enables template security. When enabled, many things are restricted |
* in the templates that normally would go unchecked. This is useful when |
* untrusted parties are editing templates and you want a reasonable level |
* of security. (no direct execution of PHP in templates for example) |
* |
* @var boolean |
*/ |
var $security = false; |
/** |
* This is the list of template directories that are considered secure. This |
* is used only if {@link $security} is enabled. One directory per array |
* element. {@link $template_dir} is in this list implicitly. |
* |
* @var array |
*/ |
var $secure_dir = array(); |
/** |
* These are the security settings for Smarty. They are used only when |
* {@link $security} is enabled. |
* |
* @var array |
*/ |
var $security_settings = array( |
'PHP_HANDLING' => false, |
'IF_FUNCS' => array('array', 'list', |
'isset', 'empty', |
'count', 'sizeof', |
'in_array', 'is_array', |
'true', 'false', 'null'), |
'INCLUDE_ANY' => false, |
'PHP_TAGS' => false, |
'MODIFIER_FUNCS' => array('count'), |
'ALLOW_CONSTANTS' => false |
); |
/** |
* This is an array of directories where trusted php scripts reside. |
* {@link $security} is disabled during their inclusion/execution. |
* |
* @var array |
*/ |
var $trusted_dir = array(); |
/** |
* The left delimiter used for the template tags. |
* |
* @var string |
*/ |
var $left_delimiter = '{'; |
/** |
* The right delimiter used for the template tags. |
* |
* @var string |
*/ |
var $right_delimiter = '}'; |
/** |
* The order in which request variables are registered, similar to |
* variables_order in php.ini E = Environment, G = GET, P = POST, |
* C = Cookies, S = Server |
* |
* @var string |
*/ |
var $request_vars_order = 'EGPCS'; |
/** |
* Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) |
* are uses as request-vars or $_*[]-vars. note: if |
* request_use_auto_globals is true, then $request_vars_order has |
* no effect, but the php-ini-value "gpc_order" |
* |
* @var boolean |
*/ |
var $request_use_auto_globals = true; |
/** |
* Set this if you want different sets of compiled files for the same |
* templates. This is useful for things like different languages. |
* Instead of creating separate sets of templates per language, you |
* set different compile_ids like 'en' and 'de'. |
* |
* @var string |
*/ |
var $compile_id = null; |
/** |
* This tells Smarty whether or not to use sub dirs in the cache/ and |
* templates_c/ directories. sub directories better organized, but |
* may not work well with PHP safe mode enabled. |
* |
* @var boolean |
* |
*/ |
var $use_sub_dirs = false; |
/** |
* This is a list of the modifiers to apply to all template variables. |
* Put each modifier in a separate array element in the order you want |
* them applied. example: <code>array('escape:"htmlall"');</code> |
* |
* @var array |
*/ |
var $default_modifiers = array(); |
/** |
* This is the resource type to be used when not specified |
* at the beginning of the resource path. examples: |
* $smarty->display('file:index.tpl'); |
* $smarty->display('db:index.tpl'); |
* $smarty->display('index.tpl'); // will use default resource type |
* {include file="file:index.tpl"} |
* {include file="db:index.tpl"} |
* {include file="index.tpl"} {* will use default resource type *} |
* |
* @var array |
*/ |
var $default_resource_type = 'file'; |
/** |
* The function used for cache file handling. If not set, built-in caching is used. |
* |
* @var null|string function name |
*/ |
var $cache_handler_func = null; |
/** |
* This indicates which filters are automatically loaded into Smarty. |
* |
* @var array array of filter names |
*/ |
var $autoload_filters = array(); |
/**#@+ |
* @var boolean |
*/ |
/** |
* This tells if config file vars of the same name overwrite each other or not. |
* if disabled, same name variables are accumulated in an array. |
*/ |
var $config_overwrite = true; |
/** |
* This tells whether or not to automatically booleanize config file variables. |
* If enabled, then the strings "on", "true", and "yes" are treated as boolean |
* true, and "off", "false" and "no" are treated as boolean false. |
*/ |
var $config_booleanize = true; |
/** |
* This tells whether hidden sections [.foobar] are readable from the |
* tempalates or not. Normally you would never allow this since that is |
* the point behind hidden sections: the application can access them, but |
* the templates cannot. |
*/ |
var $config_read_hidden = false; |
/** |
* This tells whether or not automatically fix newlines in config files. |
* It basically converts \r (mac) or \r\n (dos) to \n |
*/ |
var $config_fix_newlines = true; |
/**#@-*/ |
/** |
* If a template cannot be found, this PHP function will be executed. |
* Useful for creating templates on-the-fly or other special action. |
* |
* @var string function name |
*/ |
var $default_template_handler_func = ''; |
/** |
* The file that contains the compiler class. This can a full |
* pathname, or relative to the php_include path. |
* |
* @var string |
*/ |
var $compiler_file = 'Smarty_Compiler.class.php'; |
/** |
* The class used for compiling templates. |
* |
* @var string |
*/ |
var $compiler_class = 'Smarty_Compiler'; |
/** |
* The class used to load config vars. |
* |
* @var string |
*/ |
var $config_class = 'Config_File'; |
/**#@+ |
* END Smarty Configuration Section |
* There should be no need to touch anything below this line. |
* @access private |
*/ |
/** |
* where assigned template vars are kept |
* |
* @var array |
*/ |
var $_tpl_vars = array(); |
/** |
* stores run-time $smarty.* vars |
* |
* @var null|array |
*/ |
var $_smarty_vars = null; |
/** |
* keeps track of sections |
* |
* @var array |
*/ |
var $_sections = array(); |
/** |
* keeps track of foreach blocks |
* |
* @var array |
*/ |
var $_foreach = array(); |
/** |
* keeps track of tag hierarchy |
* |
* @var array |
*/ |
var $_tag_stack = array(); |
/** |
* configuration object |
* |
* @var Config_file |
*/ |
var $_conf_obj = null; |
/** |
* loaded configuration settings |
* |
* @var array |
*/ |
var $_config = array(array('vars' => array(), 'files' => array())); |
/** |
* md5 checksum of the string 'Smarty' |
* |
* @var string |
*/ |
var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; |
/** |
* Smarty version number |
* |
* @var string |
*/ |
var $_version = '2.6.22'; |
/** |
* current template inclusion depth |
* |
* @var integer |
*/ |
var $_inclusion_depth = 0; |
/** |
* for different compiled templates |
* |
* @var string |
*/ |
var $_compile_id = null; |
/** |
* text in URL to enable debug mode |
* |
* @var string |
*/ |
var $_smarty_debug_id = 'SMARTY_DEBUG'; |
/** |
* debugging information for debug console |
* |
* @var array |
*/ |
var $_smarty_debug_info = array(); |
/** |
* info that makes up a cache file |
* |
* @var array |
*/ |
var $_cache_info = array(); |
/** |
* default file permissions |
* |
* @var integer |
*/ |
var $_file_perms = 0644; |
/** |
* default dir permissions |
* |
* @var integer |
*/ |
var $_dir_perms = 0771; |
/** |
* registered objects |
* |
* @var array |
*/ |
var $_reg_objects = array(); |
/** |
* table keeping track of plugins |
* |
* @var array |
*/ |
var $_plugins = array( |
'modifier' => array(), |
'function' => array(), |
'block' => array(), |
'compiler' => array(), |
'prefilter' => array(), |
'postfilter' => array(), |
'outputfilter' => array(), |
'resource' => array(), |
'insert' => array()); |
/** |
* cache serials |
* |
* @var array |
*/ |
var $_cache_serials = array(); |
/** |
* name of optional cache include file |
* |
* @var string |
*/ |
var $_cache_include = null; |
/** |
* indicate if the current code is used in a compiled |
* include |
* |
* @var string |
*/ |
var $_cache_including = false; |
/**#@-*/ |
/** |
* The class constructor. |
*/ |
function Smarty() |
{ |
$this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] |
: @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); |
} |
/** |
* assigns values to template variables |
* |
* @param array|string $tpl_var the template variable name(s) |
* @param mixed $value the value to assign |
*/ |
function assign($tpl_var, $value = null) |
{ |
if (is_array($tpl_var)){ |
foreach ($tpl_var as $key => $val) { |
if ($key != '') { |
$this->_tpl_vars[$key] = $val; |
} |
} |
} else { |
if ($tpl_var != '') |
$this->_tpl_vars[$tpl_var] = $value; |
} |
} |
/** |
* assigns values to template variables by reference |
* |
* @param string $tpl_var the template variable name |
* @param mixed $value the referenced value to assign |
*/ |
function assign_by_ref($tpl_var, &$value) |
{ |
if ($tpl_var != '') |
$this->_tpl_vars[$tpl_var] = &$value; |
} |
/** |
* appends values to template variables |
* |
* @param array|string $tpl_var the template variable name(s) |
* @param mixed $value the value to append |
*/ |
function append($tpl_var, $value=null, $merge=false) |
{ |
if (is_array($tpl_var)) { |
// $tpl_var is an array, ignore $value |
foreach ($tpl_var as $_key => $_val) { |
if ($_key != '') { |
if(!@is_array($this->_tpl_vars[$_key])) { |
settype($this->_tpl_vars[$_key],'array'); |
} |
if($merge && is_array($_val)) { |
foreach($_val as $_mkey => $_mval) { |
$this->_tpl_vars[$_key][$_mkey] = $_mval; |
} |
} else { |
$this->_tpl_vars[$_key][] = $_val; |
} |
} |
} |
} else { |
if ($tpl_var != '' && isset($value)) { |
if(!@is_array($this->_tpl_vars[$tpl_var])) { |
settype($this->_tpl_vars[$tpl_var],'array'); |
} |
if($merge && is_array($value)) { |
foreach($value as $_mkey => $_mval) { |
$this->_tpl_vars[$tpl_var][$_mkey] = $_mval; |
} |
} else { |
$this->_tpl_vars[$tpl_var][] = $value; |
} |
} |
} |
} |
/** |
* appends values to template variables by reference |
* |
* @param string $tpl_var the template variable name |
* @param mixed $value the referenced value to append |
*/ |
function append_by_ref($tpl_var, &$value, $merge=false) |
{ |
if ($tpl_var != '' && isset($value)) { |
if(!@is_array($this->_tpl_vars[$tpl_var])) { |
settype($this->_tpl_vars[$tpl_var],'array'); |
} |
if ($merge && is_array($value)) { |
foreach($value as $_key => $_val) { |
$this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; |
} |
} else { |
$this->_tpl_vars[$tpl_var][] = &$value; |
} |
} |
} |
/** |
* clear the given assigned template variable. |
* |
* @param string $tpl_var the template variable to clear |
*/ |
function clear_assign($tpl_var) |
{ |
if (is_array($tpl_var)) |
foreach ($tpl_var as $curr_var) |
unset($this->_tpl_vars[$curr_var]); |
else |
unset($this->_tpl_vars[$tpl_var]); |
} |
/** |
* Registers custom function to be used in templates |
* |
* @param string $function the name of the template function |
* @param string $function_impl the name of the PHP function to register |
*/ |
function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) |
{ |
$this->_plugins['function'][$function] = |
array($function_impl, null, null, false, $cacheable, $cache_attrs); |
} |
/** |
* Unregisters custom function |
* |
* @param string $function name of template function |
*/ |
function unregister_function($function) |
{ |
unset($this->_plugins['function'][$function]); |
} |
/** |
* Registers object to be used in templates |
* |
* @param string $object name of template object |
* @param object &$object_impl the referenced PHP object to register |
* @param null|array $allowed list of allowed methods (empty = all) |
* @param boolean $smarty_args smarty argument format, else traditional |
* @param null|array $block_functs list of methods that are block format |
*/ |
function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) |
{ |
settype($allowed, 'array'); |
settype($smarty_args, 'boolean'); |
$this->_reg_objects[$object] = |
array(&$object_impl, $allowed, $smarty_args, $block_methods); |
} |
/** |
* Unregisters object |
* |
* @param string $object name of template object |
*/ |
function unregister_object($object) |
{ |
unset($this->_reg_objects[$object]); |
} |
/** |
* Registers block function to be used in templates |
* |
* @param string $block name of template block |
* @param string $block_impl PHP function to register |
*/ |
function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) |
{ |
$this->_plugins['block'][$block] = |
array($block_impl, null, null, false, $cacheable, $cache_attrs); |
} |
/** |
* Unregisters block function |
* |
* @param string $block name of template function |
*/ |
function unregister_block($block) |
{ |
unset($this->_plugins['block'][$block]); |
} |
/** |
* Registers compiler function |
* |
* @param string $function name of template function |
* @param string $function_impl name of PHP function to register |
*/ |
function register_compiler_function($function, $function_impl, $cacheable=true) |
{ |
$this->_plugins['compiler'][$function] = |
array($function_impl, null, null, false, $cacheable); |
} |
/** |
* Unregisters compiler function |
* |
* @param string $function name of template function |
*/ |
function unregister_compiler_function($function) |
{ |
unset($this->_plugins['compiler'][$function]); |
} |
/** |
* Registers modifier to be used in templates |
* |
* @param string $modifier name of template modifier |
* @param string $modifier_impl name of PHP function to register |
*/ |
function register_modifier($modifier, $modifier_impl) |
{ |
$this->_plugins['modifier'][$modifier] = |
array($modifier_impl, null, null, false); |
} |
/** |
* Unregisters modifier |
* |
* @param string $modifier name of template modifier |
*/ |
function unregister_modifier($modifier) |
{ |
unset($this->_plugins['modifier'][$modifier]); |
} |
/** |
* Registers a resource to fetch a template |
* |
* @param string $type name of resource |
* @param array $functions array of functions to handle resource |
*/ |
function register_resource($type, $functions) |
{ |
if (count($functions)==4) { |
$this->_plugins['resource'][$type] = |
array($functions, false); |
} elseif (count($functions)==5) { |
$this->_plugins['resource'][$type] = |
array(array(array(&$functions[0], $functions[1]) |
,array(&$functions[0], $functions[2]) |
,array(&$functions[0], $functions[3]) |
,array(&$functions[0], $functions[4])) |
,false); |
} else { |
$this->trigger_error("malformed function-list for '$type' in register_resource"); |
} |
} |
/** |
* Unregisters a resource |
* |
* @param string $type name of resource |
*/ |
function unregister_resource($type) |
{ |
unset($this->_plugins['resource'][$type]); |
} |
/** |
* Registers a prefilter function to apply |
* to a template before compiling |
* |
* @param callback $function |
*/ |
function register_prefilter($function) |
{ |
$this->_plugins['prefilter'][$this->_get_filter_name($function)] |
= array($function, null, null, false); |
} |
/** |
* Unregisters a prefilter function |
* |
* @param callback $function |
*/ |
function unregister_prefilter($function) |
{ |
unset($this->_plugins['prefilter'][$this->_get_filter_name($function)]); |
} |
/** |
* Registers a postfilter function to apply |
* to a compiled template after compilation |
* |
* @param callback $function |
*/ |
function register_postfilter($function) |
{ |
$this->_plugins['postfilter'][$this->_get_filter_name($function)] |
= array($function, null, null, false); |
} |
/** |
* Unregisters a postfilter function |
* |
* @param callback $function |
*/ |
function unregister_postfilter($function) |
{ |
unset($this->_plugins['postfilter'][$this->_get_filter_name($function)]); |
} |
/** |
* Registers an output filter function to apply |
* to a template output |
* |
* @param callback $function |
*/ |
function register_outputfilter($function) |
{ |
$this->_plugins['outputfilter'][$this->_get_filter_name($function)] |
= array($function, null, null, false); |
} |
/** |
* Unregisters an outputfilter function |
* |
* @param callback $function |
*/ |
function unregister_outputfilter($function) |
{ |
unset($this->_plugins['outputfilter'][$this->_get_filter_name($function)]); |
} |
/** |
* load a filter of specified type and name |
* |
* @param string $type filter type |
* @param string $name filter name |
*/ |
function load_filter($type, $name) |
{ |
switch ($type) { |
case 'output': |
$_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); |
require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); |
smarty_core_load_plugins($_params, $this); |
break; |
case 'pre': |
case 'post': |
if (!isset($this->_plugins[$type . 'filter'][$name])) |
$this->_plugins[$type . 'filter'][$name] = false; |
break; |
} |
} |
/** |
* clear cached content for the given template and cache id |
* |
* @param string $tpl_file name of template file |
* @param string $cache_id name of cache_id |
* @param string $compile_id name of compile_id |
* @param string $exp_time expiration time |
* @return boolean |
*/ |
function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) |
{ |
if (!isset($compile_id)) |
$compile_id = $this->compile_id; |
if (!isset($tpl_file)) |
$compile_id = null; |
$_auto_id = $this->_get_auto_id($cache_id, $compile_id); |
if (!empty($this->cache_handler_func)) { |
return call_user_func_array($this->cache_handler_func, |
array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); |
} else { |
$_params = array('auto_base' => $this->cache_dir, |
'auto_source' => $tpl_file, |
'auto_id' => $_auto_id, |
'exp_time' => $exp_time); |
require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); |
return smarty_core_rm_auto($_params, $this); |
} |
} |
/** |
* clear the entire contents of cache (all templates) |
* |
* @param string $exp_time expire time |
* @return boolean results of {@link smarty_core_rm_auto()} |
*/ |
function clear_all_cache($exp_time = null) |
{ |
return $this->clear_cache(null, null, null, $exp_time); |
} |
/** |
* test to see if valid cache exists for this template |
* |
* @param string $tpl_file name of template file |
* @param string $cache_id |
* @param string $compile_id |
* @return string|false results of {@link _read_cache_file()} |
*/ |
function is_cached($tpl_file, $cache_id = null, $compile_id = null) |
{ |
if (!$this->caching) |
return false; |
if (!isset($compile_id)) |
$compile_id = $this->compile_id; |
$_params = array( |
'tpl_file' => $tpl_file, |
'cache_id' => $cache_id, |
'compile_id' => $compile_id |
); |
require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); |
return smarty_core_read_cache_file($_params, $this); |
} |
/** |
* clear all the assigned template variables. |
* |
*/ |
function clear_all_assign() |
{ |
$this->_tpl_vars = array(); |
} |
/** |
* clears compiled version of specified template resource, |
* or all compiled template files if one is not specified. |
* This function is for advanced use only, not normally needed. |
* |
* @param string $tpl_file |
* @param string $compile_id |
* @param string $exp_time |
* @return boolean results of {@link smarty_core_rm_auto()} |
*/ |
function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) |
{ |
if (!isset($compile_id)) { |
$compile_id = $this->compile_id; |
} |
$_params = array('auto_base' => $this->compile_dir, |
'auto_source' => $tpl_file, |
'auto_id' => $compile_id, |
'exp_time' => $exp_time, |
'extensions' => array('.inc', '.php')); |
require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); |
return smarty_core_rm_auto($_params, $this); |
} |
/** |
* Checks whether requested template exists. |
* |
* @param string $tpl_file |
* @return boolean |
*/ |
function template_exists($tpl_file) |
{ |
$_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); |
return $this->_fetch_resource_info($_params); |
} |
/** |
* Returns an array containing template variables |
* |
* @param string $name |
* @param string $type |
* @return array |
*/ |
function &get_template_vars($name=null) |
{ |
if(!isset($name)) { |
return $this->_tpl_vars; |
} elseif(isset($this->_tpl_vars[$name])) { |
return $this->_tpl_vars[$name]; |
} else { |
// var non-existant, return valid reference |
$_tmp = null; |
return $_tmp; |
} |
} |
/** |
* Returns an array containing config variables |
* |
* @param string $name |
* @param string $type |
* @return array |
*/ |
function &get_config_vars($name=null) |
{ |
if(!isset($name) && is_array($this->_config[0])) { |
return $this->_config[0]['vars']; |
} else if(isset($this->_config[0]['vars'][$name])) { |
return $this->_config[0]['vars'][$name]; |
} else { |
// var non-existant, return valid reference |
$_tmp = null; |
return $_tmp; |
} |
} |
/** |
* trigger Smarty error |
* |
* @param string $error_msg |
* @param integer $error_type |
*/ |
function trigger_error($error_msg, $error_type = E_USER_WARNING) |
{ |
trigger_error("Smarty error: $error_msg", $error_type); |
} |
/** |
* executes & displays the template results |
* |
* @param string $resource_name |
* @param string $cache_id |
* @param string $compile_id |
*/ |
function display($resource_name, $cache_id = null, $compile_id = null) |
{ |
$this->fetch($resource_name, $cache_id, $compile_id, true); |
} |
/** |
* executes & returns or displays the template results |
* |
* @param string $resource_name |
* @param string $cache_id |
* @param string $compile_id |
* @param boolean $display |
*/ |
function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) |
{ |
static $_cache_info = array(); |
$_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) |
? $this->error_reporting : error_reporting() & ~E_NOTICE); |
if (!$this->debugging && $this->debugging_ctrl == 'URL') { |
$_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; |
if (@strstr($_query_string, $this->_smarty_debug_id)) { |
if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { |
// enable debugging for this browser session |
@setcookie('SMARTY_DEBUG', true); |
$this->debugging = true; |
} elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { |
// disable debugging for this browser session |
@setcookie('SMARTY_DEBUG', false); |
$this->debugging = false; |
} else { |
// enable debugging for this page |
$this->debugging = true; |
} |
} else { |
$this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); |
} |
} |
if ($this->debugging) { |
// capture time for debugging info |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$_debug_start_time = smarty_core_get_microtime($_params, $this); |
$this->_smarty_debug_info[] = array('type' => 'template', |
'filename' => $resource_name, |
'depth' => 0); |
$_included_tpls_idx = count($this->_smarty_debug_info) - 1; |
} |
if (!isset($compile_id)) { |
$compile_id = $this->compile_id; |
} |
$this->_compile_id = $compile_id; |
$this->_inclusion_depth = 0; |
if ($this->caching) { |
// save old cache_info, initialize cache_info |
array_push($_cache_info, $this->_cache_info); |
$this->_cache_info = array(); |
$_params = array( |
'tpl_file' => $resource_name, |
'cache_id' => $cache_id, |
'compile_id' => $compile_id, |
'results' => null |
); |
require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); |
if (smarty_core_read_cache_file($_params, $this)) { |
$_smarty_results = $_params['results']; |
if (!empty($this->_cache_info['insert_tags'])) { |
$_params = array('plugins' => $this->_cache_info['insert_tags']); |
require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); |
smarty_core_load_plugins($_params, $this); |
$_params = array('results' => $_smarty_results); |
require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); |
$_smarty_results = smarty_core_process_cached_inserts($_params, $this); |
} |
if (!empty($this->_cache_info['cache_serials'])) { |
$_params = array('results' => $_smarty_results); |
require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); |
$_smarty_results = smarty_core_process_compiled_include($_params, $this); |
} |
if ($display) { |
if ($this->debugging) |
{ |
// capture time for debugging info |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; |
require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); |
$_smarty_results .= smarty_core_display_debug_console($_params, $this); |
} |
if ($this->cache_modified_check) { |
$_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; |
$_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); |
$_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; |
if (@count($this->_cache_info['insert_tags']) == 0 |
&& !$this->_cache_serials |
&& $_gmt_mtime == $_last_modified_date) { |
if (php_sapi_name()=='cgi') |
header('Status: 304 Not Modified'); |
else |
header('HTTP/1.1 304 Not Modified'); |
} else { |
header('Last-Modified: '.$_gmt_mtime); |
echo $_smarty_results; |
} |
} else { |
echo $_smarty_results; |
} |
error_reporting($_smarty_old_error_level); |
// restore initial cache_info |
$this->_cache_info = array_pop($_cache_info); |
return true; |
} else { |
error_reporting($_smarty_old_error_level); |
// restore initial cache_info |
$this->_cache_info = array_pop($_cache_info); |
return $_smarty_results; |
} |
} else { |
$this->_cache_info['template'][$resource_name] = true; |
if ($this->cache_modified_check && $display) { |
header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); |
} |
} |
} |
// load filters that are marked as autoload |
if (count($this->autoload_filters)) { |
foreach ($this->autoload_filters as $_filter_type => $_filters) { |
foreach ($_filters as $_filter) { |
$this->load_filter($_filter_type, $_filter); |
} |
} |
} |
$_smarty_compile_path = $this->_get_compile_path($resource_name); |
// if we just need to display the results, don't perform output |
// buffering - for speed |
$_cache_including = $this->_cache_including; |
$this->_cache_including = false; |
if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { |
if ($this->_is_compiled($resource_name, $_smarty_compile_path) |
|| $this->_compile_resource($resource_name, $_smarty_compile_path)) |
{ |
include($_smarty_compile_path); |
} |
} else { |
ob_start(); |
if ($this->_is_compiled($resource_name, $_smarty_compile_path) |
|| $this->_compile_resource($resource_name, $_smarty_compile_path)) |
{ |
include($_smarty_compile_path); |
} |
$_smarty_results = ob_get_contents(); |
ob_end_clean(); |
foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { |
$_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); |
} |
} |
if ($this->caching) { |
$_params = array('tpl_file' => $resource_name, |
'cache_id' => $cache_id, |
'compile_id' => $compile_id, |
'results' => $_smarty_results); |
require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); |
smarty_core_write_cache_file($_params, $this); |
require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); |
$_smarty_results = smarty_core_process_cached_inserts($_params, $this); |
if ($this->_cache_serials) { |
// strip nocache-tags from output |
$_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' |
,'' |
,$_smarty_results); |
} |
// restore initial cache_info |
$this->_cache_info = array_pop($_cache_info); |
} |
$this->_cache_including = $_cache_including; |
if ($display) { |
if (isset($_smarty_results)) { echo $_smarty_results; } |
if ($this->debugging) { |
// capture time for debugging info |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); |
require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); |
echo smarty_core_display_debug_console($_params, $this); |
} |
error_reporting($_smarty_old_error_level); |
return; |
} else { |
error_reporting($_smarty_old_error_level); |
if (isset($_smarty_results)) { return $_smarty_results; } |
} |
} |
/** |
* load configuration values |
* |
* @param string $file |
* @param string $section |
* @param string $scope |
*/ |
function config_load($file, $section = null, $scope = 'global') |
{ |
require_once($this->_get_plugin_filepath('function', 'config_load')); |
smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); |
} |
/** |
* return a reference to a registered object |
* |
* @param string $name |
* @return object |
*/ |
function &get_registered_object($name) { |
if (!isset($this->_reg_objects[$name])) |
$this->_trigger_fatal_error("'$name' is not a registered object"); |
if (!is_object($this->_reg_objects[$name][0])) |
$this->_trigger_fatal_error("registered '$name' is not an object"); |
return $this->_reg_objects[$name][0]; |
} |
/** |
* clear configuration values |
* |
* @param string $var |
*/ |
function clear_config($var = null) |
{ |
if(!isset($var)) { |
// clear all values |
$this->_config = array(array('vars' => array(), |
'files' => array())); |
} else { |
unset($this->_config[0]['vars'][$var]); |
} |
} |
/** |
* get filepath of requested plugin |
* |
* @param string $type |
* @param string $name |
* @return string|false |
*/ |
function _get_plugin_filepath($type, $name) |
{ |
$_params = array('type' => $type, 'name' => $name); |
require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); |
return smarty_core_assemble_plugin_filepath($_params, $this); |
} |
/** |
* test if resource needs compiling |
* |
* @param string $resource_name |
* @param string $compile_path |
* @return boolean |
*/ |
function _is_compiled($resource_name, $compile_path) |
{ |
if (!$this->force_compile && file_exists($compile_path)) { |
if (!$this->compile_check) { |
// no need to check compiled file |
return true; |
} else { |
// get file source and timestamp |
$_params = array('resource_name' => $resource_name, 'get_source'=>false); |
if (!$this->_fetch_resource_info($_params)) { |
return false; |
} |
if ($_params['resource_timestamp'] <= filemtime($compile_path)) { |
// template not expired, no recompile |
return true; |
} else { |
// compile template |
return false; |
} |
} |
} else { |
// compiled template does not exist, or forced compile |
return false; |
} |
} |
/** |
* compile the template |
* |
* @param string $resource_name |
* @param string $compile_path |
* @return boolean |
*/ |
function _compile_resource($resource_name, $compile_path) |
{ |
$_params = array('resource_name' => $resource_name); |
if (!$this->_fetch_resource_info($_params)) { |
return false; |
} |
$_source_content = $_params['source_content']; |
$_cache_include = substr($compile_path, 0, -4).'.inc'; |
if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { |
// if a _cache_serial was set, we also have to write an include-file: |
if ($this->_cache_include_info) { |
require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); |
smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); |
} |
$_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); |
require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); |
smarty_core_write_compiled_resource($_params, $this); |
return true; |
} else { |
return false; |
} |
} |
/** |
* compile the given source |
* |
* @param string $resource_name |
* @param string $source_content |
* @param string $compiled_content |
* @return boolean |
*/ |
function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) |
{ |
if (file_exists(SMARTY_DIR . $this->compiler_file)) { |
require_once(SMARTY_DIR . $this->compiler_file); |
} else { |
// use include_path |
require_once($this->compiler_file); |
} |
$smarty_compiler = new $this->compiler_class; |
$smarty_compiler->template_dir = $this->template_dir; |
$smarty_compiler->compile_dir = $this->compile_dir; |
$smarty_compiler->plugins_dir = $this->plugins_dir; |
$smarty_compiler->config_dir = $this->config_dir; |
$smarty_compiler->force_compile = $this->force_compile; |
$smarty_compiler->caching = $this->caching; |
$smarty_compiler->php_handling = $this->php_handling; |
$smarty_compiler->left_delimiter = $this->left_delimiter; |
$smarty_compiler->right_delimiter = $this->right_delimiter; |
$smarty_compiler->_version = $this->_version; |
$smarty_compiler->security = $this->security; |
$smarty_compiler->secure_dir = $this->secure_dir; |
$smarty_compiler->security_settings = $this->security_settings; |
$smarty_compiler->trusted_dir = $this->trusted_dir; |
$smarty_compiler->use_sub_dirs = $this->use_sub_dirs; |
$smarty_compiler->_reg_objects = &$this->_reg_objects; |
$smarty_compiler->_plugins = &$this->_plugins; |
$smarty_compiler->_tpl_vars = &$this->_tpl_vars; |
$smarty_compiler->default_modifiers = $this->default_modifiers; |
$smarty_compiler->compile_id = $this->_compile_id; |
$smarty_compiler->_config = $this->_config; |
$smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; |
if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { |
$smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; |
} |
$smarty_compiler->_cache_include = $cache_include_path; |
$_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); |
if ($smarty_compiler->_cache_serial) { |
$this->_cache_include_info = array( |
'cache_serial'=>$smarty_compiler->_cache_serial |
,'plugins_code'=>$smarty_compiler->_plugins_code |
,'include_file_path' => $cache_include_path); |
} else { |
$this->_cache_include_info = null; |
} |
return $_results; |
} |
/** |
* Get the compile path for this resource |
* |
* @param string $resource_name |
* @return string results of {@link _get_auto_filename()} |
*/ |
function _get_compile_path($resource_name) |
{ |
return $this->_get_auto_filename($this->compile_dir, $resource_name, |
$this->_compile_id) . '.php'; |
} |
/** |
* fetch the template info. Gets timestamp, and source |
* if get_source is true |
* |
* sets $source_content to the source of the template, and |
* $resource_timestamp to its time stamp |
* @param string $resource_name |
* @param string $source_content |
* @param integer $resource_timestamp |
* @param boolean $get_source |
* @param boolean $quiet |
* @return boolean |
*/ |
function _fetch_resource_info(&$params) |
{ |
if(!isset($params['get_source'])) { $params['get_source'] = true; } |
if(!isset($params['quiet'])) { $params['quiet'] = false; } |
$_return = false; |
$_params = array('resource_name' => $params['resource_name']) ; |
if (isset($params['resource_base_path'])) |
$_params['resource_base_path'] = $params['resource_base_path']; |
else |
$_params['resource_base_path'] = $this->template_dir; |
if ($this->_parse_resource_name($_params)) { |
$_resource_type = $_params['resource_type']; |
$_resource_name = $_params['resource_name']; |
switch ($_resource_type) { |
case 'file': |
if ($params['get_source']) { |
$params['source_content'] = $this->_read_file($_resource_name); |
} |
$params['resource_timestamp'] = filemtime($_resource_name); |
$_return = is_file($_resource_name); |
break; |
default: |
// call resource functions to fetch the template source and timestamp |
if ($params['get_source']) { |
$_source_return = isset($this->_plugins['resource'][$_resource_type]) && |
call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], |
array($_resource_name, &$params['source_content'], &$this)); |
} else { |
$_source_return = true; |
} |
$_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && |
call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], |
array($_resource_name, &$params['resource_timestamp'], &$this)); |
$_return = $_source_return && $_timestamp_return; |
break; |
} |
} |
if (!$_return) { |
// see if we can get a template with the default template handler |
if (!empty($this->default_template_handler_func)) { |
if (!is_callable($this->default_template_handler_func)) { |
$this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); |
} else { |
$_return = call_user_func_array( |
$this->default_template_handler_func, |
array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); |
} |
} |
} |
if (!$_return) { |
if (!$params['quiet']) { |
$this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); |
} |
} else if ($_return && $this->security) { |
require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); |
if (!smarty_core_is_secure($_params, $this)) { |
if (!$params['quiet']) |
$this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); |
$params['source_content'] = null; |
$params['resource_timestamp'] = null; |
return false; |
} |
} |
return $_return; |
} |
/** |
* parse out the type and name from the resource |
* |
* @param string $resource_base_path |
* @param string $resource_name |
* @param string $resource_type |
* @param string $resource_name |
* @return boolean |
*/ |
function _parse_resource_name(&$params) |
{ |
// split tpl_path by the first colon |
$_resource_name_parts = explode(':', $params['resource_name'], 2); |
if (count($_resource_name_parts) == 1) { |
// no resource type given |
$params['resource_type'] = $this->default_resource_type; |
$params['resource_name'] = $_resource_name_parts[0]; |
} else { |
if(strlen($_resource_name_parts[0]) == 1) { |
// 1 char is not resource type, but part of filepath |
$params['resource_type'] = $this->default_resource_type; |
$params['resource_name'] = $params['resource_name']; |
} else { |
$params['resource_type'] = $_resource_name_parts[0]; |
$params['resource_name'] = $_resource_name_parts[1]; |
} |
} |
if ($params['resource_type'] == 'file') { |
if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { |
// relative pathname to $params['resource_base_path'] |
// use the first directory where the file is found |
foreach ((array)$params['resource_base_path'] as $_curr_path) { |
$_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; |
if (file_exists($_fullpath) && is_file($_fullpath)) { |
$params['resource_name'] = $_fullpath; |
return true; |
} |
// didn't find the file, try include_path |
$_params = array('file_path' => $_fullpath); |
require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); |
if(smarty_core_get_include_path($_params, $this)) { |
$params['resource_name'] = $_params['new_file_path']; |
return true; |
} |
} |
return false; |
} else { |
/* absolute path */ |
return file_exists($params['resource_name']); |
} |
} elseif (empty($this->_plugins['resource'][$params['resource_type']])) { |
$_params = array('type' => $params['resource_type']); |
require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); |
smarty_core_load_resource_plugin($_params, $this); |
} |
return true; |
} |
/** |
* Handle modifiers |
* |
* @param string|null $modifier_name |
* @param array|null $map_array |
* @return string result of modifiers |
*/ |
function _run_mod_handler() |
{ |
$_args = func_get_args(); |
list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); |
list($_func_name, $_tpl_file, $_tpl_line) = |
$this->_plugins['modifier'][$_modifier_name]; |
$_var = $_args[0]; |
foreach ($_var as $_key => $_val) { |
$_args[0] = $_val; |
$_var[$_key] = call_user_func_array($_func_name, $_args); |
} |
return $_var; |
} |
/** |
* Remove starting and ending quotes from the string |
* |
* @param string $string |
* @return string |
*/ |
function _dequote($string) |
{ |
if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') && |
substr($string, -1) == substr($string, 0, 1)) |
return substr($string, 1, -1); |
else |
return $string; |
} |
/** |
* read in a file |
* |
* @param string $filename |
* @return string |
*/ |
function _read_file($filename) |
{ |
if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) { |
$contents = ''; |
while (!feof($fd)) { |
$contents .= fread($fd, 8192); |
} |
fclose($fd); |
return $contents; |
} else { |
return false; |
} |
} |
/** |
* get a concrete filename for automagically created content |
* |
* @param string $auto_base |
* @param string $auto_source |
* @param string $auto_id |
* @return string |
* @staticvar string|null |
* @staticvar string|null |
*/ |
function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) |
{ |
$_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; |
$_return = $auto_base . DIRECTORY_SEPARATOR; |
if(isset($auto_id)) { |
// make auto_id safe for directory names |
$auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); |
// split into separate directories |
$_return .= $auto_id . $_compile_dir_sep; |
} |
if(isset($auto_source)) { |
// make source name safe for filename |
$_filename = urlencode(basename($auto_source)); |
$_crc32 = sprintf('%08X', crc32($auto_source)); |
// prepend %% to avoid name conflicts with |
// with $params['auto_id'] names |
$_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . |
substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; |
$_return .= '%%' . $_crc32 . '%%' . $_filename; |
} |
return $_return; |
} |
/** |
* unlink a file, possibly using expiration time |
* |
* @param string $resource |
* @param integer $exp_time |
*/ |
function _unlink($resource, $exp_time = null) |
{ |
if(isset($exp_time)) { |
if(time() - @filemtime($resource) >= $exp_time) { |
return @unlink($resource); |
} |
} else { |
return @unlink($resource); |
} |
} |
/** |
* returns an auto_id for auto-file-functions |
* |
* @param string $cache_id |
* @param string $compile_id |
* @return string|null |
*/ |
function _get_auto_id($cache_id=null, $compile_id=null) { |
if (isset($cache_id)) |
return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; |
elseif(isset($compile_id)) |
return $compile_id; |
else |
return null; |
} |
/** |
* trigger Smarty plugin error |
* |
* @param string $error_msg |
* @param string $tpl_file |
* @param integer $tpl_line |
* @param string $file |
* @param integer $line |
* @param integer $error_type |
*/ |
function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, |
$file = null, $line = null, $error_type = E_USER_ERROR) |
{ |
if(isset($file) && isset($line)) { |
$info = ' ('.basename($file).", line $line)"; |
} else { |
$info = ''; |
} |
if (isset($tpl_line) && isset($tpl_file)) { |
$this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); |
} else { |
$this->trigger_error($error_msg . $info, $error_type); |
} |
} |
/** |
* callback function for preg_replace, to call a non-cacheable block |
* @return string |
*/ |
function _process_compiled_include_callback($match) { |
$_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; |
ob_start(); |
$_func($this); |
$_ret = ob_get_contents(); |
ob_end_clean(); |
return $_ret; |
} |
/** |
* called for included templates |
* |
* @param string $_smarty_include_tpl_file |
* @param string $_smarty_include_vars |
*/ |
// $_smarty_include_tpl_file, $_smarty_include_vars |
function _smarty_include($params) |
{ |
if ($this->debugging) { |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$debug_start_time = smarty_core_get_microtime($_params, $this); |
$this->_smarty_debug_info[] = array('type' => 'template', |
'filename' => $params['smarty_include_tpl_file'], |
'depth' => ++$this->_inclusion_depth); |
$included_tpls_idx = count($this->_smarty_debug_info) - 1; |
} |
$this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); |
// config vars are treated as local, so push a copy of the |
// current ones onto the front of the stack |
array_unshift($this->_config, $this->_config[0]); |
$_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); |
if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) |
|| $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) |
{ |
include($_smarty_compile_path); |
} |
// pop the local vars off the front of the stack |
array_shift($this->_config); |
$this->_inclusion_depth--; |
if ($this->debugging) { |
// capture time for debugging info |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; |
} |
if ($this->caching) { |
$this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; |
} |
} |
/** |
* get or set an array of cached attributes for function that is |
* not cacheable |
* @return array |
*/ |
function &_smarty_cache_attrs($cache_serial, $count) { |
$_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; |
if ($this->_cache_including) { |
/* return next set of cache_attrs */ |
$_return = current($_cache_attrs); |
next($_cache_attrs); |
return $_return; |
} else { |
/* add a reference to a new set of cache_attrs */ |
$_cache_attrs[] = array(); |
return $_cache_attrs[count($_cache_attrs)-1]; |
} |
} |
/** |
* wrapper for include() retaining $this |
* @return mixed |
*/ |
function _include($filename, $once=false, $params=null) |
{ |
if ($once) { |
return include_once($filename); |
} else { |
return include($filename); |
} |
} |
/** |
* wrapper for eval() retaining $this |
* @return mixed |
*/ |
function _eval($code, $params=null) |
{ |
return eval($code); |
} |
/** |
* Extracts the filter name from the given callback |
* |
* @param callback $function |
* @return string |
*/ |
function _get_filter_name($function) |
{ |
if (is_array($function)) { |
$_class_name = (is_object($function[0]) ? |
get_class($function[0]) : $function[0]); |
return $_class_name . '_' . $function[1]; |
} |
else { |
return $function; |
} |
} |
/**#@-*/ |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/init.php |
---|
Новый файл |
0,0 → 1,21 |
<?php |
require_once "DB.php"; |
require_once "config.inc.php"; |
require "Smarty.class.php"; |
$dsn = "mysql://".$DBuser.":".$DBpass."@".$DBhost."/".$DBname; |
$options = array( |
'debug' => 2, |
'portability' => DB_PORTABILITY_ALL, |
); |
$db =& DB::connect($dsn,$options); |
if (PEAR::isError($db)) { |
die($db->getMessage()); |
} |
$smarty = new Smarty; |
$smarty->compile_check = true; |
?> |
/tags/0.1/lib/DB.php |
---|
Новый файл |
0,0 → 1,1489 |
<?php |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
/** |
* Database independent query interface |
* |
* 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 <ssb@php.net> |
* @author Tomas V.V.Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version CVS: $Id: DB.php,v 1.88 2007/08/12 05:27:25 aharvey Exp $ |
* @link http://pear.php.net/package/DB |
*/ |
/** |
* Obtain the PEAR class so it can be extended from |
*/ |
require_once 'PEAR.php'; |
// {{{ constants |
// {{{ error codes |
/**#@+ |
* One of PEAR DB's portable error codes. |
* @see DB_common::errorCode(), DB::errorMessage() |
* |
* {@internal If you add an error code here, make sure you also add a textual |
* version of it in DB::errorMessage().}} |
*/ |
/** |
* The code returned by many methods upon success |
*/ |
define('DB_OK', 1); |
/** |
* Unkown error |
*/ |
define('DB_ERROR', -1); |
/** |
* Syntax error |
*/ |
define('DB_ERROR_SYNTAX', -2); |
/** |
* Tried to insert a duplicate value into a primary or unique index |
*/ |
define('DB_ERROR_CONSTRAINT', -3); |
/** |
* An identifier in the query refers to a non-existant object |
*/ |
define('DB_ERROR_NOT_FOUND', -4); |
/** |
* Tried to create a duplicate object |
*/ |
define('DB_ERROR_ALREADY_EXISTS', -5); |
/** |
* The current driver does not support the action you attempted |
*/ |
define('DB_ERROR_UNSUPPORTED', -6); |
/** |
* The number of parameters does not match the number of placeholders |
*/ |
define('DB_ERROR_MISMATCH', -7); |
/** |
* A literal submitted did not match the data type expected |
*/ |
define('DB_ERROR_INVALID', -8); |
/** |
* The current DBMS does not support the action you attempted |
*/ |
define('DB_ERROR_NOT_CAPABLE', -9); |
/** |
* A literal submitted was too long so the end of it was removed |
*/ |
define('DB_ERROR_TRUNCATED', -10); |
/** |
* A literal number submitted did not match the data type expected |
*/ |
define('DB_ERROR_INVALID_NUMBER', -11); |
/** |
* A literal date submitted did not match the data type expected |
*/ |
define('DB_ERROR_INVALID_DATE', -12); |
/** |
* Attempt to divide something by zero |
*/ |
define('DB_ERROR_DIVZERO', -13); |
/** |
* A database needs to be selected |
*/ |
define('DB_ERROR_NODBSELECTED', -14); |
/** |
* Could not create the object requested |
*/ |
define('DB_ERROR_CANNOT_CREATE', -15); |
/** |
* Could not drop the database requested because it does not exist |
*/ |
define('DB_ERROR_CANNOT_DROP', -17); |
/** |
* An identifier in the query refers to a non-existant table |
*/ |
define('DB_ERROR_NOSUCHTABLE', -18); |
/** |
* An identifier in the query refers to a non-existant column |
*/ |
define('DB_ERROR_NOSUCHFIELD', -19); |
/** |
* The data submitted to the method was inappropriate |
*/ |
define('DB_ERROR_NEED_MORE_DATA', -20); |
/** |
* The attempt to lock the table failed |
*/ |
define('DB_ERROR_NOT_LOCKED', -21); |
/** |
* The number of columns doesn't match the number of values |
*/ |
define('DB_ERROR_VALUE_COUNT_ON_ROW', -22); |
/** |
* The DSN submitted has problems |
*/ |
define('DB_ERROR_INVALID_DSN', -23); |
/** |
* Could not connect to the database |
*/ |
define('DB_ERROR_CONNECT_FAILED', -24); |
/** |
* The PHP extension needed for this DBMS could not be found |
*/ |
define('DB_ERROR_EXTENSION_NOT_FOUND',-25); |
/** |
* The present user has inadequate permissions to perform the task requestd |
*/ |
define('DB_ERROR_ACCESS_VIOLATION', -26); |
/** |
* The database requested does not exist |
*/ |
define('DB_ERROR_NOSUCHDB', -27); |
/** |
* Tried to insert a null value into a column that doesn't allow nulls |
*/ |
define('DB_ERROR_CONSTRAINT_NOT_NULL',-29); |
/**#@-*/ |
// }}} |
// {{{ prepared statement-related |
/**#@+ |
* Identifiers for the placeholders used in prepared statements. |
* @see DB_common::prepare() |
*/ |
/** |
* Indicates a scalar (<kbd>?</kbd>) placeholder was used |
* |
* Quote and escape the value as necessary. |
*/ |
define('DB_PARAM_SCALAR', 1); |
/** |
* Indicates an opaque (<kbd>&</kbd>) placeholder was used |
* |
* The value presented is a file name. Extract the contents of that file |
* and place them in this column. |
*/ |
define('DB_PARAM_OPAQUE', 2); |
/** |
* Indicates a misc (<kbd>!</kbd>) placeholder was used |
* |
* The value should not be quoted or escaped. |
*/ |
define('DB_PARAM_MISC', 3); |
/**#@-*/ |
// }}} |
// {{{ binary data-related |
/**#@+ |
* The different ways of returning binary data from queries. |
*/ |
/** |
* Sends the fetched data straight through to output |
*/ |
define('DB_BINMODE_PASSTHRU', 1); |
/** |
* Lets you return data as usual |
*/ |
define('DB_BINMODE_RETURN', 2); |
/** |
* Converts the data to hex format before returning it |
* |
* For example the string "123" would become "313233". |
*/ |
define('DB_BINMODE_CONVERT', 3); |
/**#@-*/ |
// }}} |
// {{{ fetch modes |
/**#@+ |
* Fetch Modes. |
* @see DB_common::setFetchMode() |
*/ |
/** |
* Indicates the current default fetch mode should be used |
* @see DB_common::$fetchmode |
*/ |
define('DB_FETCHMODE_DEFAULT', 0); |
/** |
* Column data indexed by numbers, ordered from 0 and up |
*/ |
define('DB_FETCHMODE_ORDERED', 1); |
/** |
* Column data indexed by column names |
*/ |
define('DB_FETCHMODE_ASSOC', 2); |
/** |
* Column data as object properties |
*/ |
define('DB_FETCHMODE_OBJECT', 3); |
/** |
* For multi-dimensional results, make the column name the first level |
* of the array and put the row number in the second level of the array |
* |
* This is flipped from the normal behavior, which puts the row numbers |
* in the first level of the array and the column names in the second level. |
*/ |
define('DB_FETCHMODE_FLIPPED', 4); |
/**#@-*/ |
/**#@+ |
* Old fetch modes. Left here for compatibility. |
*/ |
define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); |
define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); |
define('DB_GETMODE_FLIPPED', DB_FETCHMODE_FLIPPED); |
/**#@-*/ |
// }}} |
// {{{ tableInfo() && autoPrepare()-related |
/**#@+ |
* The type of information to return from the tableInfo() method. |
* |
* Bitwised constants, so they can be combined using <kbd>|</kbd> |
* and removed using <kbd>^</kbd>. |
* |
* @see DB_common::tableInfo() |
* |
* {@internal Since the TABLEINFO constants are bitwised, if more of them are |
* added in the future, make sure to adjust DB_TABLEINFO_FULL accordingly.}} |
*/ |
define('DB_TABLEINFO_ORDER', 1); |
define('DB_TABLEINFO_ORDERTABLE', 2); |
define('DB_TABLEINFO_FULL', 3); |
/**#@-*/ |
/**#@+ |
* The type of query to create with the automatic query building methods. |
* @see DB_common::autoPrepare(), DB_common::autoExecute() |
*/ |
define('DB_AUTOQUERY_INSERT', 1); |
define('DB_AUTOQUERY_UPDATE', 2); |
/**#@-*/ |
// }}} |
// {{{ portability modes |
/**#@+ |
* Portability Modes. |
* |
* Bitwised constants, so they can be combined using <kbd>|</kbd> |
* and removed using <kbd>^</kbd>. |
* |
* @see DB_common::setOption() |
* |
* {@internal Since the PORTABILITY constants are bitwised, if more of them are |
* added in the future, make sure to adjust DB_PORTABILITY_ALL accordingly.}} |
*/ |
/** |
* Turn off all portability features |
*/ |
define('DB_PORTABILITY_NONE', 0); |
/** |
* Convert names of tables and fields to lower case |
* when using the get*(), fetch*() and tableInfo() methods |
*/ |
define('DB_PORTABILITY_LOWERCASE', 1); |
/** |
* Right trim the data output by get*() and fetch*() |
*/ |
define('DB_PORTABILITY_RTRIM', 2); |
/** |
* Force reporting the number of rows deleted |
*/ |
define('DB_PORTABILITY_DELETE_COUNT', 4); |
/** |
* Enable hack that makes numRows() work in Oracle |
*/ |
define('DB_PORTABILITY_NUMROWS', 8); |
/** |
* Makes certain error messages in certain drivers compatible |
* with those from other DBMS's |
* |
* + mysql, mysqli: change unique/primary key constraints |
* DB_ERROR_ALREADY_EXISTS -> DB_ERROR_CONSTRAINT |
* |
* + odbc(access): MS's ODBC driver reports 'no such field' as code |
* 07001, which means 'too few parameters.' When this option is on |
* that code gets mapped to DB_ERROR_NOSUCHFIELD. |
*/ |
define('DB_PORTABILITY_ERRORS', 16); |
/** |
* Convert null values to empty strings in data output by |
* get*() and fetch*() |
*/ |
define('DB_PORTABILITY_NULL_TO_EMPTY', 32); |
/** |
* Turn on all portability features |
*/ |
define('DB_PORTABILITY_ALL', 63); |
/**#@-*/ |
// }}} |
// }}} |
// {{{ class DB |
/** |
* Database independent query interface |
* |
* The main "DB" class is simply a container class with some static |
* methods for creating DB objects as well as some utility functions |
* common to all parts of DB. |
* |
* The object model of DB is as follows (indentation means inheritance): |
* <pre> |
* DB The main DB class. This is simply a utility class |
* with some "static" methods for creating DB objects as |
* well as common utility functions for other DB classes. |
* |
* DB_common The base for each DB implementation. Provides default |
* | implementations (in OO lingo virtual methods) for |
* | the actual DB implementations as well as a bunch of |
* | query utility functions. |
* | |
* +-DB_mysql The DB implementation for MySQL. Inherits DB_common. |
* When calling DB::factory or DB::connect for MySQL |
* connections, the object returned is an instance of this |
* class. |
* </pre> |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @author Tomas V.V.Cox <cox@idecnet.com> |
* @author Daniel Convissor <danielc@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB |
{ |
// {{{ &factory() |
/** |
* Create a new DB object for the specified database type but don't |
* connect to the database |
* |
* @param string $type the database type (eg "mysql") |
* @param array $options an associative array of option names and values |
* |
* @return object a new DB object. A DB_Error object on failure. |
* |
* @see DB_common::setOption() |
*/ |
function &factory($type, $options = false) |
{ |
if (!is_array($options)) { |
$options = array('persistent' => $options); |
} |
if (isset($options['debug']) && $options['debug'] >= 2) { |
// expose php errors with sufficient debug level |
include_once "DB/{$type}.php"; |
} else { |
@include_once "DB/{$type}.php"; |
} |
$classname = "DB_${type}"; |
if (!class_exists($classname)) { |
$tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, |
"Unable to include the DB/{$type}.php" |
. " file for '$dsn'", |
'DB_Error', true); |
return $tmp; |
} |
@$obj = new $classname; |
foreach ($options as $option => $value) { |
$test = $obj->setOption($option, $value); |
if (DB::isError($test)) { |
return $test; |
} |
} |
return $obj; |
} |
// }}} |
// {{{ &connect() |
/** |
* Create a new DB object including a connection to the specified database |
* |
* Example 1. |
* <code> |
* require_once 'DB.php'; |
* |
* $dsn = 'pgsql://user:password@host/database'; |
* $options = array( |
* 'debug' => 2, |
* 'portability' => DB_PORTABILITY_ALL, |
* ); |
* |
* $db =& DB::connect($dsn, $options); |
* if (PEAR::isError($db)) { |
* die($db->getMessage()); |
* } |
* </code> |
* |
* @param mixed $dsn the string "data source name" or array in the |
* format returned by DB::parseDSN() |
* @param array $options an associative array of option names and values |
* |
* @return object a new DB object. A DB_Error object on failure. |
* |
* @uses DB_dbase::connect(), DB_fbsql::connect(), DB_ibase::connect(), |
* DB_ifx::connect(), DB_msql::connect(), DB_mssql::connect(), |
* DB_mysql::connect(), DB_mysqli::connect(), DB_oci8::connect(), |
* DB_odbc::connect(), DB_pgsql::connect(), DB_sqlite::connect(), |
* DB_sybase::connect() |
* |
* @uses DB::parseDSN(), DB_common::setOption(), PEAR::isError() |
*/ |
function &connect($dsn, $options = array()) |
{ |
$dsninfo = DB::parseDSN($dsn); |
$type = $dsninfo['phptype']; |
if (!is_array($options)) { |
/* |
* For backwards compatibility. $options used to be boolean, |
* indicating whether the connection should be persistent. |
*/ |
$options = array('persistent' => $options); |
} |
if (isset($options['debug']) && $options['debug'] >= 2) { |
// expose php errors with sufficient debug level |
include_once "DB/${type}.php"; |
} else { |
@include_once "DB/${type}.php"; |
} |
$classname = "DB_${type}"; |
if (!class_exists($classname)) { |
$tmp = PEAR::raiseError(null, DB_ERROR_NOT_FOUND, null, null, |
"Unable to include the DB/{$type}.php" |
. " file for '$dsn'", |
'DB_Error', true); |
return $tmp; |
} |
@$obj = new $classname; |
foreach ($options as $option => $value) { |
$test = $obj->setOption($option, $value); |
if (DB::isError($test)) { |
return $test; |
} |
} |
$err = $obj->connect($dsninfo, $obj->getOption('persistent')); |
if (DB::isError($err)) { |
if (is_array($dsn)) { |
$err->addUserInfo(DB::getDSNString($dsn, true)); |
} else { |
$err->addUserInfo($dsn); |
} |
return $err; |
} |
return $obj; |
} |
// }}} |
// {{{ apiVersion() |
/** |
* Return the DB API version |
* |
* @return string the DB API version number |
*/ |
function apiVersion() |
{ |
return '1.7.13'; |
} |
// }}} |
// {{{ isError() |
/** |
* Determines if a variable is a DB_Error object |
* |
* @param mixed $value the variable to check |
* |
* @return bool whether $value is DB_Error object |
*/ |
function isError($value) |
{ |
return is_a($value, 'DB_Error'); |
} |
// }}} |
// {{{ isConnection() |
/** |
* Determines if a value is a DB_<driver> object |
* |
* @param mixed $value the value to test |
* |
* @return bool whether $value is a DB_<driver> object |
*/ |
function isConnection($value) |
{ |
return (is_object($value) && |
is_subclass_of($value, 'db_common') && |
method_exists($value, 'simpleQuery')); |
} |
// }}} |
// {{{ isManip() |
/** |
* Tell whether a query is a data manipulation or data definition query |
* |
* Examples of data manipulation queries are INSERT, UPDATE and DELETE. |
* Examples of data definition queries are CREATE, DROP, ALTER, GRANT, |
* REVOKE. |
* |
* @param string $query the query |
* |
* @return boolean whether $query is a data manipulation query |
*/ |
function isManip($query) |
{ |
$manips = 'INSERT|UPDATE|DELETE|REPLACE|' |
. 'CREATE|DROP|' |
. 'LOAD DATA|SELECT .* INTO .* FROM|COPY|' |
. 'ALTER|GRANT|REVOKE|' |
. 'LOCK|UNLOCK'; |
if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) { |
return true; |
} |
return false; |
} |
// }}} |
// {{{ errorMessage() |
/** |
* Return a textual error message for a DB error code |
* |
* @param integer $value the DB error code |
* |
* @return string the error message or false if the error code was |
* not recognized |
*/ |
function errorMessage($value) |
{ |
static $errorMessages; |
if (!isset($errorMessages)) { |
$errorMessages = array( |
DB_ERROR => 'unknown error', |
DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions', |
DB_ERROR_ALREADY_EXISTS => 'already exists', |
DB_ERROR_CANNOT_CREATE => 'can not create', |
DB_ERROR_CANNOT_DROP => 'can not drop', |
DB_ERROR_CONNECT_FAILED => 'connect failed', |
DB_ERROR_CONSTRAINT => 'constraint violation', |
DB_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', |
DB_ERROR_DIVZERO => 'division by zero', |
DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', |
DB_ERROR_INVALID => 'invalid', |
DB_ERROR_INVALID_DATE => 'invalid date or time', |
DB_ERROR_INVALID_DSN => 'invalid DSN', |
DB_ERROR_INVALID_NUMBER => 'invalid number', |
DB_ERROR_MISMATCH => 'mismatch', |
DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', |
DB_ERROR_NODBSELECTED => 'no database selected', |
DB_ERROR_NOSUCHDB => 'no such database', |
DB_ERROR_NOSUCHFIELD => 'no such field', |
DB_ERROR_NOSUCHTABLE => 'no such table', |
DB_ERROR_NOT_CAPABLE => 'DB backend not capable', |
DB_ERROR_NOT_FOUND => 'not found', |
DB_ERROR_NOT_LOCKED => 'not locked', |
DB_ERROR_SYNTAX => 'syntax error', |
DB_ERROR_UNSUPPORTED => 'not supported', |
DB_ERROR_TRUNCATED => 'truncated', |
DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', |
DB_OK => 'no error', |
); |
} |
if (DB::isError($value)) { |
$value = $value->getCode(); |
} |
return isset($errorMessages[$value]) ? $errorMessages[$value] |
: $errorMessages[DB_ERROR]; |
} |
// }}} |
// {{{ parseDSN() |
/** |
* Parse a data source name |
* |
* Additional keys can be added by appending a URI query string to the |
* end of the DSN. |
* |
* The format of the supplied DSN is in its fullest form: |
* <code> |
* phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true |
* </code> |
* |
* Most variations are allowed: |
* <code> |
* phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 |
* phptype://username:password@hostspec/database_name |
* phptype://username:password@hostspec |
* phptype://username@hostspec |
* phptype://hostspec/database |
* phptype://hostspec |
* phptype(dbsyntax) |
* phptype |
* </code> |
* |
* @param string $dsn Data Source Name to be parsed |
* |
* @return array an associative array with the following keys: |
* + phptype: Database backend used in PHP (mysql, odbc etc.) |
* + dbsyntax: Database used with regards to SQL syntax etc. |
* + protocol: Communication protocol to use (tcp, unix etc.) |
* + hostspec: Host specification (hostname[:port]) |
* + database: Database to use on the DBMS server |
* + username: User name for login |
* + password: Password for login |
*/ |
function parseDSN($dsn) |
{ |
$parsed = array( |
'phptype' => false, |
'dbsyntax' => false, |
'username' => false, |
'password' => false, |
'protocol' => false, |
'hostspec' => false, |
'port' => false, |
'socket' => false, |
'database' => false, |
); |
if (is_array($dsn)) { |
$dsn = array_merge($parsed, $dsn); |
if (!$dsn['dbsyntax']) { |
$dsn['dbsyntax'] = $dsn['phptype']; |
} |
return $dsn; |
} |
// Find phptype and dbsyntax |
if (($pos = strpos($dsn, '://')) !== false) { |
$str = substr($dsn, 0, $pos); |
$dsn = substr($dsn, $pos + 3); |
} else { |
$str = $dsn; |
$dsn = null; |
} |
// Get phptype and dbsyntax |
// $str => phptype(dbsyntax) |
if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { |
$parsed['phptype'] = $arr[1]; |
$parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; |
} else { |
$parsed['phptype'] = $str; |
$parsed['dbsyntax'] = $str; |
} |
if (!count($dsn)) { |
return $parsed; |
} |
// Get (if found): username and password |
// $dsn => username:password@protocol+hostspec/database |
if (($at = strrpos($dsn,'@')) !== false) { |
$str = substr($dsn, 0, $at); |
$dsn = substr($dsn, $at + 1); |
if (($pos = strpos($str, ':')) !== false) { |
$parsed['username'] = rawurldecode(substr($str, 0, $pos)); |
$parsed['password'] = rawurldecode(substr($str, $pos + 1)); |
} else { |
$parsed['username'] = rawurldecode($str); |
} |
} |
// Find protocol and hostspec |
if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { |
// $dsn => proto(proto_opts)/database |
$proto = $match[1]; |
$proto_opts = $match[2] ? $match[2] : false; |
$dsn = $match[3]; |
} else { |
// $dsn => protocol+hostspec/database (old format) |
if (strpos($dsn, '+') !== false) { |
list($proto, $dsn) = explode('+', $dsn, 2); |
} |
if (strpos($dsn, '/') !== false) { |
list($proto_opts, $dsn) = explode('/', $dsn, 2); |
} else { |
$proto_opts = $dsn; |
$dsn = null; |
} |
} |
// process the different protocol options |
$parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; |
$proto_opts = rawurldecode($proto_opts); |
if (strpos($proto_opts, ':') !== false) { |
list($proto_opts, $parsed['port']) = explode(':', $proto_opts); |
} |
if ($parsed['protocol'] == 'tcp') { |
$parsed['hostspec'] = $proto_opts; |
} elseif ($parsed['protocol'] == 'unix') { |
$parsed['socket'] = $proto_opts; |
} |
// Get dabase if any |
// $dsn => database |
if ($dsn) { |
if (($pos = strpos($dsn, '?')) === false) { |
// /database |
$parsed['database'] = rawurldecode($dsn); |
} else { |
// /database?param1=value1¶m2=value2 |
$parsed['database'] = rawurldecode(substr($dsn, 0, $pos)); |
$dsn = substr($dsn, $pos + 1); |
if (strpos($dsn, '&') !== false) { |
$opts = explode('&', $dsn); |
} else { // database?param1=value1 |
$opts = array($dsn); |
} |
foreach ($opts as $opt) { |
list($key, $value) = explode('=', $opt); |
if (!isset($parsed[$key])) { |
// don't allow params overwrite |
$parsed[$key] = rawurldecode($value); |
} |
} |
} |
} |
return $parsed; |
} |
// }}} |
// {{{ getDSNString() |
/** |
* Returns the given DSN in a string format suitable for output. |
* |
* @param array|string the DSN to parse and format |
* @param boolean true to hide the password, false to include it |
* @return string |
*/ |
function getDSNString($dsn, $hidePassword) { |
/* Calling parseDSN will ensure that we have all the array elements |
* defined, and means that we deal with strings and array in the same |
* manner. */ |
$dsnArray = DB::parseDSN($dsn); |
if ($hidePassword) { |
$dsnArray['password'] = 'PASSWORD'; |
} |
/* Protocol is special-cased, as using the default "tcp" along with an |
* Oracle TNS connection string fails. */ |
if (is_string($dsn) && strpos($dsn, 'tcp') === false && $dsnArray['protocol'] == 'tcp') { |
$dsnArray['protocol'] = false; |
} |
// Now we just have to construct the actual string. This is ugly. |
$dsnString = $dsnArray['phptype']; |
if ($dsnArray['dbsyntax']) { |
$dsnString .= '('.$dsnArray['dbsyntax'].')'; |
} |
$dsnString .= '://' |
.$dsnArray['username'] |
.':' |
.$dsnArray['password'] |
.'@' |
.$dsnArray['protocol']; |
if ($dsnArray['socket']) { |
$dsnString .= '('.$dsnArray['socket'].')'; |
} |
if ($dsnArray['protocol'] && $dsnArray['hostspec']) { |
$dsnString .= '+'; |
} |
$dsnString .= $dsnArray['hostspec']; |
if ($dsnArray['port']) { |
$dsnString .= ':'.$dsnArray['port']; |
} |
$dsnString .= '/'.$dsnArray['database']; |
/* Option handling. Unfortunately, parseDSN simply places options into |
* the top-level array, so we'll first get rid of the fields defined by |
* DB and see what's left. */ |
unset($dsnArray['phptype'], |
$dsnArray['dbsyntax'], |
$dsnArray['username'], |
$dsnArray['password'], |
$dsnArray['protocol'], |
$dsnArray['socket'], |
$dsnArray['hostspec'], |
$dsnArray['port'], |
$dsnArray['database'] |
); |
if (count($dsnArray) > 0) { |
$dsnString .= '?'; |
$i = 0; |
foreach ($dsnArray as $key => $value) { |
if (++$i > 1) { |
$dsnString .= '&'; |
} |
$dsnString .= $key.'='.$value; |
} |
} |
return $dsnString; |
} |
// }}} |
} |
// }}} |
// {{{ class DB_Error |
/** |
* DB_Error implements a class for reporting portable database error |
* messages |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_Error extends PEAR_Error |
{ |
// {{{ constructor |
/** |
* DB_Error constructor |
* |
* @param mixed $code DB error code, or string with error message |
* @param int $mode what "error mode" to operate in |
* @param int $level what error level to use for $mode & |
* PEAR_ERROR_TRIGGER |
* @param mixed $debuginfo additional debug info, such as the last query |
* |
* @see PEAR_Error |
*/ |
function DB_Error($code = DB_ERROR, $mode = PEAR_ERROR_RETURN, |
$level = E_USER_NOTICE, $debuginfo = null) |
{ |
if (is_int($code)) { |
$this->PEAR_Error('DB Error: ' . DB::errorMessage($code), $code, |
$mode, $level, $debuginfo); |
} else { |
$this->PEAR_Error("DB Error: $code", DB_ERROR, |
$mode, $level, $debuginfo); |
} |
} |
// }}} |
} |
// }}} |
// {{{ class DB_result |
/** |
* This class implements a wrapper for a DB result set |
* |
* A new instance of this class will be returned by the DB implementation |
* after processing a query that returns data. |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
*/ |
class DB_result |
{ |
// {{{ properties |
/** |
* Should results be freed automatically when there are no more rows? |
* @var boolean |
* @see DB_common::$options |
*/ |
var $autofree; |
/** |
* A reference to the DB_<driver> object |
* @var object |
*/ |
var $dbh; |
/** |
* The current default fetch mode |
* @var integer |
* @see DB_common::$fetchmode |
*/ |
var $fetchmode; |
/** |
* The name of the class into which results should be fetched when |
* DB_FETCHMODE_OBJECT is in effect |
* |
* @var string |
* @see DB_common::$fetchmode_object_class |
*/ |
var $fetchmode_object_class; |
/** |
* The number of rows to fetch from a limit query |
* @var integer |
*/ |
var $limit_count = null; |
/** |
* The row to start fetching from in limit queries |
* @var integer |
*/ |
var $limit_from = null; |
/** |
* The execute parameters that created this result |
* @var array |
* @since Property available since Release 1.7.0 |
*/ |
var $parameters; |
/** |
* The query string that created this result |
* |
* Copied here incase it changes in $dbh, which is referenced |
* |
* @var string |
* @since Property available since Release 1.7.0 |
*/ |
var $query; |
/** |
* The query result resource id created by PHP |
* @var resource |
*/ |
var $result; |
/** |
* The present row being dealt with |
* @var integer |
*/ |
var $row_counter = null; |
/** |
* The prepared statement resource id created by PHP in $dbh |
* |
* This resource is only available when the result set was created using |
* a driver's native execute() method, not PEAR DB's emulated one. |
* |
* Copied here incase it changes in $dbh, which is referenced |
* |
* {@internal Mainly here because the InterBase/Firebird API is only |
* able to retrieve data from result sets if the statemnt handle is |
* still in scope.}} |
* |
* @var resource |
* @since Property available since Release 1.7.0 |
*/ |
var $statement; |
// }}} |
// {{{ constructor |
/** |
* This constructor sets the object's properties |
* |
* @param object &$dbh the DB object reference |
* @param resource $result the result resource id |
* @param array $options an associative array with result options |
* |
* @return void |
*/ |
function DB_result(&$dbh, $result, $options = array()) |
{ |
$this->autofree = $dbh->options['autofree']; |
$this->dbh = &$dbh; |
$this->fetchmode = $dbh->fetchmode; |
$this->fetchmode_object_class = $dbh->fetchmode_object_class; |
$this->parameters = $dbh->last_parameters; |
$this->query = $dbh->last_query; |
$this->result = $result; |
$this->statement = empty($dbh->last_stmt) ? null : $dbh->last_stmt; |
foreach ($options as $key => $value) { |
$this->setOption($key, $value); |
} |
} |
/** |
* Set options for the DB_result object |
* |
* @param string $key the option to set |
* @param mixed $value the value to set the option to |
* |
* @return void |
*/ |
function setOption($key, $value = null) |
{ |
switch ($key) { |
case 'limit_from': |
$this->limit_from = $value; |
break; |
case 'limit_count': |
$this->limit_count = $value; |
} |
} |
// }}} |
// {{{ fetchRow() |
/** |
* Fetch a row of data and return it by reference into an array |
* |
* The type of array returned can be controlled either by setting this |
* method's <var>$fetchmode</var> parameter or by changing the default |
* fetch mode setFetchMode() before calling this method. |
* |
* There are two options for standardizing the information returned |
* from databases, ensuring their values are consistent when changing |
* DBMS's. These portability options can be turned on when creating a |
* new DB object or by using setOption(). |
* |
* + <var>DB_PORTABILITY_LOWERCASE</var> |
* convert names of fields to lower case |
* |
* + <var>DB_PORTABILITY_RTRIM</var> |
* right trim the data |
* |
* @param int $fetchmode the constant indicating how to format the data |
* @param int $rownum the row number to fetch (index starts at 0) |
* |
* @return mixed an array or object containing the row's data, |
* NULL when the end of the result set is reached |
* or a DB_Error object on failure. |
* |
* @see DB_common::setOption(), DB_common::setFetchMode() |
*/ |
function &fetchRow($fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) |
{ |
if ($fetchmode === DB_FETCHMODE_DEFAULT) { |
$fetchmode = $this->fetchmode; |
} |
if ($fetchmode === DB_FETCHMODE_OBJECT) { |
$fetchmode = DB_FETCHMODE_ASSOC; |
$object_class = $this->fetchmode_object_class; |
} |
if (is_null($rownum) && $this->limit_from !== null) { |
if ($this->row_counter === null) { |
$this->row_counter = $this->limit_from; |
// Skip rows |
if ($this->dbh->features['limit'] === false) { |
$i = 0; |
while ($i++ < $this->limit_from) { |
$this->dbh->fetchInto($this->result, $arr, $fetchmode); |
} |
} |
} |
if ($this->row_counter >= ($this->limit_from + $this->limit_count)) |
{ |
if ($this->autofree) { |
$this->free(); |
} |
$tmp = null; |
return $tmp; |
} |
if ($this->dbh->features['limit'] === 'emulate') { |
$rownum = $this->row_counter; |
} |
$this->row_counter++; |
} |
$res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); |
if ($res === DB_OK) { |
if (isset($object_class)) { |
// The default mode is specified in the |
// DB_common::fetchmode_object_class property |
if ($object_class == 'stdClass') { |
$arr = (object) $arr; |
} else { |
$arr = new $object_class($arr); |
} |
} |
return $arr; |
} |
if ($res == null && $this->autofree) { |
$this->free(); |
} |
return $res; |
} |
// }}} |
// {{{ fetchInto() |
/** |
* Fetch a row of data into an array which is passed by reference |
* |
* The type of array returned can be controlled either by setting this |
* method's <var>$fetchmode</var> parameter or by changing the default |
* fetch mode setFetchMode() before calling this method. |
* |
* There are two options for standardizing the information returned |
* from databases, ensuring their values are consistent when changing |
* DBMS's. These portability options can be turned on when creating a |
* new DB object or by using setOption(). |
* |
* + <var>DB_PORTABILITY_LOWERCASE</var> |
* convert names of fields to lower case |
* |
* + <var>DB_PORTABILITY_RTRIM</var> |
* right trim the data |
* |
* @param array &$arr the variable where the data should be placed |
* @param int $fetchmode the constant indicating how to format the data |
* @param int $rownum the row number to fetch (index starts at 0) |
* |
* @return mixed DB_OK if a row is processed, NULL when the end of the |
* result set is reached or a DB_Error object on failure |
* |
* @see DB_common::setOption(), DB_common::setFetchMode() |
*/ |
function fetchInto(&$arr, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum = null) |
{ |
if ($fetchmode === DB_FETCHMODE_DEFAULT) { |
$fetchmode = $this->fetchmode; |
} |
if ($fetchmode === DB_FETCHMODE_OBJECT) { |
$fetchmode = DB_FETCHMODE_ASSOC; |
$object_class = $this->fetchmode_object_class; |
} |
if (is_null($rownum) && $this->limit_from !== null) { |
if ($this->row_counter === null) { |
$this->row_counter = $this->limit_from; |
// Skip rows |
if ($this->dbh->features['limit'] === false) { |
$i = 0; |
while ($i++ < $this->limit_from) { |
$this->dbh->fetchInto($this->result, $arr, $fetchmode); |
} |
} |
} |
if ($this->row_counter >= ( |
$this->limit_from + $this->limit_count)) |
{ |
if ($this->autofree) { |
$this->free(); |
} |
return null; |
} |
if ($this->dbh->features['limit'] === 'emulate') { |
$rownum = $this->row_counter; |
} |
$this->row_counter++; |
} |
$res = $this->dbh->fetchInto($this->result, $arr, $fetchmode, $rownum); |
if ($res === DB_OK) { |
if (isset($object_class)) { |
// default mode specified in the |
// DB_common::fetchmode_object_class property |
if ($object_class == 'stdClass') { |
$arr = (object) $arr; |
} else { |
$arr = new $object_class($arr); |
} |
} |
return DB_OK; |
} |
if ($res == null && $this->autofree) { |
$this->free(); |
} |
return $res; |
} |
// }}} |
// {{{ numCols() |
/** |
* Get the the number of columns in a result set |
* |
* @return int the number of columns. A DB_Error object on failure. |
*/ |
function numCols() |
{ |
return $this->dbh->numCols($this->result); |
} |
// }}} |
// {{{ numRows() |
/** |
* Get the number of rows in a result set |
* |
* @return int the number of rows. A DB_Error object on failure. |
*/ |
function numRows() |
{ |
if ($this->dbh->features['numrows'] === 'emulate' |
&& $this->dbh->options['portability'] & DB_PORTABILITY_NUMROWS) |
{ |
if ($this->dbh->features['prepare']) { |
$res = $this->dbh->query($this->query, $this->parameters); |
} else { |
$res = $this->dbh->query($this->query); |
} |
if (DB::isError($res)) { |
return $res; |
} |
$i = 0; |
while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) { |
$i++; |
} |
$count = $i; |
} else { |
$count = $this->dbh->numRows($this->result); |
} |
/* fbsql is checked for here because limit queries are implemented |
* using a TOP() function, which results in fbsql_num_rows still |
* returning the total number of rows that would have been returned, |
* rather than the real number. As a result, we'll just do the limit |
* calculations for fbsql in the same way as a database with emulated |
* limits. Unfortunately, we can't just do this in DB_fbsql::numRows() |
* because that only gets the result resource, rather than the full |
* DB_Result object. */ |
if (($this->dbh->features['limit'] === 'emulate' |
&& $this->limit_from !== null) |
|| $this->dbh->phptype == 'fbsql') { |
$limit_count = is_null($this->limit_count) ? $count : $this->limit_count; |
if ($count < $this->limit_from) { |
$count = 0; |
} elseif ($count < ($this->limit_from + $limit_count)) { |
$count -= $this->limit_from; |
} else { |
$count = $limit_count; |
} |
} |
return $count; |
} |
// }}} |
// {{{ nextResult() |
/** |
* Get the next result if a batch of queries was executed |
* |
* @return bool true if a new result is available or false if not |
*/ |
function nextResult() |
{ |
return $this->dbh->nextResult($this->result); |
} |
// }}} |
// {{{ free() |
/** |
* Frees the resources allocated for this result set |
* |
* @return bool true on success. A DB_Error object on failure. |
*/ |
function free() |
{ |
$err = $this->dbh->freeResult($this->result); |
if (DB::isError($err)) { |
return $err; |
} |
$this->result = false; |
$this->statement = false; |
return true; |
} |
// }}} |
// {{{ tableInfo() |
/** |
* @see DB_common::tableInfo() |
* @deprecated Method deprecated some time before Release 1.2 |
*/ |
function tableInfo($mode = null) |
{ |
if (is_string($mode)) { |
return $this->dbh->raiseError(DB_ERROR_NEED_MORE_DATA); |
} |
return $this->dbh->tableInfo($this, $mode); |
} |
// }}} |
// {{{ getQuery() |
/** |
* Determine the query string that created this result |
* |
* @return string the query string |
* |
* @since Method available since Release 1.7.0 |
*/ |
function getQuery() |
{ |
return $this->query; |
} |
// }}} |
// {{{ getRowCounter() |
/** |
* Tells which row number is currently being processed |
* |
* @return integer the current row being looked at. Starts at 1. |
*/ |
function getRowCounter() |
{ |
return $this->row_counter; |
} |
// }}} |
} |
// }}} |
// {{{ class DB_row |
/** |
* PEAR DB Row Object |
* |
* The object contains a row of data from a result set. Each column's data |
* is placed in a property named for the column. |
* |
* @category Database |
* @package DB |
* @author Stig Bakken <ssb@php.net> |
* @copyright 1997-2007 The PHP Group |
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
* @version Release: 1.7.13 |
* @link http://pear.php.net/package/DB |
* @see DB_common::setFetchMode() |
*/ |
class DB_row |
{ |
// {{{ constructor |
/** |
* The constructor places a row's data into properties of this object |
* |
* @param array the array containing the row's data |
* |
* @return void |
*/ |
function DB_row(&$arr) |
{ |
foreach ($arr as $key => $value) { |
$this->$key = &$arr[$key]; |
} |
} |
// }}} |
} |
// }}} |
/* |
* Local variables: |
* tab-width: 4 |
* c-basic-offset: 4 |
* End: |
*/ |
?> |
/tags/0.1/lib/Config_File.class.php |
---|
Новый файл |
0,0 → 1,393 |
<?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 |
* |
* For questions, help, comments, discussion, etc., please join the |
* Smarty mailing list. Send a blank e-mail to |
* smarty-discussion-subscribe@googlegroups.com |
* |
* @link http://www.smarty.net/ |
* @version 2.6.22 |
* @copyright Copyright: 2001-2005 New Digital Group, Inc. |
* @author Andrei Zmievski <andrei@php.net> |
* @access public |
* @package Smarty |
*/ |
/* $Id: Config_File.class.php 2786 2008-09-18 21:04:38Z Uwe.Tews $ */ |
/** |
* 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); |
} |
/**#@-*/ |
} |
?> |
/tags/0.1/lib/internals/core.process_cached_inserts.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.write_cache_file.php |
---|
Новый файл |
0,0 → 1,96 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Prepend the cache information to the cache file |
* and write it |
* |
* @param string $tpl_file |
* @param string $cache_id |
* @param string $compile_id |
* @param string $results |
* @return true|null |
*/ |
// $tpl_file, $cache_id, $compile_id, $results |
function smarty_core_write_cache_file($params, &$smarty) |
{ |
// put timestamp in cache header |
$smarty->_cache_info['timestamp'] = time(); |
if ($smarty->cache_lifetime > -1){ |
// expiration set |
$smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime; |
} else { |
// cache will never expire |
$smarty->_cache_info['expires'] = -1; |
} |
// collapse nocache.../nocache-tags |
if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) { |
// remove everything between every pair of outermost noache.../nocache-tags |
// and replace it by a single nocache-tag |
// this new nocache-tag will be replaced by dynamic contents in |
// smarty_core_process_compiled_includes() on a cache-read |
$match_count = count($match[0]); |
$results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE); |
$level = 0; |
$j = 0; |
for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) { |
if ($results[$i] == $match[0][$j]) { |
// nocache tag |
if ($match[1][$j]) { // closing tag |
$level--; |
unset($results[$i]); |
} else { // opening tag |
if ($level++ > 0) unset($results[$i]); |
} |
$j++; |
} elseif ($level > 0) { |
unset($results[$i]); |
} |
} |
$params['results'] = implode('', $results); |
} |
$smarty->_cache_info['cache_serials'] = $smarty->_cache_serials; |
// prepend the cache header info into cache file |
$_cache_info = serialize($smarty->_cache_info); |
$params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results']; |
if (!empty($smarty->cache_handler_func)) { |
// use cache_handler function |
call_user_func_array($smarty->cache_handler_func, |
array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], $smarty->_cache_info['expires'])); |
} else { |
// use local cache file |
if(!@is_writable($smarty->cache_dir)) { |
// cache_dir not writable, see if it exists |
if(!@is_dir($smarty->cache_dir)) { |
$smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); |
return false; |
} |
$smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR); |
return false; |
} |
$_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 = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true); |
require_once(SMARTY_CORE_DIR . 'core.write_file.php'); |
smarty_core_write_file($_params, $smarty); |
return true; |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.rmdir.php |
---|
Новый файл |
0,0 → 1,54 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* delete a dir recursively (level=0 -> keep root) |
* WARNING: no tests, it will try to remove what you tell it! |
* |
* @param string $dirname |
* @param integer $level |
* @param integer $exp_time |
* @return boolean |
*/ |
// $dirname, $level = 1, $exp_time = null |
function smarty_core_rmdir($params, &$smarty) |
{ |
if(!isset($params['level'])) { $params['level'] = 1; } |
if(!isset($params['exp_time'])) { $params['exp_time'] = null; } |
if($_handle = @opendir($params['dirname'])) { |
while (false !== ($_entry = readdir($_handle))) { |
if ($_entry != '.' && $_entry != '..') { |
if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) { |
$_params = array( |
'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry, |
'level' => $params['level'] + 1, |
'exp_time' => $params['exp_time'] |
); |
smarty_core_rmdir($_params, $smarty); |
} |
else { |
$smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']); |
} |
} |
} |
closedir($_handle); |
} |
if ($params['level']) { |
return @rmdir($params['dirname']); |
} |
return (bool)$_handle; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.write_compiled_resource.php |
---|
Новый файл |
0,0 → 1,35 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* write the compiled resource |
* |
* @param string $compile_path |
* @param string $compiled_content |
* @return true |
*/ |
function smarty_core_write_compiled_resource($params, &$smarty) |
{ |
if(!@is_writable($smarty->compile_dir)) { |
// compile_dir not writable, see if it exists |
if(!@is_dir($smarty->compile_dir)) { |
$smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); |
return false; |
} |
$smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR); |
return false; |
} |
$_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true); |
require_once(SMARTY_CORE_DIR . 'core.write_file.php'); |
smarty_core_write_file($_params, $smarty); |
return true; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.load_plugins.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.is_secure.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.create_dir_structure.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.run_insert_handler.php |
---|
Новый файл |
0,0 → 1,71 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Handle insert tags |
* |
* @param array $args |
* @return string |
*/ |
function smarty_core_run_insert_handler($params, &$smarty) |
{ |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
if ($smarty->debugging) { |
$_params = array(); |
$_debug_start_time = smarty_core_get_microtime($_params, $smarty); |
} |
if ($smarty->caching) { |
$_arg_string = serialize($params['args']); |
$_name = $params['args']['name']; |
if (!isset($smarty->_cache_info['insert_tags'][$_name])) { |
$smarty->_cache_info['insert_tags'][$_name] = array('insert', |
$_name, |
$smarty->_plugins['insert'][$_name][1], |
$smarty->_plugins['insert'][$_name][2], |
!empty($params['args']['script']) ? true : false); |
} |
return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5; |
} else { |
if (isset($params['args']['script'])) { |
$_params = array('resource_name' => $smarty->_dequote($params['args']['script'])); |
require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); |
if(!smarty_core_get_php_resource($_params, $smarty)) { |
return false; |
} |
if ($_params['resource_type'] == 'file') { |
$smarty->_include($_params['php_resource'], true); |
} else { |
$smarty->_eval($_params['php_resource']); |
} |
unset($params['args']['script']); |
} |
$_funcname = $smarty->_plugins['insert'][$params['args']['name']][0]; |
$_content = $_funcname($params['args'], $smarty); |
if ($smarty->debugging) { |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$smarty->_smarty_debug_info[] = array('type' => 'insert', |
'filename' => 'insert_'.$params['args']['name'], |
'depth' => $smarty->_inclusion_depth, |
'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); |
} |
if (!empty($params['args']["assign"])) { |
$smarty->assign($params['args']["assign"], $_content); |
} else { |
return $_content; |
} |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.assemble_plugin_filepath.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.is_trusted.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.get_microtime.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.write_file.php |
---|
Новый файл |
0,0 → 1,54 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* write out a file to disk |
* |
* @param string $filename |
* @param string $contents |
* @param boolean $create_dirs |
* @return boolean |
*/ |
function smarty_core_write_file($params, &$smarty) |
{ |
$_dirname = dirname($params['filename']); |
if ($params['create_dirs']) { |
$_params = array('dir' => $_dirname); |
require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php'); |
smarty_core_create_dir_structure($_params, $smarty); |
} |
// write to tmp file, then rename it to avoid file locking race condition |
$_tmp_file = tempnam($_dirname, 'wrt'); |
if (!($fd = @fopen($_tmp_file, 'wb'))) { |
$_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt'); |
if (!($fd = @fopen($_tmp_file, 'wb'))) { |
$smarty->trigger_error("problem writing temporary file '$_tmp_file'"); |
return false; |
} |
} |
fwrite($fd, $params['contents']); |
fclose($fd); |
if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) { |
// On platforms and filesystems that cannot overwrite with rename() |
// delete the file before renaming it -- because windows always suffers |
// this, it is short-circuited to avoid the initial rename() attempt |
@unlink($params['filename']); |
@rename($_tmp_file, $params['filename']); |
} |
@chmod($params['filename'], $smarty->_file_perms); |
return true; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.smarty_include_php.php |
---|
Новый файл |
0,0 → 1,50 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* called for included php files within templates |
* |
* @param string $smarty_file |
* @param string $smarty_assign variable to assign the included template's |
* output into |
* @param boolean $smarty_once uses include_once if this is true |
* @param array $smarty_include_vars associative array of vars from |
* {include file="blah" var=$var} |
*/ |
// $file, $assign, $once, $_smarty_include_vars |
function smarty_core_smarty_include_php($params, &$smarty) |
{ |
$_params = array('resource_name' => $params['smarty_file']); |
require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); |
smarty_core_get_php_resource($_params, $smarty); |
$_smarty_resource_type = $_params['resource_type']; |
$_smarty_php_resource = $_params['php_resource']; |
if (!empty($params['smarty_assign'])) { |
ob_start(); |
if ($_smarty_resource_type == 'file') { |
$smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); |
} else { |
$smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); |
} |
$smarty->assign($params['smarty_assign'], ob_get_contents()); |
ob_end_clean(); |
} else { |
if ($_smarty_resource_type == 'file') { |
$smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); |
} else { |
$smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); |
} |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.display_debug_console.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.get_php_resource.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.process_compiled_include.php |
---|
Новый файл |
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_info['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; |
} |
?> |
/tags/0.1/lib/internals/core.read_cache_file.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.get_include_path.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.assign_smarty_interface.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.load_resource_plugin.php |
---|
Новый файл |
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: */ |
?> |
/tags/0.1/lib/internals/core.rm_auto.php |
---|
Новый файл |
0,0 → 1,71 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* delete an automagically created file by name and id |
* |
* @param string $auto_base |
* @param string $auto_source |
* @param string $auto_id |
* @param integer $exp_time |
* @return boolean |
*/ |
// $auto_base, $auto_source = null, $auto_id = null, $exp_time = null |
function smarty_core_rm_auto($params, &$smarty) |
{ |
if (!@is_dir($params['auto_base'])) |
return false; |
if(!isset($params['auto_id']) && !isset($params['auto_source'])) { |
$_params = array( |
'dirname' => $params['auto_base'], |
'level' => 0, |
'exp_time' => $params['exp_time'] |
); |
require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); |
$_res = smarty_core_rmdir($_params, $smarty); |
} else { |
$_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']); |
if(isset($params['auto_source'])) { |
if (isset($params['extensions'])) { |
$_res = false; |
foreach ((array)$params['extensions'] as $_extension) |
$_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']); |
} else { |
$_res = $smarty->_unlink($_tname, $params['exp_time']); |
} |
} elseif ($smarty->use_sub_dirs) { |
$_params = array( |
'dirname' => $_tname, |
'level' => 1, |
'exp_time' => $params['exp_time'] |
); |
require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); |
$_res = smarty_core_rmdir($_params, $smarty); |
} else { |
// remove matching file names |
$_handle = opendir($params['auto_base']); |
$_res = true; |
while (false !== ($_filename = readdir($_handle))) { |
if($_filename == '.' || $_filename == '..') { |
continue; |
} elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) { |
$_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']); |
} |
} |
} |
} |
return $_res; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/internals/core.write_compiled_include.php |
---|
Новый файл |
0,0 → 1,91 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Extract non-cacheable parts out of compiled template and write it |
* |
* @param string $compile_path |
* @param string $template_compiled |
* @return boolean |
*/ |
function smarty_core_write_compiled_include($params, &$smarty) |
{ |
$_tag_start = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\'; endif;'; |
$_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{/nocache\:(\\2)#(\\3)\}\'; endif;'; |
preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', |
$params['compiled_content'], $_match_source, PREG_SET_ORDER); |
// no nocache-parts found: done |
if (count($_match_source)==0) return; |
// convert the matched php-code to functions |
$_include_compiled = "<?php /* Smarty version ".$smarty->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; |
$_include_compiled .= " compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n"; |
$_compile_path = $params['include_file_path']; |
$smarty->_cache_serials[$_compile_path] = $params['cache_serial']; |
$_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>"; |
$_include_compiled .= $params['plugins_code']; |
$_include_compiled .= "<?php"; |
$this_varname = ((double)phpversion() >= 5.0) ? '_smarty' : 'this'; |
for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) { |
$_match =& $_match_source[$_i]; |
$source = $_match[4]; |
if ($this_varname == '_smarty') { |
/* rename $this to $_smarty in the sourcecode */ |
$tokens = token_get_all('<?php ' . $_match[4]); |
/* remove trailing <?php */ |
$open_tag = ''; |
while ($tokens) { |
$token = array_shift($tokens); |
if (is_array($token)) { |
$open_tag .= $token[1]; |
} else { |
$open_tag .= $token; |
} |
if ($open_tag == '<?php ') break; |
} |
for ($i=0, $count = count($tokens); $i < $count; $i++) { |
if (is_array($tokens[$i])) { |
if ($tokens[$i][0] == T_VARIABLE && $tokens[$i][1] == '$this') { |
$tokens[$i] = '$' . $this_varname; |
} else { |
$tokens[$i] = $tokens[$i][1]; |
} |
} |
} |
$source = implode('', $tokens); |
} |
/* add function to compiled include */ |
$_include_compiled .= " |
function _smarty_tplfunc_$_match[2]_$_match[3](&\$$this_varname) |
{ |
$source |
} |
"; |
} |
$_include_compiled .= "\n\n?>\n"; |
$_params = array('filename' => $_compile_path, |
'contents' => $_include_compiled, 'create_dirs' => true); |
require_once(SMARTY_CORE_DIR . 'core.write_file.php'); |
smarty_core_write_file($_params, $smarty); |
return true; |
} |
?> |
/tags/0.1/lib/plugins/function.debug.php |
---|
Новый файл |
0,0 → 1,35 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {debug} function plugin |
* |
* Type: function<br> |
* Name: debug<br> |
* Date: July 1, 2002<br> |
* Purpose: popup debug window |
* @link http://smarty.php.net/manual/en/language.function.debug.php {debug} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @version 1.0 |
* @param array |
* @param Smarty |
* @return string output from {@link Smarty::_generate_debug_output()} |
*/ |
function smarty_function_debug($params, &$smarty) |
{ |
if (isset($params['output'])) { |
$smarty->assign('_smarty_debug_output', $params['output']); |
} |
require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); |
return smarty_core_display_debug_console(null, $smarty); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.eval.php |
---|
Новый файл |
0,0 → 1,49 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {eval} function plugin |
* |
* Type: function<br> |
* Name: eval<br> |
* Purpose: evaluate a template variable as a template<br> |
* @link http://smarty.php.net/manual/en/language.function.eval.php {eval} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
*/ |
function smarty_function_eval($params, &$smarty) |
{ |
if (!isset($params['var'])) { |
$smarty->trigger_error("eval: missing 'var' parameter"); |
return; |
} |
if($params['var'] == '') { |
return; |
} |
$smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); |
ob_start(); |
$smarty->_eval('?>' . $_var_compiled); |
$_contents = ob_get_contents(); |
ob_end_clean(); |
if (!empty($params['assign'])) { |
$smarty->assign($params['assign'], $_contents); |
} else { |
return $_contents; |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.strip_tags.php |
---|
Новый файл |
0,0 → 1,32 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty strip_tags modifier plugin |
* |
* Type: modifier<br> |
* Name: strip_tags<br> |
* Purpose: strip html tags from text |
* @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php |
* strip_tags (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param boolean |
* @return string |
*/ |
function smarty_modifier_strip_tags($string, $replace_with_space = true) |
{ |
if ($replace_with_space) |
return preg_replace('!<[^>]*?>!', ' ', $string); |
else |
return strip_tags($string); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.fetch.php |
---|
Новый файл |
0,0 → 1,221 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {fetch} plugin |
* |
* Type: function<br> |
* Name: fetch<br> |
* Purpose: fetch file, web or ftp data and display results |
* @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
* @return string|null if the assign parameter is passed, Smarty assigns the |
* result to a template variable |
*/ |
function smarty_function_fetch($params, &$smarty) |
{ |
if (empty($params['file'])) { |
$smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); |
return; |
} |
$content = ''; |
if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { |
$_params = array('resource_type' => 'file', 'resource_name' => $params['file']); |
require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); |
if(!smarty_core_is_secure($_params, $smarty)) { |
$smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); |
return; |
} |
// fetch the file |
if($fp = @fopen($params['file'],'r')) { |
while(!feof($fp)) { |
$content .= fgets ($fp,4096); |
} |
fclose($fp); |
} else { |
$smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); |
return; |
} |
} else { |
// not a local file |
if(preg_match('!^http://!i',$params['file'])) { |
// http fetch |
if($uri_parts = parse_url($params['file'])) { |
// set defaults |
$host = $server_name = $uri_parts['host']; |
$timeout = 30; |
$accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; |
$agent = "Smarty Template Engine ".$smarty->_version; |
$referer = ""; |
$uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; |
$uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; |
$_is_proxy = false; |
if(empty($uri_parts['port'])) { |
$port = 80; |
} else { |
$port = $uri_parts['port']; |
} |
if(!empty($uri_parts['user'])) { |
$user = $uri_parts['user']; |
} |
if(!empty($uri_parts['pass'])) { |
$pass = $uri_parts['pass']; |
} |
// loop through parameters, setup headers |
foreach($params as $param_key => $param_value) { |
switch($param_key) { |
case "file": |
case "assign": |
case "assign_headers": |
break; |
case "user": |
if(!empty($param_value)) { |
$user = $param_value; |
} |
break; |
case "pass": |
if(!empty($param_value)) { |
$pass = $param_value; |
} |
break; |
case "accept": |
if(!empty($param_value)) { |
$accept = $param_value; |
} |
break; |
case "header": |
if(!empty($param_value)) { |
if(!preg_match('![\w\d-]+: .+!',$param_value)) { |
$smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); |
return; |
} else { |
$extra_headers[] = $param_value; |
} |
} |
break; |
case "proxy_host": |
if(!empty($param_value)) { |
$proxy_host = $param_value; |
} |
break; |
case "proxy_port": |
if(!preg_match('!\D!', $param_value)) { |
$proxy_port = (int) $param_value; |
} else { |
$smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); |
return; |
} |
break; |
case "agent": |
if(!empty($param_value)) { |
$agent = $param_value; |
} |
break; |
case "referer": |
if(!empty($param_value)) { |
$referer = $param_value; |
} |
break; |
case "timeout": |
if(!preg_match('!\D!', $param_value)) { |
$timeout = (int) $param_value; |
} else { |
$smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); |
return; |
} |
break; |
default: |
$smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); |
return; |
} |
} |
if(!empty($proxy_host) && !empty($proxy_port)) { |
$_is_proxy = true; |
$fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); |
} else { |
$fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); |
} |
if(!$fp) { |
$smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)"); |
return; |
} else { |
if($_is_proxy) { |
fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); |
} else { |
fputs($fp, "GET $uri HTTP/1.0\r\n"); |
} |
if(!empty($host)) { |
fputs($fp, "Host: $host\r\n"); |
} |
if(!empty($accept)) { |
fputs($fp, "Accept: $accept\r\n"); |
} |
if(!empty($agent)) { |
fputs($fp, "User-Agent: $agent\r\n"); |
} |
if(!empty($referer)) { |
fputs($fp, "Referer: $referer\r\n"); |
} |
if(isset($extra_headers) && is_array($extra_headers)) { |
foreach($extra_headers as $curr_header) { |
fputs($fp, $curr_header."\r\n"); |
} |
} |
if(!empty($user) && !empty($pass)) { |
fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); |
} |
fputs($fp, "\r\n"); |
while(!feof($fp)) { |
$content .= fgets($fp,4096); |
} |
fclose($fp); |
$csplit = split("\r\n\r\n",$content,2); |
$content = $csplit[1]; |
if(!empty($params['assign_headers'])) { |
$smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); |
} |
} |
} else { |
$smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); |
return; |
} |
} else { |
// ftp fetch |
if($fp = @fopen($params['file'],'r')) { |
while(!feof($fp)) { |
$content .= fgets ($fp,4096); |
} |
fclose($fp); |
} else { |
$smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); |
return; |
} |
} |
} |
if (!empty($params['assign'])) { |
$smarty->assign($params['assign'],$content); |
} else { |
return $content; |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.capitalize.php |
---|
Новый файл |
0,0 → 1,43 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty capitalize modifier plugin |
* |
* Type: modifier<br> |
* Name: capitalize<br> |
* Purpose: capitalize words in the string |
* @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE |
* capitalize (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return string |
*/ |
function smarty_modifier_capitalize($string, $uc_digits = false) |
{ |
smarty_modifier_capitalize_ucfirst(null, $uc_digits); |
return preg_replace_callback('!\'?\b\w(\w|\')*\b!', 'smarty_modifier_capitalize_ucfirst', $string); |
} |
function smarty_modifier_capitalize_ucfirst($string, $uc_digits = null) |
{ |
static $_uc_digits = false; |
if(isset($uc_digits)) { |
$_uc_digits = $uc_digits; |
return; |
} |
if(substr($string[0],0,1) != "'" && !preg_match("!\d!",$string[0]) || $_uc_digits) |
return ucfirst($string[0]); |
else |
return $string[0]; |
} |
?> |
/tags/0.1/lib/plugins/modifier.count_characters.php |
---|
Новый файл |
0,0 → 1,32 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty count_characters modifier plugin |
* |
* Type: modifier<br> |
* Name: count_characteres<br> |
* Purpose: count the number of characters in a text |
* @link http://smarty.php.net/manual/en/language.modifier.count.characters.php |
* count_characters (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param boolean include whitespace in the character count |
* @return integer |
*/ |
function smarty_modifier_count_characters($string, $include_spaces = false) |
{ |
if ($include_spaces) |
return(strlen($string)); |
return preg_match_all("/[^\s]/",$string, $match); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_checkboxes.php |
---|
Новый файл |
0,0 → 1,143 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_checkboxes} function plugin |
* |
* File: function.html_checkboxes.php<br> |
* Type: function<br> |
* Name: html_checkboxes<br> |
* Date: 24.Feb.2003<br> |
* Purpose: Prints out a list of checkbox input types<br> |
* Input:<br> |
* - name (optional) - string default "checkbox" |
* - values (required) - array |
* - options (optional) - associative array |
* - checked (optional) - array default not set |
* - separator (optional) - ie <br> or |
* - output (optional) - the output next to each checkbox |
* - assign (optional) - assign the output as an array to this variable |
* Examples: |
* <pre> |
* {html_checkboxes values=$ids output=$names} |
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names} |
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names} |
* </pre> |
* @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} |
* (Smarty online manual) |
* @author Christopher Kvarme <christopher.kvarme@flashjab.com> |
* @author credits to Monte Ohrt <monte at ohrt dot com> |
* @version 1.0 |
* @param array |
* @param Smarty |
* @return string |
* @uses smarty_function_escape_special_chars() |
*/ |
function smarty_function_html_checkboxes($params, &$smarty) |
{ |
require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); |
$name = 'checkbox'; |
$values = null; |
$options = null; |
$selected = null; |
$separator = ''; |
$labels = true; |
$output = null; |
$extra = ''; |
foreach($params as $_key => $_val) { |
switch($_key) { |
case 'name': |
case 'separator': |
$$_key = $_val; |
break; |
case 'labels': |
$$_key = (bool)$_val; |
break; |
case 'options': |
$$_key = (array)$_val; |
break; |
case 'values': |
case 'output': |
$$_key = array_values((array)$_val); |
break; |
case 'checked': |
case 'selected': |
$selected = array_map('strval', array_values((array)$_val)); |
break; |
case 'checkboxes': |
$smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); |
$options = (array)$_val; |
break; |
case 'assign': |
break; |
default: |
if(!is_array($_val)) { |
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; |
} else { |
$smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); |
} |
break; |
} |
} |
if (!isset($options) && !isset($values)) |
return ''; /* raise error here? */ |
settype($selected, 'array'); |
$_html_result = array(); |
if (isset($options)) { |
foreach ($options as $_key=>$_val) |
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); |
} else { |
foreach ($values as $_i=>$_key) { |
$_val = isset($output[$_i]) ? $output[$_i] : ''; |
$_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); |
} |
} |
if(!empty($params['assign'])) { |
$smarty->assign($params['assign'], $_html_result); |
} else { |
return implode("\n",$_html_result); |
} |
} |
function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { |
$_output = ''; |
if ($labels) $_output .= '<label>'; |
$_output .= '<input type="checkbox" name="' |
. smarty_function_escape_special_chars($name) . '[]" value="' |
. smarty_function_escape_special_chars($value) . '"'; |
if (in_array((string)$value, $selected)) { |
$_output .= ' checked="checked"'; |
} |
$_output .= $extra . ' />' . $output; |
if ($labels) $_output .= '</label>'; |
$_output .= $separator; |
return $_output; |
} |
?> |
/tags/0.1/lib/plugins/function.config_load.php |
---|
Новый файл |
0,0 → 1,142 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {config_load} function plugin |
* |
* Type: function<br> |
* Name: config_load<br> |
* Purpose: load config file vars |
* @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author messju mohr <messju at lammfellpuschen dot de> (added use of resources) |
* @param array Format: |
* <pre> |
* array('file' => required config file name, |
* 'section' => optional config file section to load |
* 'scope' => local/parent/global |
* 'global' => overrides scope, setting to parent if true) |
* </pre> |
* @param Smarty |
*/ |
function smarty_function_config_load($params, &$smarty) |
{ |
if ($smarty->debugging) { |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$_debug_start_time = smarty_core_get_microtime($_params, $smarty); |
} |
$_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; |
$_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; |
$_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; |
$_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; |
if (!isset($_file) || strlen($_file) == 0) { |
$smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); |
} |
if (isset($_scope)) { |
if ($_scope != 'local' && |
$_scope != 'parent' && |
$_scope != 'global') { |
$smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); |
} |
} else { |
if ($_global) { |
$_scope = 'parent'; |
} else { |
$_scope = 'local'; |
} |
} |
$_params = array('resource_name' => $_file, |
'resource_base_path' => $smarty->config_dir, |
'get_source' => false); |
$smarty->_parse_resource_name($_params); |
$_file_path = $_params['resource_type'] . ':' . $_params['resource_name']; |
if (isset($_section)) |
$_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); |
else |
$_compile_file = $smarty->_get_compile_path($_file_path); |
if($smarty->force_compile || !file_exists($_compile_file)) { |
$_compile = true; |
} elseif ($smarty->compile_check) { |
$_params = array('resource_name' => $_file, |
'resource_base_path' => $smarty->config_dir, |
'get_source' => false); |
$_compile = $smarty->_fetch_resource_info($_params) && |
$_params['resource_timestamp'] > filemtime($_compile_file); |
} else { |
$_compile = false; |
} |
if($_compile) { |
// compile config file |
if(!is_object($smarty->_conf_obj)) { |
require_once SMARTY_DIR . $smarty->config_class . '.class.php'; |
$smarty->_conf_obj = new $smarty->config_class(); |
$smarty->_conf_obj->overwrite = $smarty->config_overwrite; |
$smarty->_conf_obj->booleanize = $smarty->config_booleanize; |
$smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; |
$smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; |
} |
$_params = array('resource_name' => $_file, |
'resource_base_path' => $smarty->config_dir, |
$_params['get_source'] = true); |
if (!$smarty->_fetch_resource_info($_params)) { |
return; |
} |
$smarty->_conf_obj->set_file_contents($_file, $_params['source_content']); |
$_config_vars = array_merge($smarty->_conf_obj->get($_file), |
$smarty->_conf_obj->get($_file, $_section)); |
if(function_exists('var_export')) { |
$_output = '<?php $_config_vars = ' . var_export($_config_vars, true) . '; ?>'; |
} else { |
$_output = '<?php $_config_vars = unserialize(\'' . strtr(serialize($_config_vars),array('\''=>'\\\'', '\\'=>'\\\\')) . '\'); ?>'; |
} |
$_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp'])); |
require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); |
smarty_core_write_compiled_resource($_params, $smarty); |
} else { |
include($_compile_file); |
} |
if ($smarty->caching) { |
$smarty->_cache_info['config'][$_file] = true; |
} |
$smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); |
$smarty->_config[0]['files'][$_file] = true; |
if ($_scope == 'parent') { |
$smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); |
$smarty->_config[1]['files'][$_file] = true; |
} else if ($_scope == 'global') { |
for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { |
$smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); |
$smarty->_config[$i]['files'][$_file] = true; |
} |
} |
if ($smarty->debugging) { |
$_params = array(); |
require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); |
$smarty->_smarty_debug_info[] = array('type' => 'config', |
'filename' => $_file.' ['.$_section.'] '.$_scope, |
'depth' => $smarty->_inclusion_depth, |
'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.upper.php |
---|
Новый файл |
0,0 → 1,26 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty upper modifier plugin |
* |
* Type: modifier<br> |
* Name: upper<br> |
* Purpose: convert string to uppercase |
* @link http://smarty.php.net/manual/en/language.modifier.upper.php |
* upper (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return string |
*/ |
function smarty_modifier_upper($string) |
{ |
return strtoupper($string); |
} |
?> |
/tags/0.1/lib/plugins/modifier.spacify.php |
---|
Новый файл |
0,0 → 1,30 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty spacify modifier plugin |
* |
* Type: modifier<br> |
* Name: spacify<br> |
* Purpose: add spaces between characters in a string |
* @link http://smarty.php.net/manual/en/language.modifier.spacify.php |
* spacify (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param string |
* @return string |
*/ |
function smarty_modifier_spacify($string, $spacify_char = ' ') |
{ |
return implode($spacify_char, |
preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY)); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.count_sentences.php |
---|
Новый файл |
0,0 → 1,29 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty count_sentences modifier plugin |
* |
* Type: modifier<br> |
* Name: count_sentences |
* Purpose: count the number of sentences in a text |
* @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php |
* count_sentences (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return integer |
*/ |
function smarty_modifier_count_sentences($string) |
{ |
// find periods with a word before but not after. |
return preg_match_all('/[^\s]\.(?!\w)/', $string, $match); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/outputfilter.trimwhitespace.php |
---|
Новый файл |
0,0 → 1,75 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty trimwhitespace outputfilter plugin |
* |
* File: outputfilter.trimwhitespace.php<br> |
* Type: outputfilter<br> |
* Name: trimwhitespace<br> |
* Date: Jan 25, 2003<br> |
* Purpose: trim leading white space and blank lines from |
* template source after it gets interpreted, cleaning |
* up code and saving bandwidth. Does not affect |
* <<PRE>></PRE> and <SCRIPT></SCRIPT> blocks.<br> |
* Install: Drop into the plugin directory, call |
* <code>$smarty->load_filter('output','trimwhitespace');</code> |
* from application. |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author Contributions from Lars Noschinski <lars@usenet.noschinski.de> |
* @version 1.3 |
* @param string |
* @param Smarty |
*/ |
function smarty_outputfilter_trimwhitespace($source, &$smarty) |
{ |
// Pull out the script blocks |
preg_match_all("!<script[^>]*?>.*?</script>!is", $source, $match); |
$_script_blocks = $match[0]; |
$source = preg_replace("!<script[^>]*?>.*?</script>!is", |
'@@@SMARTY:TRIM:SCRIPT@@@', $source); |
// Pull out the pre blocks |
preg_match_all("!<pre[^>]*?>.*?</pre>!is", $source, $match); |
$_pre_blocks = $match[0]; |
$source = preg_replace("!<pre[^>]*?>.*?</pre>!is", |
'@@@SMARTY:TRIM:PRE@@@', $source); |
// Pull out the textarea blocks |
preg_match_all("!<textarea[^>]*?>.*?</textarea>!is", $source, $match); |
$_textarea_blocks = $match[0]; |
$source = preg_replace("!<textarea[^>]*?>.*?</textarea>!is", |
'@@@SMARTY:TRIM:TEXTAREA@@@', $source); |
// remove all leading spaces, tabs and carriage returns NOT |
// preceeded by a php close tag. |
$source = trim(preg_replace('/((?<!\?>)\n)[\s]+/m', '\1', $source)); |
// replace textarea blocks |
smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); |
// replace pre blocks |
smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); |
// replace script blocks |
smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); |
return $source; |
} |
function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) { |
$_len = strlen($search_str); |
$_pos = 0; |
for ($_i=0, $_count=count($replace); $_i<$_count; $_i++) |
if (($_pos=strpos($subject, $search_str, $_pos))!==false) |
$subject = substr_replace($subject, $replace[$_i], $_pos, $_len); |
else |
break; |
} |
?> |
/tags/0.1/lib/plugins/modifier.strip.php |
---|
Новый файл |
0,0 → 1,33 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty strip modifier plugin |
* |
* Type: modifier<br> |
* Name: strip<br> |
* Purpose: Replace all repeated spaces, newlines, tabs |
* with a single space or supplied replacement string.<br> |
* Example: {$var|strip} {$var|strip:" "} |
* Date: September 25th, 2002 |
* @link http://smarty.php.net/manual/en/language.modifier.strip.php |
* strip (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @version 1.0 |
* @param string |
* @param string |
* @return string |
*/ |
function smarty_modifier_strip($text, $replace = ' ') |
{ |
return preg_replace('!\s+!', $replace, $text); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_table.php |
---|
Новый файл |
0,0 → 1,177 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_table} function plugin |
* |
* Type: function<br> |
* Name: html_table<br> |
* Date: Feb 17, 2003<br> |
* Purpose: make an html table from an array of data<br> |
* Input:<br> |
* - loop = array to loop through |
* - cols = number of columns, comma separated list of column names |
* or array of column names |
* - rows = number of rows |
* - table_attr = table attributes |
* - th_attr = table heading attributes (arrays are cycled) |
* - tr_attr = table row attributes (arrays are cycled) |
* - td_attr = table cell attributes (arrays are cycled) |
* - trailpad = value to pad trailing cells with |
* - caption = text for caption element |
* - vdir = vertical direction (default: "down", means top-to-bottom) |
* - hdir = horizontal direction (default: "right", means left-to-right) |
* - inner = inner loop (default "cols": print $loop line by line, |
* $loop will be printed column by column otherwise) |
* |
* |
* Examples: |
* <pre> |
* {table loop=$data} |
* {table loop=$data cols=4 tr_attr='"bgcolor=red"'} |
* {table loop=$data cols="first,second,third" tr_attr=$colors} |
* </pre> |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author credit to Messju Mohr <messju at lammfellpuschen dot de> |
* @author credit to boots <boots dot smarty at yahoo dot com> |
* @version 1.1 |
* @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table} |
* (Smarty online manual) |
* @param array |
* @param Smarty |
* @return string |
*/ |
function smarty_function_html_table($params, &$smarty) |
{ |
$table_attr = 'border="1"'; |
$tr_attr = ''; |
$th_attr = ''; |
$td_attr = ''; |
$cols = $cols_count = 3; |
$rows = 3; |
$trailpad = ' '; |
$vdir = 'down'; |
$hdir = 'right'; |
$inner = 'cols'; |
$caption = ''; |
if (!isset($params['loop'])) { |
$smarty->trigger_error("html_table: missing 'loop' parameter"); |
return; |
} |
foreach ($params as $_key=>$_value) { |
switch ($_key) { |
case 'loop': |
$$_key = (array)$_value; |
break; |
case 'cols': |
if (is_array($_value) && !empty($_value)) { |
$cols = $_value; |
$cols_count = count($_value); |
} elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) { |
$cols = explode(',', $_value); |
$cols_count = count($cols); |
} elseif (!empty($_value)) { |
$cols_count = (int)$_value; |
} else { |
$cols_count = $cols; |
} |
break; |
case 'rows': |
$$_key = (int)$_value; |
break; |
case 'table_attr': |
case 'trailpad': |
case 'hdir': |
case 'vdir': |
case 'inner': |
case 'caption': |
$$_key = (string)$_value; |
break; |
case 'tr_attr': |
case 'td_attr': |
case 'th_attr': |
$$_key = $_value; |
break; |
} |
} |
$loop_count = count($loop); |
if (empty($params['rows'])) { |
/* no rows specified */ |
$rows = ceil($loop_count/$cols_count); |
} elseif (empty($params['cols'])) { |
if (!empty($params['rows'])) { |
/* no cols specified, but rows */ |
$cols_count = ceil($loop_count/$rows); |
} |
} |
$output = "<table $table_attr>\n"; |
if (!empty($caption)) { |
$output .= '<caption>' . $caption . "</caption>\n"; |
} |
if (is_array($cols)) { |
$cols = ($hdir == 'right') ? $cols : array_reverse($cols); |
$output .= "<thead><tr>\n"; |
for ($r=0; $r<$cols_count; $r++) { |
$output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>'; |
$output .= $cols[$r]; |
$output .= "</th>\n"; |
} |
$output .= "</tr></thead>\n"; |
} |
$output .= "<tbody>\n"; |
for ($r=0; $r<$rows; $r++) { |
$output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n"; |
$rx = ($vdir == 'down') ? $r*$cols_count : ($rows-1-$r)*$cols_count; |
for ($c=0; $c<$cols_count; $c++) { |
$x = ($hdir == 'right') ? $rx+$c : $rx+$cols_count-1-$c; |
if ($inner!='cols') { |
/* shuffle x to loop over rows*/ |
$x = floor($x/$cols_count) + ($x%$cols_count)*$rows; |
} |
if ($x<$loop_count) { |
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n"; |
} else { |
$output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n"; |
} |
} |
$output .= "</tr>\n"; |
} |
$output .= "</tbody>\n"; |
$output .= "</table>\n"; |
return $output; |
} |
function smarty_function_html_table_cycle($name, $var, $no) { |
if(!is_array($var)) { |
$ret = $var; |
} else { |
$ret = $var[$no % count($var)]; |
} |
return ($ret) ? ' '.$ret : ''; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.wordwrap.php |
---|
Новый файл |
0,0 → 1,29 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty wordwrap modifier plugin |
* |
* Type: modifier<br> |
* Name: wordwrap<br> |
* Purpose: wrap a string of text at a given length |
* @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php |
* wordwrap (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param integer |
* @param string |
* @param boolean |
* @return string |
*/ |
function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false) |
{ |
return wordwrap($string,$length,$break,$cut); |
} |
?> |
/tags/0.1/lib/plugins/modifier.count_words.php |
---|
Новый файл |
0,0 → 1,33 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty count_words modifier plugin |
* |
* Type: modifier<br> |
* Name: count_words<br> |
* Purpose: count the number of words in a text |
* @link http://smarty.php.net/manual/en/language.modifier.count.words.php |
* count_words (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return integer |
*/ |
function smarty_modifier_count_words($string) |
{ |
// split text by ' ',\r,\n,\f,\t |
$split_array = preg_split('/\s+/',$string); |
// count matches that contain alphanumerics |
$word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array); |
return count($word_count); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_options.php |
---|
Новый файл |
0,0 → 1,122 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_options} function plugin |
* |
* Type: function<br> |
* Name: html_options<br> |
* Input:<br> |
* - name (optional) - string default "select" |
* - values (required if no options supplied) - array |
* - options (required if no values supplied) - associative array |
* - selected (optional) - string default not set |
* - output (required if not options supplied) - array |
* Purpose: Prints the list of <option> tags generated from |
* the passed parameters |
* @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
* @return string |
* @uses smarty_function_escape_special_chars() |
*/ |
function smarty_function_html_options($params, &$smarty) |
{ |
require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); |
$name = null; |
$values = null; |
$options = null; |
$selected = array(); |
$output = null; |
$extra = ''; |
foreach($params as $_key => $_val) { |
switch($_key) { |
case 'name': |
$$_key = (string)$_val; |
break; |
case 'options': |
$$_key = (array)$_val; |
break; |
case 'values': |
case 'output': |
$$_key = array_values((array)$_val); |
break; |
case 'selected': |
$$_key = array_map('strval', array_values((array)$_val)); |
break; |
default: |
if(!is_array($_val)) { |
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; |
} else { |
$smarty->trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE); |
} |
break; |
} |
} |
if (!isset($options) && !isset($values)) |
return ''; /* raise error here? */ |
$_html_result = ''; |
if (isset($options)) { |
foreach ($options as $_key=>$_val) |
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected); |
} else { |
foreach ($values as $_i=>$_key) { |
$_val = isset($output[$_i]) ? $output[$_i] : ''; |
$_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected); |
} |
} |
if(!empty($name)) { |
$_html_result = '<select name="' . $name . '"' . $extra . '>' . "\n" . $_html_result . '</select>' . "\n"; |
} |
return $_html_result; |
} |
function smarty_function_html_options_optoutput($key, $value, $selected) { |
if(!is_array($value)) { |
$_html_result = '<option label="' . smarty_function_escape_special_chars($value) . '" value="' . |
smarty_function_escape_special_chars($key) . '"'; |
if (in_array((string)$key, $selected)) |
$_html_result .= ' selected="selected"'; |
$_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . "\n"; |
} else { |
$_html_result = smarty_function_html_options_optgroup($key, $value, $selected); |
} |
return $_html_result; |
} |
function smarty_function_html_options_optgroup($key, $values, $selected) { |
$optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n"; |
foreach ($values as $key => $value) { |
$optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected); |
} |
$optgroup_html .= "</optgroup>\n"; |
return $optgroup_html; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.cat.php |
---|
Новый файл |
0,0 → 1,33 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty cat modifier plugin |
* |
* Type: modifier<br> |
* Name: cat<br> |
* Date: Feb 24, 2003 |
* Purpose: catenate a value to a variable |
* Input: string to catenate |
* Example: {$var|cat:"foo"} |
* @link http://smarty.php.net/manual/en/language.modifier.cat.php cat |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @version 1.0 |
* @param string |
* @param string |
* @return string |
*/ |
function smarty_modifier_cat($string, $cat) |
{ |
return $string . $cat; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_select_time.php |
---|
Новый файл |
0,0 → 1,194 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_select_time} function plugin |
* |
* Type: function<br> |
* Name: html_select_time<br> |
* Purpose: Prints the dropdowns for time selection |
* @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time} |
* (Smarty online manual) |
* @author Roberto Berto <roberto@berto.net> |
* @credits Monte Ohrt <monte AT ohrt DOT com> |
* @param array |
* @param Smarty |
* @return string |
* @uses smarty_make_timestamp() |
*/ |
function smarty_function_html_select_time($params, &$smarty) |
{ |
require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); |
require_once $smarty->_get_plugin_filepath('function','html_options'); |
/* Default values. */ |
$prefix = "Time_"; |
$time = time(); |
$display_hours = true; |
$display_minutes = true; |
$display_seconds = true; |
$display_meridian = true; |
$use_24_hours = true; |
$minute_interval = 1; |
$second_interval = 1; |
/* Should the select boxes be part of an array when returned from PHP? |
e.g. setting it to "birthday", would create "birthday[Hour]", |
"birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]". |
Can be combined with prefix. */ |
$field_array = null; |
$all_extra = null; |
$hour_extra = null; |
$minute_extra = null; |
$second_extra = null; |
$meridian_extra = null; |
foreach ($params as $_key=>$_value) { |
switch ($_key) { |
case 'prefix': |
case 'time': |
case 'field_array': |
case 'all_extra': |
case 'hour_extra': |
case 'minute_extra': |
case 'second_extra': |
case 'meridian_extra': |
$$_key = (string)$_value; |
break; |
case 'display_hours': |
case 'display_minutes': |
case 'display_seconds': |
case 'display_meridian': |
case 'use_24_hours': |
$$_key = (bool)$_value; |
break; |
case 'minute_interval': |
case 'second_interval': |
$$_key = (int)$_value; |
break; |
default: |
$smarty->trigger_error("[html_select_time] unknown parameter $_key", E_USER_WARNING); |
} |
} |
$time = smarty_make_timestamp($time); |
$html_result = ''; |
if ($display_hours) { |
$hours = $use_24_hours ? range(0, 23) : range(1, 12); |
$hour_fmt = $use_24_hours ? '%H' : '%I'; |
for ($i = 0, $for_max = count($hours); $i < $for_max; $i++) |
$hours[$i] = sprintf('%02d', $hours[$i]); |
$html_result .= '<select name='; |
if (null !== $field_array) { |
$html_result .= '"' . $field_array . '[' . $prefix . 'Hour]"'; |
} else { |
$html_result .= '"' . $prefix . 'Hour"'; |
} |
if (null !== $hour_extra){ |
$html_result .= ' ' . $hour_extra; |
} |
if (null !== $all_extra){ |
$html_result .= ' ' . $all_extra; |
} |
$html_result .= '>'."\n"; |
$html_result .= smarty_function_html_options(array('output' => $hours, |
'values' => $hours, |
'selected' => strftime($hour_fmt, $time), |
'print_result' => false), |
$smarty); |
$html_result .= "</select>\n"; |
} |
if ($display_minutes) { |
$all_minutes = range(0, 59); |
for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval) |
$minutes[] = sprintf('%02d', $all_minutes[$i]); |
$selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval); |
$html_result .= '<select name='; |
if (null !== $field_array) { |
$html_result .= '"' . $field_array . '[' . $prefix . 'Minute]"'; |
} else { |
$html_result .= '"' . $prefix . 'Minute"'; |
} |
if (null !== $minute_extra){ |
$html_result .= ' ' . $minute_extra; |
} |
if (null !== $all_extra){ |
$html_result .= ' ' . $all_extra; |
} |
$html_result .= '>'."\n"; |
$html_result .= smarty_function_html_options(array('output' => $minutes, |
'values' => $minutes, |
'selected' => $selected, |
'print_result' => false), |
$smarty); |
$html_result .= "</select>\n"; |
} |
if ($display_seconds) { |
$all_seconds = range(0, 59); |
for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval) |
$seconds[] = sprintf('%02d', $all_seconds[$i]); |
$selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval); |
$html_result .= '<select name='; |
if (null !== $field_array) { |
$html_result .= '"' . $field_array . '[' . $prefix . 'Second]"'; |
} else { |
$html_result .= '"' . $prefix . 'Second"'; |
} |
if (null !== $second_extra){ |
$html_result .= ' ' . $second_extra; |
} |
if (null !== $all_extra){ |
$html_result .= ' ' . $all_extra; |
} |
$html_result .= '>'."\n"; |
$html_result .= smarty_function_html_options(array('output' => $seconds, |
'values' => $seconds, |
'selected' => $selected, |
'print_result' => false), |
$smarty); |
$html_result .= "</select>\n"; |
} |
if ($display_meridian && !$use_24_hours) { |
$html_result .= '<select name='; |
if (null !== $field_array) { |
$html_result .= '"' . $field_array . '[' . $prefix . 'Meridian]"'; |
} else { |
$html_result .= '"' . $prefix . 'Meridian"'; |
} |
if (null !== $meridian_extra){ |
$html_result .= ' ' . $meridian_extra; |
} |
if (null !== $all_extra){ |
$html_result .= ' ' . $all_extra; |
} |
$html_result .= '>'."\n"; |
$html_result .= smarty_function_html_options(array('output' => array('AM', 'PM'), |
'values' => array('am', 'pm'), |
'selected' => strtolower(strftime('%p', $time)), |
'print_result' => false), |
$smarty); |
$html_result .= "</select>\n"; |
} |
return $html_result; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/shared.make_timestamp.php |
---|
Новый файл |
0,0 → 1,46 |
<?php |
/** |
* Smarty shared plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Function: smarty_make_timestamp<br> |
* Purpose: used by other smarty functions to make a timestamp |
* from a string. |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return string |
*/ |
function smarty_make_timestamp($string) |
{ |
if(empty($string)) { |
// use "now": |
$time = time(); |
} elseif (preg_match('/^\d{14}$/', $string)) { |
// it is mysql timestamp format of YYYYMMDDHHMMSS? |
$time = mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2), |
substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4)); |
} elseif (is_numeric($string)) { |
// it is a numeric string, we handle it as timestamp |
$time = (int)$string; |
} else { |
// strtotime should handle it |
$time = strtotime($string); |
if ($time == -1 || $time === false) { |
// strtotime() was not able to parse $string, use "now": |
$time = time(); |
} |
} |
return $time; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.debug_print_var.php |
---|
Новый файл |
0,0 → 1,90 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty debug_print_var modifier plugin |
* |
* Type: modifier<br> |
* Name: debug_print_var<br> |
* Purpose: formats variable contents for display in the console |
* @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php |
* debug_print_var (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array|object |
* @param integer |
* @param integer |
* @return string |
*/ |
function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40) |
{ |
$_replace = array( |
"\n" => '<i>\n</i>', |
"\r" => '<i>\r</i>', |
"\t" => '<i>\t</i>' |
); |
switch (gettype($var)) { |
case 'array' : |
$results = '<b>Array (' . count($var) . ')</b>'; |
foreach ($var as $curr_key => $curr_val) { |
$results .= '<br>' . str_repeat(' ', $depth * 2) |
. '<b>' . strtr($curr_key, $_replace) . '</b> => ' |
. smarty_modifier_debug_print_var($curr_val, ++$depth, $length); |
$depth--; |
} |
break; |
case 'object' : |
$object_vars = get_object_vars($var); |
$results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>'; |
foreach ($object_vars as $curr_key => $curr_val) { |
$results .= '<br>' . str_repeat(' ', $depth * 2) |
. '<b> ->' . strtr($curr_key, $_replace) . '</b> = ' |
. smarty_modifier_debug_print_var($curr_val, ++$depth, $length); |
$depth--; |
} |
break; |
case 'boolean' : |
case 'NULL' : |
case 'resource' : |
if (true === $var) { |
$results = 'true'; |
} elseif (false === $var) { |
$results = 'false'; |
} elseif (null === $var) { |
$results = 'null'; |
} else { |
$results = htmlspecialchars((string) $var); |
} |
$results = '<i>' . $results . '</i>'; |
break; |
case 'integer' : |
case 'float' : |
$results = htmlspecialchars((string) $var); |
break; |
case 'string' : |
$results = strtr($var, $_replace); |
if (strlen($var) > $length ) { |
$results = substr($var, 0, $length - 3) . '...'; |
} |
$results = htmlspecialchars('"' . $results . '"'); |
break; |
case 'unknown type' : |
default : |
$results = strtr((string) $var, $_replace); |
if (strlen($results) > $length ) { |
$results = substr($results, 0, $length - 3) . '...'; |
} |
$results = htmlspecialchars($results); |
} |
return $results; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.replace.php |
---|
Новый файл |
0,0 → 1,30 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty replace modifier plugin |
* |
* Type: modifier<br> |
* Name: replace<br> |
* Purpose: simple search/replace |
* @link http://smarty.php.net/manual/en/language.modifier.replace.php |
* replace (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param string |
* @param string |
* @return string |
*/ |
function smarty_modifier_replace($string, $search, $replace) |
{ |
return str_replace($search, $replace, $string); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.mailto.php |
---|
Новый файл |
0,0 → 1,165 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {mailto} function plugin |
* |
* Type: function<br> |
* Name: mailto<br> |
* Date: May 21, 2002 |
* Purpose: automate mailto address link creation, and optionally |
* encode them.<br> |
* Input:<br> |
* - address = e-mail address |
* - text = (optional) text to display, default is address |
* - encode = (optional) can be one of: |
* * none : no encoding (default) |
* * javascript : encode with javascript |
* * javascript_charcode : encode with javascript charcode |
* * hex : encode with hexidecimal (no javascript) |
* - cc = (optional) address(es) to carbon copy |
* - bcc = (optional) address(es) to blind carbon copy |
* - subject = (optional) e-mail subject |
* - newsgroups = (optional) newsgroup(s) to post to |
* - followupto = (optional) address(es) to follow up to |
* - extra = (optional) extra tags for the href link |
* |
* Examples: |
* <pre> |
* {mailto address="me@domain.com"} |
* {mailto address="me@domain.com" encode="javascript"} |
* {mailto address="me@domain.com" encode="hex"} |
* {mailto address="me@domain.com" subject="Hello to you!"} |
* {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"} |
* {mailto address="me@domain.com" extra='class="mailto"'} |
* </pre> |
* @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto} |
* (Smarty online manual) |
* @version 1.2 |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author credits to Jason Sweat (added cc, bcc and subject functionality) |
* @param array |
* @param Smarty |
* @return string |
*/ |
function smarty_function_mailto($params, &$smarty) |
{ |
$extra = ''; |
if (empty($params['address'])) { |
$smarty->trigger_error("mailto: missing 'address' parameter"); |
return; |
} else { |
$address = $params['address']; |
} |
$text = $address; |
// netscape and mozilla do not decode %40 (@) in BCC field (bug?) |
// so, don't encode it. |
$search = array('%40', '%2C'); |
$replace = array('@', ','); |
$mail_parms = array(); |
foreach ($params as $var=>$value) { |
switch ($var) { |
case 'cc': |
case 'bcc': |
case 'followupto': |
if (!empty($value)) |
$mail_parms[] = $var.'='.str_replace($search,$replace,rawurlencode($value)); |
break; |
case 'subject': |
case 'newsgroups': |
$mail_parms[] = $var.'='.rawurlencode($value); |
break; |
case 'extra': |
case 'text': |
$$var = $value; |
default: |
} |
} |
$mail_parm_vals = ''; |
for ($i=0; $i<count($mail_parms); $i++) { |
$mail_parm_vals .= (0==$i) ? '?' : '&'; |
$mail_parm_vals .= $mail_parms[$i]; |
} |
$address .= $mail_parm_vals; |
$encode = (empty($params['encode'])) ? 'none' : $params['encode']; |
if (!in_array($encode,array('javascript','javascript_charcode','hex','none')) ) { |
$smarty->trigger_error("mailto: 'encode' parameter must be none, javascript or hex"); |
return; |
} |
if ($encode == 'javascript' ) { |
$string = 'document.write(\'<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>\');'; |
$js_encode = ''; |
for ($x=0; $x < strlen($string); $x++) { |
$js_encode .= '%' . bin2hex($string[$x]); |
} |
return '<script type="text/javascript">eval(unescape(\''.$js_encode.'\'))</script>'; |
} elseif ($encode == 'javascript_charcode' ) { |
$string = '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>'; |
for($x = 0, $y = strlen($string); $x < $y; $x++ ) { |
$ord[] = ord($string[$x]); |
} |
$_ret = "<script type=\"text/javascript\" language=\"javascript\">\n"; |
$_ret .= "<!--\n"; |
$_ret .= "{document.write(String.fromCharCode("; |
$_ret .= implode(',',$ord); |
$_ret .= "))"; |
$_ret .= "}\n"; |
$_ret .= "//-->\n"; |
$_ret .= "</script>\n"; |
return $_ret; |
} elseif ($encode == 'hex') { |
preg_match('!^(.*)(\?.*)$!',$address,$match); |
if(!empty($match[2])) { |
$smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript."); |
return; |
} |
$address_encode = ''; |
for ($x=0; $x < strlen($address); $x++) { |
if(preg_match('!\w!',$address[$x])) { |
$address_encode .= '%' . bin2hex($address[$x]); |
} else { |
$address_encode .= $address[$x]; |
} |
} |
$text_encode = ''; |
for ($x=0; $x < strlen($text); $x++) { |
$text_encode .= '&#x' . bin2hex($text[$x]).';'; |
} |
$mailto = "mailto:"; |
return '<a href="'.$mailto.$address_encode.'" '.$extra.'>'.$text_encode.'</a>'; |
} else { |
// no encoding |
return '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>'; |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.popup_init.php |
---|
Новый файл |
0,0 → 1,40 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {popup_init} function plugin |
* |
* Type: function<br> |
* Name: popup_init<br> |
* Purpose: initialize overlib |
* @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
* @return string |
*/ |
function smarty_function_popup_init($params, &$smarty) |
{ |
$zindex = 1000; |
if (!empty($params['zindex'])) { |
$zindex = $params['zindex']; |
} |
if (!empty($params['src'])) { |
return '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:'.$zindex.';"></div>' . "\n" |
. '<script type="text/javascript" language="JavaScript" src="'.$params['src'].'"></script>' . "\n"; |
} else { |
$smarty->trigger_error("popup_init: missing src parameter"); |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.string_format.php |
---|
Новый файл |
0,0 → 1,29 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty string_format modifier plugin |
* |
* Type: modifier<br> |
* Name: string_format<br> |
* Purpose: format strings via sprintf |
* @link http://smarty.php.net/manual/en/language.modifier.string.format.php |
* string_format (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param string |
* @return string |
*/ |
function smarty_modifier_string_format($string, $format) |
{ |
return sprintf($format, $string); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.nl2br.php |
---|
Новый файл |
0,0 → 1,35 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty plugin |
* |
* Type: modifier<br> |
* Name: nl2br<br> |
* Date: Feb 26, 2003 |
* Purpose: convert \r\n, \r or \n to <<br>> |
* Input:<br> |
* - contents = contents to replace |
* - preceed_test = if true, includes preceeding break tags |
* in replacement |
* Example: {$text|nl2br} |
* @link http://smarty.php.net/manual/en/language.modifier.nl2br.php |
* nl2br (Smarty online manual) |
* @version 1.0 |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return string |
*/ |
function smarty_modifier_nl2br($string) |
{ |
return nl2br($string); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.math.php |
---|
Новый файл |
0,0 → 1,84 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {math} function plugin |
* |
* Type: function<br> |
* Name: math<br> |
* Purpose: handle math computations in template<br> |
* @link http://smarty.php.net/manual/en/language.function.math.php {math} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
* @return string |
*/ |
function smarty_function_math($params, &$smarty) |
{ |
// be sure equation parameter is present |
if (empty($params['equation'])) { |
$smarty->trigger_error("math: missing equation parameter"); |
return; |
} |
$equation = $params['equation']; |
// make sure parenthesis are balanced |
if (substr_count($equation,"(") != substr_count($equation,")")) { |
$smarty->trigger_error("math: unbalanced parenthesis"); |
return; |
} |
// match all vars in equation, make sure all are passed |
preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!",$equation, $match); |
$allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10', |
'max','min','pi','pow','rand','round','sin','sqrt','srand','tan'); |
foreach($match[1] as $curr_var) { |
if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) { |
$smarty->trigger_error("math: function call $curr_var not allowed"); |
return; |
} |
} |
foreach($params as $key => $val) { |
if ($key != "equation" && $key != "format" && $key != "assign") { |
// make sure value is not empty |
if (strlen($val)==0) { |
$smarty->trigger_error("math: parameter $key is empty"); |
return; |
} |
if (!is_numeric($val)) { |
$smarty->trigger_error("math: parameter $key: is not numeric"); |
return; |
} |
$equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation); |
} |
} |
eval("\$smarty_math_result = ".$equation.";"); |
if (empty($params['format'])) { |
if (empty($params['assign'])) { |
return $smarty_math_result; |
} else { |
$smarty->assign($params['assign'],$smarty_math_result); |
} |
} else { |
if (empty($params['assign'])){ |
printf($params['format'],$smarty_math_result); |
} else { |
$smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result)); |
} |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.indent.php |
---|
Новый файл |
0,0 → 1,28 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty indent modifier plugin |
* |
* Type: modifier<br> |
* Name: indent<br> |
* Purpose: indent lines of text |
* @link http://smarty.php.net/manual/en/language.modifier.indent.php |
* indent (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param integer |
* @param string |
* @return string |
*/ |
function smarty_modifier_indent($string,$chars=4,$char=" ") |
{ |
return preg_replace('!^!m',str_repeat($char,$chars),$string); |
} |
?> |
/tags/0.1/lib/plugins/modifier.default.php |
---|
Новый файл |
0,0 → 1,32 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty default modifier plugin |
* |
* Type: modifier<br> |
* Name: default<br> |
* Purpose: designate default value for empty variables |
* @link http://smarty.php.net/manual/en/language.modifier.default.php |
* default (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param string |
* @return string |
*/ |
function smarty_modifier_default($string, $default = '') |
{ |
if (!isset($string) || $string === '') |
return $default; |
else |
return $string; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.date_format.php |
---|
Новый файл |
0,0 → 1,58 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Include the {@link shared.make_timestamp.php} plugin |
*/ |
require_once $smarty->_get_plugin_filepath('shared', 'make_timestamp'); |
/** |
* Smarty date_format modifier plugin |
* |
* Type: modifier<br> |
* Name: date_format<br> |
* Purpose: format datestamps via strftime<br> |
* Input:<br> |
* - string: input date string |
* - format: strftime format for output |
* - default_date: default date if $string is empty |
* @link http://smarty.php.net/manual/en/language.modifier.date.format.php |
* date_format (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param string |
* @param string |
* @return string|void |
* @uses smarty_make_timestamp() |
*/ |
function smarty_modifier_date_format($string, $format = '%b %e, %Y', $default_date = '') |
{ |
if ($string != '') { |
$timestamp = smarty_make_timestamp($string); |
} elseif ($default_date != '') { |
$timestamp = smarty_make_timestamp($default_date); |
} else { |
return; |
} |
if (DIRECTORY_SEPARATOR == '\\') { |
$_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T'); |
$_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S'); |
if (strpos($format, '%e') !== false) { |
$_win_from[] = '%e'; |
$_win_to[] = sprintf('%\' 2d', date('j', $timestamp)); |
} |
if (strpos($format, '%l') !== false) { |
$_win_from[] = '%l'; |
$_win_to[] = sprintf('%\' 2d', date('h', $timestamp)); |
} |
$format = str_replace($_win_from, $_win_to, $format); |
} |
return strftime($format, $timestamp); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.truncate.php |
---|
Новый файл |
0,0 → 1,50 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty truncate modifier plugin |
* |
* Type: modifier<br> |
* Name: truncate<br> |
* Purpose: Truncate a string to a certain length if necessary, |
* optionally splitting in the middle of a word, and |
* appending the $etc string or inserting $etc into the middle. |
* @link http://smarty.php.net/manual/en/language.modifier.truncate.php |
* truncate (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param integer |
* @param string |
* @param boolean |
* @param boolean |
* @return string |
*/ |
function smarty_modifier_truncate($string, $length = 80, $etc = '...', |
$break_words = false, $middle = false) |
{ |
if ($length == 0) |
return ''; |
if (strlen($string) > $length) { |
$length -= min($length, strlen($etc)); |
if (!$break_words && !$middle) { |
$string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1)); |
} |
if(!$middle) { |
return substr($string, 0, $length) . $etc; |
} else { |
return substr($string, 0, $length/2) . $etc . substr($string, -$length/2); |
} |
} else { |
return $string; |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.cycle.php |
---|
Новый файл |
0,0 → 1,102 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {cycle} function plugin |
* |
* Type: function<br> |
* Name: cycle<br> |
* Date: May 3, 2002<br> |
* Purpose: cycle through given values<br> |
* Input: |
* - name = name of cycle (optional) |
* - values = comma separated list of values to cycle, |
* or an array of values to cycle |
* (this can be left out for subsequent calls) |
* - reset = boolean - resets given var to true |
* - print = boolean - print var or not. default is true |
* - advance = boolean - whether or not to advance the cycle |
* - delimiter = the value delimiter, default is "," |
* - assign = boolean, assigns to template var instead of |
* printed. |
* |
* Examples:<br> |
* <pre> |
* {cycle values="#eeeeee,#d0d0d0d"} |
* {cycle name=row values="one,two,three" reset=true} |
* {cycle name=row} |
* </pre> |
* @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author credit to Mark Priatel <mpriatel@rogers.com> |
* @author credit to Gerard <gerard@interfold.com> |
* @author credit to Jason Sweat <jsweat_php@yahoo.com> |
* @version 1.3 |
* @param array |
* @param Smarty |
* @return string|null |
*/ |
function smarty_function_cycle($params, &$smarty) |
{ |
static $cycle_vars; |
$name = (empty($params['name'])) ? 'default' : $params['name']; |
$print = (isset($params['print'])) ? (bool)$params['print'] : true; |
$advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; |
$reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; |
if (!in_array('values', array_keys($params))) { |
if(!isset($cycle_vars[$name]['values'])) { |
$smarty->trigger_error("cycle: missing 'values' parameter"); |
return; |
} |
} else { |
if(isset($cycle_vars[$name]['values']) |
&& $cycle_vars[$name]['values'] != $params['values'] ) { |
$cycle_vars[$name]['index'] = 0; |
} |
$cycle_vars[$name]['values'] = $params['values']; |
} |
$cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ','; |
if(is_array($cycle_vars[$name]['values'])) { |
$cycle_array = $cycle_vars[$name]['values']; |
} else { |
$cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); |
} |
if(!isset($cycle_vars[$name]['index']) || $reset ) { |
$cycle_vars[$name]['index'] = 0; |
} |
if (isset($params['assign'])) { |
$print = false; |
$smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); |
} |
if($print) { |
$retval = $cycle_array[$cycle_vars[$name]['index']]; |
} else { |
$retval = null; |
} |
if($advance) { |
if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { |
$cycle_vars[$name]['index'] = 0; |
} else { |
$cycle_vars[$name]['index']++; |
} |
} |
return $retval; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_select_date.php |
---|
Новый файл |
0,0 → 1,331 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_select_date} plugin |
* |
* Type: function<br> |
* Name: html_select_date<br> |
* Purpose: Prints the dropdowns for date selection. |
* |
* ChangeLog:<br> |
* - 1.0 initial release |
* - 1.1 added support for +/- N syntax for begin |
* and end year values. (Monte) |
* - 1.2 added support for yyyy-mm-dd syntax for |
* time value. (Jan Rosier) |
* - 1.3 added support for choosing format for |
* month values (Gary Loescher) |
* - 1.3.1 added support for choosing format for |
* day values (Marcus Bointon) |
* - 1.3.2 support negative timestamps, force year |
* dropdown to include given date unless explicitly set (Monte) |
* - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that |
* of 0000-00-00 dates (cybot, boots) |
* @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date} |
* (Smarty online manual) |
* @version 1.3.4 |
* @author Andrei Zmievski |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
* @return string |
*/ |
function smarty_function_html_select_date($params, &$smarty) |
{ |
require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); |
require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); |
require_once $smarty->_get_plugin_filepath('function','html_options'); |
/* Default values. */ |
$prefix = "Date_"; |
$start_year = strftime("%Y"); |
$end_year = $start_year; |
$display_days = true; |
$display_months = true; |
$display_years = true; |
$month_format = "%B"; |
/* Write months as numbers by default GL */ |
$month_value_format = "%m"; |
$day_format = "%02d"; |
/* Write day values using this format MB */ |
$day_value_format = "%d"; |
$year_as_text = false; |
/* Display years in reverse order? Ie. 2000,1999,.... */ |
$reverse_years = false; |
/* Should the select boxes be part of an array when returned from PHP? |
e.g. setting it to "birthday", would create "birthday[Day]", |
"birthday[Month]" & "birthday[Year]". Can be combined with prefix */ |
$field_array = null; |
/* <select size>'s of the different <select> tags. |
If not set, uses default dropdown. */ |
$day_size = null; |
$month_size = null; |
$year_size = null; |
/* Unparsed attributes common to *ALL* the <select>/<input> tags. |
An example might be in the template: all_extra ='class ="foo"'. */ |
$all_extra = null; |
/* Separate attributes for the tags. */ |
$day_extra = null; |
$month_extra = null; |
$year_extra = null; |
/* Order in which to display the fields. |
"D" -> day, "M" -> month, "Y" -> year. */ |
$field_order = 'MDY'; |
/* String printed between the different fields. */ |
$field_separator = "\n"; |
$time = time(); |
$all_empty = null; |
$day_empty = null; |
$month_empty = null; |
$year_empty = null; |
$extra_attrs = ''; |
foreach ($params as $_key=>$_value) { |
switch ($_key) { |
case 'prefix': |
case 'time': |
case 'start_year': |
case 'end_year': |
case 'month_format': |
case 'day_format': |
case 'day_value_format': |
case 'field_array': |
case 'day_size': |
case 'month_size': |
case 'year_size': |
case 'all_extra': |
case 'day_extra': |
case 'month_extra': |
case 'year_extra': |
case 'field_order': |
case 'field_separator': |
case 'month_value_format': |
case 'month_empty': |
case 'day_empty': |
case 'year_empty': |
$$_key = (string)$_value; |
break; |
case 'all_empty': |
$$_key = (string)$_value; |
$day_empty = $month_empty = $year_empty = $all_empty; |
break; |
case 'display_days': |
case 'display_months': |
case 'display_years': |
case 'year_as_text': |
case 'reverse_years': |
$$_key = (bool)$_value; |
break; |
default: |
if(!is_array($_value)) { |
$extra_attrs .= ' '.$_key.'="'.smarty_function_escape_special_chars($_value).'"'; |
} else { |
$smarty->trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE); |
} |
break; |
} |
} |
if (preg_match('!^-\d+$!', $time)) { |
// negative timestamp, use date() |
$time = date('Y-m-d', $time); |
} |
// If $time is not in format yyyy-mm-dd |
if (preg_match('/^(\d{0,4}-\d{0,2}-\d{0,2})/', $time, $found)) { |
$time = $found[1]; |
} else { |
// use smarty_make_timestamp to get an unix timestamp and |
// strftime to make yyyy-mm-dd |
$time = strftime('%Y-%m-%d', smarty_make_timestamp($time)); |
} |
// Now split this in pieces, which later can be used to set the select |
$time = explode("-", $time); |
// make syntax "+N" or "-N" work with start_year and end_year |
if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) { |
if ($match[1] == '+') { |
$end_year = strftime('%Y') + $match[2]; |
} else { |
$end_year = strftime('%Y') - $match[2]; |
} |
} |
if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) { |
if ($match[1] == '+') { |
$start_year = strftime('%Y') + $match[2]; |
} else { |
$start_year = strftime('%Y') - $match[2]; |
} |
} |
if (strlen($time[0]) > 0) { |
if ($start_year > $time[0] && !isset($params['start_year'])) { |
// force start year to include given date if not explicitly set |
$start_year = $time[0]; |
} |
if($end_year < $time[0] && !isset($params['end_year'])) { |
// force end year to include given date if not explicitly set |
$end_year = $time[0]; |
} |
} |
$field_order = strtoupper($field_order); |
$html_result = $month_result = $day_result = $year_result = ""; |
$field_separator_count = -1; |
if ($display_months) { |
$field_separator_count++; |
$month_names = array(); |
$month_values = array(); |
if(isset($month_empty)) { |
$month_names[''] = $month_empty; |
$month_values[''] = ''; |
} |
for ($i = 1; $i <= 12; $i++) { |
$month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000)); |
$month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000)); |
} |
$month_result .= '<select name='; |
if (null !== $field_array){ |
$month_result .= '"' . $field_array . '[' . $prefix . 'Month]"'; |
} else { |
$month_result .= '"' . $prefix . 'Month"'; |
} |
if (null !== $month_size){ |
$month_result .= ' size="' . $month_size . '"'; |
} |
if (null !== $month_extra){ |
$month_result .= ' ' . $month_extra; |
} |
if (null !== $all_extra){ |
$month_result .= ' ' . $all_extra; |
} |
$month_result .= $extra_attrs . '>'."\n"; |
$month_result .= smarty_function_html_options(array('output' => $month_names, |
'values' => $month_values, |
'selected' => (int)$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '', |
'print_result' => false), |
$smarty); |
$month_result .= '</select>'; |
} |
if ($display_days) { |
$field_separator_count++; |
$days = array(); |
if (isset($day_empty)) { |
$days[''] = $day_empty; |
$day_values[''] = ''; |
} |
for ($i = 1; $i <= 31; $i++) { |
$days[] = sprintf($day_format, $i); |
$day_values[] = sprintf($day_value_format, $i); |
} |
$day_result .= '<select name='; |
if (null !== $field_array){ |
$day_result .= '"' . $field_array . '[' . $prefix . 'Day]"'; |
} else { |
$day_result .= '"' . $prefix . 'Day"'; |
} |
if (null !== $day_size){ |
$day_result .= ' size="' . $day_size . '"'; |
} |
if (null !== $all_extra){ |
$day_result .= ' ' . $all_extra; |
} |
if (null !== $day_extra){ |
$day_result .= ' ' . $day_extra; |
} |
$day_result .= $extra_attrs . '>'."\n"; |
$day_result .= smarty_function_html_options(array('output' => $days, |
'values' => $day_values, |
'selected' => $time[2], |
'print_result' => false), |
$smarty); |
$day_result .= '</select>'; |
} |
if ($display_years) { |
$field_separator_count++; |
if (null !== $field_array){ |
$year_name = $field_array . '[' . $prefix . 'Year]'; |
} else { |
$year_name = $prefix . 'Year'; |
} |
if ($year_as_text) { |
$year_result .= '<input type="text" name="' . $year_name . '" value="' . $time[0] . '" size="4" maxlength="4"'; |
if (null !== $all_extra){ |
$year_result .= ' ' . $all_extra; |
} |
if (null !== $year_extra){ |
$year_result .= ' ' . $year_extra; |
} |
$year_result .= ' />'; |
} else { |
$years = range((int)$start_year, (int)$end_year); |
if ($reverse_years) { |
rsort($years, SORT_NUMERIC); |
} else { |
sort($years, SORT_NUMERIC); |
} |
$yearvals = $years; |
if(isset($year_empty)) { |
array_unshift($years, $year_empty); |
array_unshift($yearvals, ''); |
} |
$year_result .= '<select name="' . $year_name . '"'; |
if (null !== $year_size){ |
$year_result .= ' size="' . $year_size . '"'; |
} |
if (null !== $all_extra){ |
$year_result .= ' ' . $all_extra; |
} |
if (null !== $year_extra){ |
$year_result .= ' ' . $year_extra; |
} |
$year_result .= $extra_attrs . '>'."\n"; |
$year_result .= smarty_function_html_options(array('output' => $years, |
'values' => $yearvals, |
'selected' => $time[0], |
'print_result' => false), |
$smarty); |
$year_result .= '</select>'; |
} |
} |
// Loop thru the field_order field |
for ($i = 0; $i <= 2; $i++){ |
$c = substr($field_order, $i, 1); |
switch ($c){ |
case 'D': |
$html_result .= $day_result; |
break; |
case 'M': |
$html_result .= $month_result; |
break; |
case 'Y': |
$html_result .= $year_result; |
break; |
} |
// Add the field seperator |
if($i < $field_separator_count) { |
$html_result .= $field_separator; |
} |
} |
return $html_result; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.lower.php |
---|
Новый файл |
0,0 → 1,26 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty lower modifier plugin |
* |
* Type: modifier<br> |
* Name: lower<br> |
* Purpose: convert string to lowercase |
* @link http://smarty.php.net/manual/en/language.modifier.lower.php |
* lower (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return string |
*/ |
function smarty_modifier_lower($string) |
{ |
return strtolower($string); |
} |
?> |
/tags/0.1/lib/plugins/shared.escape_special_chars.php |
---|
Новый файл |
0,0 → 1,31 |
<?php |
/** |
* Smarty shared plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* escape_special_chars common function |
* |
* Function: smarty_function_escape_special_chars<br> |
* Purpose: used by other smarty functions to escape |
* special chars except for already escaped ones |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return string |
*/ |
function smarty_function_escape_special_chars($string) |
{ |
if(!is_array($string)) { |
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); |
$string = htmlspecialchars($string); |
$string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string); |
} |
return $string; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/block.textformat.php |
---|
Новый файл |
0,0 → 1,103 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {textformat}{/textformat} block plugin |
* |
* Type: block function<br> |
* Name: textformat<br> |
* Purpose: format text a certain way with preset styles |
* or custom wrap/indent settings<br> |
* @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} |
* (Smarty online manual) |
* @param array |
* <pre> |
* Params: style: string (email) |
* indent: integer (0) |
* wrap: integer (80) |
* wrap_char string ("\n") |
* indent_char: string (" ") |
* wrap_boundary: boolean (true) |
* </pre> |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string contents of the block |
* @param Smarty clever simulation of a method |
* @return string string $content re-formatted |
*/ |
function smarty_block_textformat($params, $content, &$smarty) |
{ |
if (is_null($content)) { |
return; |
} |
$style = null; |
$indent = 0; |
$indent_first = 0; |
$indent_char = ' '; |
$wrap = 80; |
$wrap_char = "\n"; |
$wrap_cut = false; |
$assign = null; |
foreach ($params as $_key => $_val) { |
switch ($_key) { |
case 'style': |
case 'indent_char': |
case 'wrap_char': |
case 'assign': |
$$_key = (string)$_val; |
break; |
case 'indent': |
case 'indent_first': |
case 'wrap': |
$$_key = (int)$_val; |
break; |
case 'wrap_cut': |
$$_key = (bool)$_val; |
break; |
default: |
$smarty->trigger_error("textformat: unknown attribute '$_key'"); |
} |
} |
if ($style == 'email') { |
$wrap = 72; |
} |
// split into paragraphs |
$_paragraphs = preg_split('![\r\n][\r\n]!',$content); |
$_output = ''; |
for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { |
if ($_paragraphs[$_x] == '') { |
continue; |
} |
// convert mult. spaces & special chars to single space |
$_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]); |
// indent first line |
if($indent_first > 0) { |
$_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; |
} |
// wordwrap sentences |
$_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); |
// indent lines |
if($indent > 0) { |
$_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); |
} |
} |
$_output = implode($wrap_char . $wrap_char, $_paragraphs); |
return $assign ? $smarty->assign($assign, $_output) : $_output; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.popup.php |
---|
Новый файл |
0,0 → 1,119 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {popup} function plugin |
* |
* Type: function<br> |
* Name: popup<br> |
* Purpose: make text pop up in windows via overlib |
* @link http://smarty.php.net/manual/en/language.function.popup.php {popup} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array |
* @param Smarty |
* @return string |
*/ |
function smarty_function_popup($params, &$smarty) |
{ |
$append = ''; |
foreach ($params as $_key=>$_value) { |
switch ($_key) { |
case 'text': |
case 'trigger': |
case 'function': |
case 'inarray': |
$$_key = (string)$_value; |
if ($_key == 'function' || $_key == 'inarray') |
$append .= ',' . strtoupper($_key) . ",'$_value'"; |
break; |
case 'caption': |
case 'closetext': |
case 'status': |
$append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'"; |
break; |
case 'fgcolor': |
case 'bgcolor': |
case 'textcolor': |
case 'capcolor': |
case 'closecolor': |
case 'textfont': |
case 'captionfont': |
case 'closefont': |
case 'fgbackground': |
case 'bgbackground': |
case 'caparray': |
case 'capicon': |
case 'background': |
case 'frame': |
$append .= ',' . strtoupper($_key) . ",'$_value'"; |
break; |
case 'textsize': |
case 'captionsize': |
case 'closesize': |
case 'width': |
case 'height': |
case 'border': |
case 'offsetx': |
case 'offsety': |
case 'snapx': |
case 'snapy': |
case 'fixx': |
case 'fixy': |
case 'padx': |
case 'pady': |
case 'timeout': |
case 'delay': |
$append .= ',' . strtoupper($_key) . ",$_value"; |
break; |
case 'sticky': |
case 'left': |
case 'right': |
case 'center': |
case 'above': |
case 'below': |
case 'noclose': |
case 'autostatus': |
case 'autostatuscap': |
case 'fullhtml': |
case 'hauto': |
case 'vauto': |
case 'mouseoff': |
case 'followmouse': |
case 'closeclick': |
if ($_value) $append .= ',' . strtoupper($_key); |
break; |
default: |
$smarty->trigger_error("[popup] unknown parameter $_key", E_USER_WARNING); |
} |
} |
if (empty($text) && !isset($inarray) && empty($function)) { |
$smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required"); |
return false; |
} |
if (empty($trigger)) { $trigger = "onmouseover"; } |
$retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\''; |
$retval .= $append . ');"'; |
if ($trigger == 'onmouseover') |
$retval .= ' onmouseout="nd();"'; |
return $retval; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_radios.php |
---|
Новый файл |
0,0 → 1,156 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_radios} function plugin |
* |
* File: function.html_radios.php<br> |
* Type: function<br> |
* Name: html_radios<br> |
* Date: 24.Feb.2003<br> |
* Purpose: Prints out a list of radio input types<br> |
* Input:<br> |
* - name (optional) - string default "radio" |
* - values (required) - array |
* - options (optional) - associative array |
* - checked (optional) - array default not set |
* - separator (optional) - ie <br> or |
* - output (optional) - the output next to each radio button |
* - assign (optional) - assign the output as an array to this variable |
* Examples: |
* <pre> |
* {html_radios values=$ids output=$names} |
* {html_radios values=$ids name='box' separator='<br>' output=$names} |
* {html_radios values=$ids checked=$checked separator='<br>' output=$names} |
* </pre> |
* @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios} |
* (Smarty online manual) |
* @author Christopher Kvarme <christopher.kvarme@flashjab.com> |
* @author credits to Monte Ohrt <monte at ohrt dot com> |
* @version 1.0 |
* @param array |
* @param Smarty |
* @return string |
* @uses smarty_function_escape_special_chars() |
*/ |
function smarty_function_html_radios($params, &$smarty) |
{ |
require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); |
$name = 'radio'; |
$values = null; |
$options = null; |
$selected = null; |
$separator = ''; |
$labels = true; |
$label_ids = false; |
$output = null; |
$extra = ''; |
foreach($params as $_key => $_val) { |
switch($_key) { |
case 'name': |
case 'separator': |
$$_key = (string)$_val; |
break; |
case 'checked': |
case 'selected': |
if(is_array($_val)) { |
$smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING); |
} else { |
$selected = (string)$_val; |
} |
break; |
case 'labels': |
case 'label_ids': |
$$_key = (bool)$_val; |
break; |
case 'options': |
$$_key = (array)$_val; |
break; |
case 'values': |
case 'output': |
$$_key = array_values((array)$_val); |
break; |
case 'radios': |
$smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING); |
$options = (array)$_val; |
break; |
case 'assign': |
break; |
default: |
if(!is_array($_val)) { |
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; |
} else { |
$smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE); |
} |
break; |
} |
} |
if (!isset($options) && !isset($values)) |
return ''; /* raise error here? */ |
$_html_result = array(); |
if (isset($options)) { |
foreach ($options as $_key=>$_val) |
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids); |
} else { |
foreach ($values as $_i=>$_key) { |
$_val = isset($output[$_i]) ? $output[$_i] : ''; |
$_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids); |
} |
} |
if(!empty($params['assign'])) { |
$smarty->assign($params['assign'], $_html_result); |
} else { |
return implode("\n",$_html_result); |
} |
} |
function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids) { |
$_output = ''; |
if ($labels) { |
if($label_ids) { |
$_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!', '_', $name . '_' . $value)); |
$_output .= '<label for="' . $_id . '">'; |
} else { |
$_output .= '<label>'; |
} |
} |
$_output .= '<input type="radio" name="' |
. smarty_function_escape_special_chars($name) . '" value="' |
. smarty_function_escape_special_chars($value) . '"'; |
if ($labels && $label_ids) $_output .= ' id="' . $_id . '"'; |
if ((string)$value==$selected) { |
$_output .= ' checked="checked"'; |
} |
$_output .= $extra . ' />' . $output; |
if ($labels) $_output .= '</label>'; |
$_output .= $separator; |
return $_output; |
} |
?> |
/tags/0.1/lib/plugins/function.assign_debug_info.php |
---|
Новый файл |
0,0 → 1,40 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {assign_debug_info} function plugin |
* |
* Type: function<br> |
* Name: assign_debug_info<br> |
* Purpose: assign debug info to the template<br> |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, |
* {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} |
* @param Smarty |
*/ |
function smarty_function_assign_debug_info($params, &$smarty) |
{ |
$assigned_vars = $smarty->_tpl_vars; |
ksort($assigned_vars); |
if (@is_array($smarty->_config[0])) { |
$config_vars = $smarty->_config[0]; |
ksort($config_vars); |
$smarty->assign("_debug_config_keys", array_keys($config_vars)); |
$smarty->assign("_debug_config_vals", array_values($config_vars)); |
} |
$included_templates = $smarty->_smarty_debug_info; |
$smarty->assign("_debug_keys", array_keys($assigned_vars)); |
$smarty->assign("_debug_vals", array_values($assigned_vars)); |
$smarty->assign("_debug_tpls", $included_templates); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.html_image.php |
---|
Новый файл |
0,0 → 1,142 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {html_image} function plugin |
* |
* Type: function<br> |
* Name: html_image<br> |
* Date: Feb 24, 2003<br> |
* Purpose: format HTML tags for the image<br> |
* Input:<br> |
* - file = file (and path) of image (required) |
* - height = image height (optional, default actual height) |
* - width = image width (optional, default actual width) |
* - basedir = base directory for absolute paths, default |
* is environment variable DOCUMENT_ROOT |
* - path_prefix = prefix for path output (optional, default empty) |
* |
* Examples: {html_image file="/images/masthead.gif"} |
* Output: <img src="/images/masthead.gif" width=400 height=23> |
* @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @author credits to Duda <duda@big.hu> - wrote first image function |
* in repository, helped with lots of functionality |
* @version 1.0 |
* @param array |
* @param Smarty |
* @return string |
* @uses smarty_function_escape_special_chars() |
*/ |
function smarty_function_html_image($params, &$smarty) |
{ |
require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); |
$alt = ''; |
$file = ''; |
$height = ''; |
$width = ''; |
$extra = ''; |
$prefix = ''; |
$suffix = ''; |
$path_prefix = ''; |
$server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; |
$basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; |
foreach($params as $_key => $_val) { |
switch($_key) { |
case 'file': |
case 'height': |
case 'width': |
case 'dpi': |
case 'path_prefix': |
case 'basedir': |
$$_key = $_val; |
break; |
case 'alt': |
if(!is_array($_val)) { |
$$_key = smarty_function_escape_special_chars($_val); |
} else { |
$smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); |
} |
break; |
case 'link': |
case 'href': |
$prefix = '<a href="' . $_val . '">'; |
$suffix = '</a>'; |
break; |
default: |
if(!is_array($_val)) { |
$extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; |
} else { |
$smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); |
} |
break; |
} |
} |
if (empty($file)) { |
$smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); |
return; |
} |
if (substr($file,0,1) == '/') { |
$_image_path = $basedir . $file; |
} else { |
$_image_path = $file; |
} |
if(!isset($params['width']) || !isset($params['height'])) { |
if(!$_image_data = @getimagesize($_image_path)) { |
if(!file_exists($_image_path)) { |
$smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); |
return; |
} else if(!is_readable($_image_path)) { |
$smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); |
return; |
} else { |
$smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); |
return; |
} |
} |
if ($smarty->security && |
($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && |
(require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && |
(!smarty_core_is_secure($_params, $smarty)) ) { |
$smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); |
} |
if(!isset($params['width'])) { |
$width = $_image_data[0]; |
} |
if(!isset($params['height'])) { |
$height = $_image_data[1]; |
} |
} |
if(isset($params['dpi'])) { |
if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { |
$dpi_default = 72; |
} else { |
$dpi_default = 96; |
} |
$_resize = $dpi_default/$params['dpi']; |
$width = round($width * $_resize); |
$height = round($height * $_resize); |
} |
return $prefix . '<img src="'.$path_prefix.$file.'" alt="'.$alt.'" width="'.$width.'" height="'.$height.'"'.$extra.' />' . $suffix; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.escape.php |
---|
Новый файл |
0,0 → 1,93 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty escape modifier plugin |
* |
* Type: modifier<br> |
* Name: escape<br> |
* Purpose: Escape the string according to escapement type |
* @link http://smarty.php.net/manual/en/language.modifier.escape.php |
* escape (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param html|htmlall|url|quotes|hex|hexentity|javascript |
* @return string |
*/ |
function smarty_modifier_escape($string, $esc_type = 'html', $char_set = 'ISO-8859-1') |
{ |
switch ($esc_type) { |
case 'html': |
return htmlspecialchars($string, ENT_QUOTES, $char_set); |
case 'htmlall': |
return htmlentities($string, ENT_QUOTES, $char_set); |
case 'url': |
return rawurlencode($string); |
case 'urlpathinfo': |
return str_replace('%2F','/',rawurlencode($string)); |
case 'quotes': |
// escape unescaped single quotes |
return preg_replace("%(?<!\\\\)'%", "\\'", $string); |
case 'hex': |
// escape every character into hex |
$return = ''; |
for ($x=0; $x < strlen($string); $x++) { |
$return .= '%' . bin2hex($string[$x]); |
} |
return $return; |
case 'hexentity': |
$return = ''; |
for ($x=0; $x < strlen($string); $x++) { |
$return .= '&#x' . bin2hex($string[$x]) . ';'; |
} |
return $return; |
case 'decentity': |
$return = ''; |
for ($x=0; $x < strlen($string); $x++) { |
$return .= '&#' . ord($string[$x]) . ';'; |
} |
return $return; |
case 'javascript': |
// escape quotes and backslashes, newlines, etc. |
return strtr($string, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n','</'=>'<\/')); |
case 'mail': |
// safe way to display e-mail address on a web page |
return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string); |
case 'nonstd': |
// escape non-standard chars, such as ms document quotes |
$_res = ''; |
for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) { |
$_ord = ord(substr($string, $_i, 1)); |
// non-standard char, escape it |
if($_ord >= 126){ |
$_res .= '&#' . $_ord . ';'; |
} |
else { |
$_res .= substr($string, $_i, 1); |
} |
} |
return $_res; |
default: |
return $string; |
} |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.count_paragraphs.php |
---|
Новый файл |
0,0 → 1,29 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty count_paragraphs modifier plugin |
* |
* Type: modifier<br> |
* Name: count_paragraphs<br> |
* Purpose: count the number of paragraphs in a text |
* @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php |
* count_paragraphs (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @return integer |
*/ |
function smarty_modifier_count_paragraphs($string) |
{ |
// count \r or \n characters |
return count(preg_split('/[\r\n]+/', $string)); |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/compiler.assign.php |
---|
Новый файл |
0,0 → 1,40 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {assign} compiler function plugin |
* |
* Type: compiler function<br> |
* Name: assign<br> |
* Purpose: assign a value to a template variable |
* @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} |
* (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> (initial author) |
* @author messju mohr <messju at lammfellpuschen dot de> (conversion to compiler function) |
* @param string containing var-attribute and value-attribute |
* @param Smarty_Compiler |
*/ |
function smarty_compiler_assign($tag_attrs, &$compiler) |
{ |
$_params = $compiler->_parse_attrs($tag_attrs); |
if (!isset($_params['var'])) { |
$compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING); |
return; |
} |
if (!isset($_params['value'])) { |
$compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING); |
return; |
} |
return "\$this->assign({$_params['var']}, {$_params['value']});"; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/modifier.regex_replace.php |
---|
Новый файл |
0,0 → 1,48 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty regex_replace modifier plugin |
* |
* Type: modifier<br> |
* Name: regex_replace<br> |
* Purpose: regular expression search/replace |
* @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php |
* regex_replace (Smarty online manual) |
* @author Monte Ohrt <monte at ohrt dot com> |
* @param string |
* @param string|array |
* @param string|array |
* @return string |
*/ |
function smarty_modifier_regex_replace($string, $search, $replace) |
{ |
if(is_array($search)) { |
foreach($search as $idx => $s) |
$search[$idx] = _smarty_regex_replace_check($s); |
} else { |
$search = _smarty_regex_replace_check($search); |
} |
return preg_replace($search, $replace, $string); |
} |
function _smarty_regex_replace_check($search) |
{ |
if (($pos = strpos($search,"\0")) !== false) |
$search = substr($search,0,$pos); |
if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) { |
/* remove eval-modifier from $search */ |
$search = substr($search, 0, -strlen($match[1])) . preg_replace('![e\s]+!', '', $match[1]); |
} |
return $search; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/lib/plugins/function.counter.php |
---|
Новый файл |
0,0 → 1,80 |
<?php |
/** |
* Smarty plugin |
* @package Smarty |
* @subpackage plugins |
*/ |
/** |
* Smarty {counter} function plugin |
* |
* Type: function<br> |
* Name: counter<br> |
* Purpose: print out a counter value |
* @author Monte Ohrt <monte at ohrt dot com> |
* @link http://smarty.php.net/manual/en/language.function.counter.php {counter} |
* (Smarty online manual) |
* @param array parameters |
* @param Smarty |
* @return string|null |
*/ |
function smarty_function_counter($params, &$smarty) |
{ |
static $counters = array(); |
$name = (isset($params['name'])) ? $params['name'] : 'default'; |
if (!isset($counters[$name])) { |
$counters[$name] = array( |
'start'=>1, |
'skip'=>1, |
'direction'=>'up', |
'count'=>1 |
); |
} |
$counter =& $counters[$name]; |
if (isset($params['start'])) { |
$counter['start'] = $counter['count'] = (int)$params['start']; |
} |
if (!empty($params['assign'])) { |
$counter['assign'] = $params['assign']; |
} |
if (isset($counter['assign'])) { |
$smarty->assign($counter['assign'], $counter['count']); |
} |
if (isset($params['print'])) { |
$print = (bool)$params['print']; |
} else { |
$print = empty($counter['assign']); |
} |
if ($print) { |
$retval = $counter['count']; |
} else { |
$retval = null; |
} |
if (isset($params['skip'])) { |
$counter['skip'] = $params['skip']; |
} |
if (isset($params['direction'])) { |
$counter['direction'] = $params['direction']; |
} |
if ($counter['direction'] == "down") |
$counter['count'] -= $counter['skip']; |
else |
$counter['count'] += $counter['skip']; |
return $retval; |
} |
/* vim: set expandtab: */ |
?> |
/tags/0.1/oops.php |
---|
Новый файл |
0,0 → 1,7 |
<? |
include "lib/init.php"; |
$smarty->display('oops.tpl'); |
?> |
/tags/0.1/ant.css |
---|
Новый файл |
0,0 → 1,38 |
#ant { |
font: 12pt/20pt Georgia; |
} |
#ant input { |
margin: 0 5px 0 15px; |
font: 12pt Georgia; |
} |
#ant p { |
margin: 0; |
} |
#footer { |
margin: 5px 0; |
padding: 5px 0; |
border-top: 1px solid #a9a9a9; |
font: 10pt Georgia; |
color: #a9a9a9; |
} |
#footer a { |
color: #a9a9a9; |
text-decoration: none; |
} |
pre { |
font: 12pt Arial; |
border: 1px solid #000; |
margin: 10px 0; |
padding: 10px; |
background-color: #dcdcdc; |
} |
#sourceslist { |
font-family: Arial; |
padding: 1px 3px; |
} |