Comparar commits
61 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 0332cda6ad | |||
| d639cee653 | |||
| 506b42ad69 | |||
| e72f6d401c | |||
| 3f1ace7995 | |||
| 36f0ecd678 | |||
| 421b83cff0 | |||
| ceb8640949 | |||
| 76e3b8682c | |||
| cad11337ee | |||
| 49b6ca73e0 | |||
| f7f32dc2a9 | |||
| d787d2cad1 | |||
| 03e7017520 | |||
| cd46249e63 | |||
| 29efccbe27 | |||
| 8d4dafee7e | |||
| 933b5cc8a9 | |||
| 32f5f85937 | |||
| c5891c3e8b | |||
| 004604f027 | |||
| 0198720dbf | |||
| e4c1a81488 | |||
| 728afd7cc3 | |||
| 750950687a | |||
| c54b304d0f | |||
| 490f214b95 | |||
| 4af27736da | |||
| 55ed325afb | |||
| 05467f968e | |||
| 13ce93ab77 | |||
| 476eed0f0f | |||
| d0fb1bbd7f | |||
| 541db733a8 | |||
| e665e811b8 | |||
| 0ecf4b9b4e | |||
| 5afa86ac95 | |||
| 00d825073f | |||
| 9969ff7861 | |||
| cbc1ac46ce | |||
| 4aa2f22387 | |||
| ed5afe1ccd | |||
| ef453a49a8 | |||
| 3c994b5f39 | |||
| 4404c100e6 | |||
| fb00ee196d | |||
| c85fac8289 | |||
| ad022b6c87 | |||
| 211db86d90 | |||
| 031c17a240 | |||
| fdb9e9dfd5 | |||
| 78bf5cb306 | |||
| 1ef34718b2 | |||
| c6d897bc78 | |||
| fb1a623ffa | |||
| 3e0f04afce | |||
| 7499287bfd | |||
| 7bc39b1341 | |||
| 2e75fc328f | |||
| 0c6c62ec4f | |||
| 46d42d4fe3 |
@@ -16,3 +16,4 @@ TODO.rym
|
||||
config-*.php
|
||||
good-config.php
|
||||
*.mo
|
||||
/vendor/
|
||||
|
||||
@@ -146,6 +146,7 @@ This section is a catch-all for site-wide variables.
|
||||
be fine-tuned for notices, messages, profile bios and group descriptions.
|
||||
Zero indicates no limit.
|
||||
|
||||
* favicon: the path to a custom favicon, eg: favicon.png
|
||||
|
||||
db
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -191,14 +192,19 @@ The ones that you may want to set are listed below for clarity.
|
||||
until they get their databases fixed up. See "UTF-8 database" above for
|
||||
details.
|
||||
|
||||
* `schemacheck` (enum["runtime", "script"], default "runtime"): when to let
|
||||
plugins check the database schema to add tables or update them. 'runtime'
|
||||
can be costly (plugins check the schema on every hit, adding potentially
|
||||
several db queries, some quite long), but not everyone knows how to run a
|
||||
script or has the access in their hosting environment to do so. If you can,
|
||||
set this to 'script' and run scripts/checkschema.php whenever you install
|
||||
or upgrade a plugin.
|
||||
* `schemacheck` (enum["runtime", "script"], default "runtime"): when
|
||||
to let plugins check the database schema to add tables or update
|
||||
them. 'runtime' can be costly (plugins check the schema on every
|
||||
hit, adding potentially several db queries, some quite long), but
|
||||
not everyone knows how to run a script or has the access in their
|
||||
hosting environment to do so. If you can, set this to 'script' and
|
||||
run scripts/checkschema.php whenever you install or upgrade a
|
||||
plugin.
|
||||
|
||||
* `x-static-delivery` (string, default null): when a string, use this
|
||||
as the header with wich to serve static files. Possible values are
|
||||
'X-Sendfile' (for Apache and others) and 'X-Accel-Redirect' (for
|
||||
nginx).
|
||||
|
||||
syslog
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -667,6 +673,12 @@ in php.ini to be large enough to handle your upload. In httpd.conf
|
||||
(if you're using apache), check that the LimitRequestBody directive isn't
|
||||
set too low (it's optional, so it may not be there at all).
|
||||
|
||||
* `extblacklist`: associative array to either deny certain extensions or
|
||||
change them to a different one. For example:
|
||||
$config['attachments']['extblacklist']['php'] = 'phps'; // this turns .php into .phps
|
||||
$config['attachments']['extblacklist']['exe'] = false; // this would deny any uploads
|
||||
// of files with the "exe" extension
|
||||
|
||||
* `process_links`: follow redirects and save all available file information
|
||||
(mimetype, date, size, oembed, etc.). Defaults to true.
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#Simple way to Webfinger enable your domain -- needs PHP
|
||||
|
||||
##Step 1
|
||||
|
||||
Put the 'dot-well-known' on your website, so it loads at:
|
||||
|
||||
https://another_cool.org/.well-known/
|
||||
|
||||
(Remember the . at the beginning of this one, which is common practice
|
||||
for "hidden" files and why we have renamed it "dot-")
|
||||
|
||||
## Step 2
|
||||
|
||||
Edit the .well-known/webfinger/index.php file and replace "https://www.example.org/gnusocial/index.php" with the domain name
|
||||
you're hosting the .well-known handler on.
|
||||
@@ -1,56 +0,0 @@
|
||||
Initial simple way to Webfinger enable your domain -- needs PHP.
|
||||
================================================================
|
||||
|
||||
This guide needs some updating, since it will only guide you to present
|
||||
XML data (while the curl command likely gives you JSON). The workaround
|
||||
is to simply make curl get 'webfinger.xml' instead, and/or have another
|
||||
file that contains JSON, but that requires editing the PHP file as well.
|
||||
|
||||
Step 1
|
||||
======
|
||||
|
||||
Put the 'dot-well-known' on your website, so it loads at:
|
||||
|
||||
https://example.com/.well-known/
|
||||
|
||||
(Remember the . at the beginning of this one, which is common practice
|
||||
for "hidden" files and why we have renamed it "dot-")
|
||||
|
||||
Step 2
|
||||
======
|
||||
|
||||
Edit the .well-known/host-meta file and replace "example.com" with the
|
||||
domain name you're hosting the .well-known directory on.
|
||||
|
||||
Using vim you can do this as a quick method:
|
||||
$ vim .well-known/host-meta [ENTER]
|
||||
:%s/example.com/domain.com/ [ENTER]
|
||||
:wq [ENTER]
|
||||
|
||||
Step 3
|
||||
======
|
||||
|
||||
For each user on your site, and this might only be you...
|
||||
|
||||
In the webfinger directory, make a copy of the example@example.com.xml file
|
||||
so that it's called (replace username and example.com with appropriate
|
||||
values, the domain name should be the same as you're "socialifying"):
|
||||
|
||||
username@example.com.xml
|
||||
|
||||
Then edit the file contents, replacing "social.example.com" with your
|
||||
GNU social instance's base path, and change the user ID number (and
|
||||
nickname for the FOAF link) to that of your account on your social
|
||||
site. If you don't know your user ID number, you can see this on your
|
||||
GNU social profile page by looking at the destination URLs in the
|
||||
Feeds links.
|
||||
|
||||
PROTIP: You can get the bulk of the contents (note the <Subject> element though)
|
||||
from curling down your real webfinger data:
|
||||
$ curl https://social.example.com/.well-known/webfinger?resource=acct:username@social.example.com
|
||||
|
||||
Finally
|
||||
=======
|
||||
|
||||
Using this method, though fiddly, you can now be @user@domain without
|
||||
the need for any prefixes for subdomains, etc.
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
|
||||
<Link rel="lrdd" type="application/xrd+xml"
|
||||
template="https://example.com/.well-known/webfinger?resource={uri}"/>
|
||||
</XRD>
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||
<Subject>acct:username@example.com</Subject>
|
||||
<Alias>acct:username@social.example.com</Alias>
|
||||
<Alias>https://social.example.com/user/1</Alias>
|
||||
<Link rel="http://webfinger.net/rel/profile-page"
|
||||
type="text/html"
|
||||
href="https://social.example.com/user/1"/>
|
||||
|
||||
<Link rel="http://schemas.google.com/g/2010#updates-from"
|
||||
type="application/atom+xml"
|
||||
href="https://social.example.com/api/statuses/user_timeline/1.atom"/>
|
||||
|
||||
<!-- Is this/was this ever supported?
|
||||
<Link rel="http://microformats.org/profile/hcard"
|
||||
type="text/html"
|
||||
href="https://social.example.com/hcard"/> -->
|
||||
|
||||
<Link rel="http://gmpg.org/xfn/11"
|
||||
type="text/html"
|
||||
href="https://social.example.com/user/1"/>
|
||||
|
||||
<Link rel="describedby"
|
||||
type="application/rdf+xml"
|
||||
href="https://social.example.com/username/foaf"/>
|
||||
|
||||
<Link rel="http://salmon-protocol.org/ns/salmon-replies"
|
||||
href="https://social.example.com/main/salmon/user/1"/>
|
||||
|
||||
<Link rel="http://salmon-protocol.org/ns/salmon-mention"
|
||||
href="https://social.example.com/main/salmon/user/1"/>
|
||||
|
||||
<Link rel="http://ostatus.org/schema/1.0/subscribe"
|
||||
template="https://social.example.com/main/ostatussub?profile={uri}"/>
|
||||
</XRD>
|
||||
+30
-38
@@ -1,43 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* GNU social
|
||||
* Copyright (C) 2010, Free Software Foundation, Inc
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// FIXME: REPLACE \/ here
|
||||
define('MY_GNUSOCIAL', 'https://www.example.org/gnusocial/index.php');
|
||||
|
||||
/**
|
||||
* This is a general solution for when you can't have your GNU social instance in the domain root and for when you want to
|
||||
* socialfy from another domain.
|
||||
*/
|
||||
|
||||
|
||||
// basename should make sure we can't escape this directory
|
||||
$u = basename($_GET['resource']);
|
||||
|
||||
if (!strpos($u, '@')) {
|
||||
throw new Exception('Bad resource');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mb_strpos($u, 'acct:')===0) {
|
||||
$u = substr($u, 5);
|
||||
}
|
||||
|
||||
// Just to be a little bit safer, you know, with all the unicode stuff going on
|
||||
$u = filter_var($u, FILTER_SANITIZE_EMAIL);
|
||||
|
||||
$f = $u . ".xml";
|
||||
|
||||
if (file_exists($f)) {
|
||||
header('Content-Disposition: attachment; filename="'.urlencode($f).'"');
|
||||
header('Content-type: application/xrd+xml');
|
||||
echo file_get_contents($f);
|
||||
if (!function_exists('getallheaders')) {
|
||||
function getallheaders()
|
||||
{
|
||||
$headers = [];
|
||||
foreach ($_SERVER as $name => $value) {
|
||||
if (substr($name, 0, 5) == 'HTTP_') {
|
||||
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, getallheaders());
|
||||
curl_setopt($ch, CURLOPT_URL, MY_GNUSOCIAL . str_replace('webfinger/', 'webfinger', $_SERVER['REQUEST_URI']));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
$response = curl_exec($ch);
|
||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($response, 0, $header_size);
|
||||
$body = substr($response, $header_size);
|
||||
header($header);
|
||||
echo $body;
|
||||
curl_close($ch);
|
||||
@@ -7,6 +7,9 @@ plugin_mo = $(patsubst %.po,%.mo,$(wildcard plugins/*/locale/*/LC_MESSAGES/*.po)
|
||||
|
||||
translations : $(core_mo) $(plugin_mo)
|
||||
|
||||
upgrade :
|
||||
php scripts/upgrade.php
|
||||
|
||||
clean :
|
||||
rm -f $(core_mo) $(plugin_mo)
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# GNU social 1.20.x
|
||||
# GNU social 2.0.x
|
||||
(c) 2010-2019 Free Software Foundation, Inc
|
||||
|
||||
This is the README file for GNU social, the free
|
||||
|
||||
+105
-6
@@ -41,9 +41,8 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
class AttachmentAction extends ManagedAction
|
||||
{
|
||||
/**
|
||||
* Attachment object to show
|
||||
* Attachment File object to show
|
||||
*/
|
||||
|
||||
var $attachment = null;
|
||||
|
||||
/**
|
||||
@@ -60,14 +59,25 @@ class AttachmentAction extends ManagedAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($id = $this->trimmed('attachment')) {
|
||||
$this->attachment = File::getKV($id);
|
||||
try {
|
||||
if (!empty($id = $this->trimmed('attachment'))) {
|
||||
$this->attachment = File::getByID($id);
|
||||
} elseif (!empty($filehash = $this->trimmed('filehash'))) {
|
||||
$this->attachment = File::getByHash($filehash);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Not found
|
||||
}
|
||||
|
||||
if (!$this->attachment instanceof File) {
|
||||
// TRANS: Client error displayed trying to get a non-existing attachment.
|
||||
$this->clientError(_('No such attachment.'), 404);
|
||||
}
|
||||
|
||||
$filename = $this->attachment->getFileOrThumbnailPath();
|
||||
|
||||
if (empty($filename)) {
|
||||
$this->clientError(_('Requested local URL for a file that is not stored locally.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -94,7 +104,7 @@ class AttachmentAction extends ManagedAction
|
||||
|
||||
public function showPage()
|
||||
{
|
||||
if (empty($this->attachment->filename)) {
|
||||
if (empty($this->attachment->getFileOrThumbnailPath())) {
|
||||
// if it's not a local file, gtfo
|
||||
common_redirect($this->attachment->getUrl(), 303);
|
||||
}
|
||||
@@ -133,4 +143,93 @@ class AttachmentAction extends ManagedAction
|
||||
$ns = new AttachmentNoticeSection($this);
|
||||
$ns->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-modified date for file
|
||||
*
|
||||
* @return int last-modified date as unix timestamp
|
||||
*/
|
||||
public function lastModified()
|
||||
{
|
||||
if (common_config('site', 'use_x_sendfile')) {
|
||||
return null;
|
||||
}
|
||||
$path = $this->attachment->getFileOrThumbnailPath();
|
||||
if (!empty($path)) {
|
||||
return filemtime($path);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* etag header for file
|
||||
*
|
||||
* This returns the same data (inode, size, mtime) as Apache would,
|
||||
* but in decimal instead of hex.
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (common_config('site', 'use_x_sendfile')) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$path = $this->attachment->getFileOrThumbnailPath();
|
||||
|
||||
$cache = Cache::instance();
|
||||
if($cache) {
|
||||
if (empty($path)) {
|
||||
return null;
|
||||
}
|
||||
$key = Cache::key('attachments:etag:' . $path);
|
||||
$etag = $cache->get($key);
|
||||
if($etag === false) {
|
||||
$etag = crc32(file_get_contents($path));
|
||||
$cache->set($key,$etag);
|
||||
}
|
||||
return $etag;
|
||||
}
|
||||
|
||||
if (!empty($path)) {
|
||||
$stat = stat($path);
|
||||
return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Include $filepath in the response, for viewing and downloading.
|
||||
* If provided, $filesize is used to size the HTTP request,
|
||||
* otherwise it's value is calculated
|
||||
* @param string $filepath the absolute path to the file to send
|
||||
* @param $filesize optional, calculated if unkown
|
||||
*/
|
||||
static function sendFile(string $filepath, $filesize) {
|
||||
if (is_string(common_config('site', 'x-static-delivery'))) {
|
||||
$tmp = explode(INSTALLDIR, $filepath);
|
||||
$relative_path = end($tmp);
|
||||
common_debug("Using Static Delivery with header: '" .
|
||||
common_config('site', 'x-static-delivery') . ": {$relative_path}'");
|
||||
header(common_config('site', 'x-static-delivery') . ": {$relative_path}");
|
||||
} else {
|
||||
if (empty($filesize)) {
|
||||
$filesize = filesize($filepath);
|
||||
}
|
||||
header("Content-Length: {$filesize}");
|
||||
// header('Cache-Control: private, no-transform, no-store, must-revalidate');
|
||||
|
||||
$ret = @readfile($filepath);
|
||||
|
||||
if ($ret === false) {
|
||||
common_log(LOG_ERR, "Couldn't read file at {$filepath}.");
|
||||
} elseif ($ret !== $filesize) {
|
||||
common_log(LOG_ERR, "The lengths of the file as recorded on the DB (or on disk) for the file " .
|
||||
"{$filepath} differ from what was sent to the user ({$filesize} vs {$ret}).");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,28 @@ class Attachment_downloadAction extends AttachmentAction
|
||||
{
|
||||
public function showPage()
|
||||
{
|
||||
common_redirect($this->attachment->getUrl(), 302);
|
||||
// Checks file exists or throws FileNotFoundException
|
||||
$filepath = $this->attachment->getFileOrThumbnailPath();
|
||||
$filesize = $this->attachment->getFileOrThumbnailSize();
|
||||
$mimetype = $this->attachment->getFileOrThumbnailMimetype();
|
||||
|
||||
if (empty($filepath)) {
|
||||
$this->clientError(_('No such attachment'), 404);
|
||||
}
|
||||
|
||||
$filename = MediaFile::getDisplayName($this->attachment);
|
||||
|
||||
// Disable errors, to not mess with the file contents (suppress errors in case access to this
|
||||
// function is blocked, like in some shared hosts). Automatically reset at the end of the
|
||||
// script execution, and we don't want to have any more errors until then, so don't reset it
|
||||
@ini_set('display_errors', 0);
|
||||
|
||||
header("Content-Description: File Transfer");
|
||||
header("Content-Type: {$mimetype}");
|
||||
header("Content-Disposition: attachment; filename=\"{$filename}\"");
|
||||
header('Expires: 0');
|
||||
header('Content-Transfer-Encoding: binary'); // FIXME? Can this be different?
|
||||
|
||||
AttachmentAction::sendFile($filepath, $filesize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +53,43 @@ class Attachment_thumbnailAction extends AttachmentAction
|
||||
$this->thumb_c = $this->boolean('c');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an inline representation of an attachment of the size
|
||||
* requested in the GET variables (read in the constructor). Tries
|
||||
* to send the most appropriate file with the correct size and
|
||||
* headers or displays an error if it's not possible.
|
||||
*/
|
||||
public function showPage()
|
||||
{
|
||||
|
||||
// Returns a File_thumbnail object or throws exception if not available
|
||||
try {
|
||||
$thumbnail = $this->attachment->getThumbnail($this->thumb_w, $this->thumb_h, $this->thumb_c);
|
||||
$file = $thumbnail->getFile();
|
||||
} catch (UseFileAsThumbnailException $e) {
|
||||
common_redirect($e->file->getUrl(), 302);
|
||||
// With this exception, the file exists locally
|
||||
$file = $e->file;
|
||||
} catch(FileNotFoundException $e) {
|
||||
$this->clientError(_('No such attachment'), 404);
|
||||
}
|
||||
|
||||
common_redirect(File_thumbnail::url($thumbnail->getFilename()), 302);
|
||||
// Checks file exists or throws FileNotFoundException
|
||||
$filepath = $file->getFileOrThumbnailPath($thumbnail);
|
||||
$filesize = $this->attachment->getFileOrThumbnailSize($thumbnail);
|
||||
$mimetype = $file->getFileOrThumbnailMimetype($thumbnail);
|
||||
$filename = MediaFile::getDisplayName($file);
|
||||
|
||||
// Disable errors, to not mess with the file contents (suppress errors in case access to this
|
||||
// function is blocked, like in some shared hosts). Automatically reset at the end of the
|
||||
// script execution, and we don't want to have any more errors until then, so don't reset it
|
||||
@ini_set('display_errors', 0);
|
||||
|
||||
header("Content-Description: File Transfer");
|
||||
header("Content-Type: {$mimetype}");
|
||||
header("Content-Disposition: inline; filename=\"{$filename}\"");
|
||||
header('Expires: 0');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
|
||||
AttachmentAction::sendFile($filepath, $filesize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* View notice attachment
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @author Miguel Dantas <biodantasgs@gmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
*/
|
||||
class Attachment_viewAction extends AttachmentAction
|
||||
{
|
||||
public function showPage()
|
||||
{
|
||||
// Checks file exists or throws FileNotFoundException
|
||||
$filepath = $this->attachment->getFileOrThumbnailPath();
|
||||
$filesize = $this->attachment->getFileOrThumbnailSize();
|
||||
$mimetype = $this->attachment->getFileOrThumbnailMimetype();
|
||||
|
||||
if (empty($filepath)) {
|
||||
$this->clientError(_('No such attachment'), 404);
|
||||
}
|
||||
|
||||
$filename = MediaFile::getDisplayName($this->attachment);
|
||||
|
||||
// Disable errors, to not mess with the file contents (suppress errors in case access to this
|
||||
// function is blocked, like in some shared hosts). Automatically reset at the end of the
|
||||
// script execution, and we don't want to have any more errors until then, so don't reset it
|
||||
@ini_set('display_errors', 0);
|
||||
|
||||
header("Content-Description: File Transfer");
|
||||
header("Content-Type: {$mimetype}");
|
||||
if (in_array(common_get_mime_media($mimetype), ['image', 'video'])) {
|
||||
header("Content-Disposition: inline; filename=\"{$filename}\"");
|
||||
} else {
|
||||
header("Content-Disposition: attachment; filename=\"{$filename}\"");
|
||||
}
|
||||
header('Expires: 0');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
|
||||
AttachmentAction::sendFile($filepath, $filesize);
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2009, StatusNet, Inc.
|
||||
*
|
||||
* Return a requested file
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category PrivateAttachments
|
||||
* @package StatusNet
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* An action for returning a requested file
|
||||
*
|
||||
* The StatusNet system will do an implicit user check if the site is
|
||||
* private before allowing this to continue
|
||||
*
|
||||
* @category PrivateAttachments
|
||||
* @package StatusNet
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class GetfileAction extends Action
|
||||
{
|
||||
/**
|
||||
* Path of file to return
|
||||
*/
|
||||
var $path = null;
|
||||
|
||||
/**
|
||||
* Get file name
|
||||
*
|
||||
* @param array $args $_REQUEST array
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$filename = $this->trimmed('filename');
|
||||
$path = null;
|
||||
|
||||
if ($filename && File::validFilename($filename)) {
|
||||
$path = File::path($filename);
|
||||
}
|
||||
|
||||
if (empty($path) or !file_exists($path)) {
|
||||
// TRANS: Client error displayed when requesting a non-existent file.
|
||||
$this->clientError(_('No such file.'), 404);
|
||||
}
|
||||
if (!is_readable($path)) {
|
||||
// TRANS: Client error displayed when requesting a file without having read access to it.
|
||||
$this->clientError(_('Cannot read file.'), 403);
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this page read-only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-modified date for file
|
||||
*
|
||||
* @return int last-modified date as unix timestamp
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (common_config('site', 'use_x_sendfile')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return filemtime($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* etag for file
|
||||
*
|
||||
* This returns the same data (inode, size, mtime) as Apache would,
|
||||
* but in decimal instead of hex.
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (common_config('site', 'use_x_sendfile')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cache = Cache::instance();
|
||||
if($cache) {
|
||||
$key = Cache::key('attachments:etag:' . $this->path);
|
||||
$etag = $cache->get($key);
|
||||
if($etag === false) {
|
||||
$etag = crc32(file_get_contents($this->path));
|
||||
$cache->set($key,$etag);
|
||||
}
|
||||
return $etag;
|
||||
}
|
||||
|
||||
$stat = stat($this->path);
|
||||
return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
// undo headers set by PHP sessions
|
||||
$sec = session_cache_expire() * 60;
|
||||
header('Expires: ' . date(DATE_RFC1123, time() + $sec));
|
||||
header('Cache-Control: max-age=' . $sec);
|
||||
|
||||
parent::handle();
|
||||
|
||||
$path = $this->path;
|
||||
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
|
||||
header('Content-Type: ' . $finfo->file($path));
|
||||
|
||||
if (common_config('site', 'use_x_sendfile')) {
|
||||
header('X-Sendfile: ' . $path);
|
||||
} else {
|
||||
header('Content-Length: ' . filesize($path));
|
||||
readfile($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
+132
-29
@@ -127,11 +127,11 @@ class File extends Managed_DataObject
|
||||
$args = $r->map(mb_substr($u['path'], 1));
|
||||
if ($args['action'] === 'attachment') {
|
||||
try {
|
||||
// $args['attachment'] should always be set if action===attachment, given our routing rules
|
||||
$file = File::getByID($args['attachment']);
|
||||
return $file;
|
||||
} catch (EmptyPkeyValueException $e) {
|
||||
// ...but $args['attachment'] can also be 0...
|
||||
if (!empty($args['attachment'])) {
|
||||
return File::getByID($args['attachment']);
|
||||
} elseif ($args['filehash']) {
|
||||
return File::getByHash($args['filehash']);
|
||||
}
|
||||
} catch (NoResultException $e) {
|
||||
// apparently this link goes to us, but is _not_ an existing attachment (File) ID?
|
||||
}
|
||||
@@ -336,6 +336,35 @@ class File extends Managed_DataObject
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return string|bool Value from the 'extblacklist' array, in the config
|
||||
*/
|
||||
public static function getSafeExtension(string $filename) {
|
||||
if (preg_match('/^.+?\.([A-Za-z0-9]+)$/', $filename, $matches) === 1) {
|
||||
// we matched on a file extension, so let's see if it means something.
|
||||
common_debug("MATCHES EXT: " . print_r($matches, true));
|
||||
$ext = mb_strtolower($matches[1]);
|
||||
$blacklist = common_config('attachments', 'extblacklist');
|
||||
// If we got an extension from $filename we want to check if it's in a blacklist
|
||||
// so we avoid people uploading restricted files
|
||||
if (array_key_exists($ext, $blacklist)) {
|
||||
if (!is_string($blacklist[$ext])) {
|
||||
// Blocked
|
||||
return false;
|
||||
}
|
||||
// return a safe replacement extension ('php' => 'phps' for example)
|
||||
return $blacklist[$ext];
|
||||
} else {
|
||||
// the attachment extension based on its filename was not blacklisted so it's ok to use it
|
||||
return $ext;
|
||||
}
|
||||
} else {
|
||||
// No extension
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $mimetype string The mimetype we've discovered for this file.
|
||||
* @param $filename string An optional filename which we can use on failure.
|
||||
@@ -351,28 +380,16 @@ class File extends Managed_DataObject
|
||||
return $ext;
|
||||
} catch (UnknownMimeExtensionException $e) {
|
||||
// We don't know the extension for this mimetype, but let's guess.
|
||||
|
||||
// If we can't recognize the extension from the MIME, we try
|
||||
// to guess based on filename, if one was supplied.
|
||||
if (!is_null($filename) && preg_match('/^.+\.([A-Za-z0-9]+)$/', $filename, $matches)) {
|
||||
// we matched on a file extension, so let's see if it means something.
|
||||
$ext = mb_strtolower($matches[1]);
|
||||
|
||||
$blacklist = common_config('attachments', 'extblacklist');
|
||||
// If we got an extension from $filename we want to check if it's in a blacklist
|
||||
// so we avoid people uploading .php files etc.
|
||||
if (array_key_exists($ext, $blacklist)) {
|
||||
if (!is_string($blacklist[$ext])) {
|
||||
// we don't have a safe replacement extension
|
||||
throw new ClientException(_('Blacklisted file extension.'));
|
||||
}
|
||||
common_debug('Found replaced extension for filename '._ve($filename).': '._ve($ext));
|
||||
|
||||
// return a safe replacement extension ('php' => 'phps' for example)
|
||||
return $blacklist[$ext];
|
||||
if (!is_null($filename)) {
|
||||
$ext = getSafeExtension($filename);
|
||||
if ($ext === false) {
|
||||
// we don't have a safe replacement extension
|
||||
throw new ClientException(_('Blacklisted file extension.'));
|
||||
} else {
|
||||
return $ext;
|
||||
}
|
||||
// the attachment extension based on its filename was not blacklisted so it's ok to use it
|
||||
return $ext;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_INFO, 'Problem when figuring out extension for mimetype: '._ve($e));
|
||||
@@ -381,9 +398,9 @@ class File extends Managed_DataObject
|
||||
// If nothing else has given us a result, try to extract it from
|
||||
// the mimetype value (this turns .jpg to .jpeg for example...)
|
||||
$matches = array();
|
||||
// FIXME: try to build a regexp that will get jpeg from image/jpeg as well as json from application/jrd+json
|
||||
if (!preg_match('/\/([a-z0-9]+)/', mb_strtolower($mimetype), $matches)) {
|
||||
throw new Exception('Malformed mimetype: '.$mimetype);
|
||||
// Will get jpeg from image/jpeg as well as json from application/jrd+json
|
||||
if (!preg_match('/[\/+-\.]([a-z0-9]+)/', mb_strtolower($mimetype), $matches)) {
|
||||
throw new Exception("Malformed mimetype: {$mimetype}");
|
||||
}
|
||||
return mb_strtolower($matches[1]);
|
||||
}
|
||||
@@ -576,11 +593,97 @@ class File extends Managed_DataObject
|
||||
return $filepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to either a file, or it's thumbnail if the file doesn't exist.
|
||||
* This is useful in case the original file is deleted, or, as is the case for Embed
|
||||
* thumbnails, we only have a thumbnail and not a file
|
||||
* @return string Path
|
||||
* @throws FileNotFoundException
|
||||
* @throws FileNotStoredLocallyException
|
||||
* @throws InvalidFilenameException
|
||||
* @throws ServerException
|
||||
*/
|
||||
public function getFileOrThumbnailPath($thumbnail = null) : string
|
||||
{
|
||||
if (!empty($thumbnail)) {
|
||||
return $thumbnail->getPath();
|
||||
}
|
||||
if (!empty($this->filename)) {
|
||||
$filepath = self::path($this->filename);
|
||||
if (file_exists($filepath)) {
|
||||
return $filepath;
|
||||
} else {
|
||||
throw new FileNotFoundException($filepath);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return File_thumbnail::byFile($this, true)->getPath();
|
||||
} catch (NoResultException $e) {
|
||||
// File not stored locally
|
||||
throw new FileNotStoredLocallyException($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mime type of the thumbnail if we have it, or, if not, of the File
|
||||
* @return string
|
||||
* @throws FileNotFoundException
|
||||
* @throws NoResultException
|
||||
* @throws ServerException
|
||||
* @throws UnsupportedMediaException
|
||||
*/
|
||||
public function getFileOrThumbnailMimetype($thumbnail = null) : string
|
||||
{
|
||||
if (!empty($thumbnail)) {
|
||||
$filepath = $thumbnail->getPath();
|
||||
} elseif (!empty($this->filename)) {
|
||||
return $this->mimetype;
|
||||
} else {
|
||||
$filepath = File_thumbnail::byFile($this, true)->getPath();
|
||||
}
|
||||
|
||||
$info = @getimagesize($filepath);
|
||||
if ($info !== false) {
|
||||
return $info['mime'];
|
||||
} else {
|
||||
throw new UnsupportedMediaException(_("Thumbnail is not an image."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the thumbnail if we have it, or, if not, of the File
|
||||
* @return int
|
||||
* @throws FileNotFoundException
|
||||
* @throws NoResultException
|
||||
* @throws ServerException
|
||||
*/
|
||||
public function getFileOrThumbnailSize($thumbnail = null) : int
|
||||
{
|
||||
if (!empty($thumbnail)) {
|
||||
return filesize($thumbnail->getPath());
|
||||
} elseif (!empty($this->filename)) {
|
||||
return $this->size;
|
||||
} else {
|
||||
return filesize(File_thumbnail::byFile($this)->getPath());
|
||||
}
|
||||
}
|
||||
|
||||
public function getAttachmentUrl()
|
||||
{
|
||||
return common_local_url('attachment', array('attachment'=>$this->getID()));
|
||||
}
|
||||
|
||||
public function getAttachmentDownloadUrl()
|
||||
{
|
||||
return common_local_url('attachment_download', array('attachment'=>$this->getID()));
|
||||
}
|
||||
|
||||
public function getAttachmentViewUrl()
|
||||
{
|
||||
return common_local_url('attachment_view', array('attachment'=>$this->getID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $use_local true means require local, null means prefer local, false means use whatever is stored
|
||||
* @return string
|
||||
@@ -591,7 +694,7 @@ class File extends Managed_DataObject
|
||||
if ($use_local !== false) {
|
||||
if (is_string($this->filename) || !empty($this->filename)) {
|
||||
// A locally stored file, so let's generate a URL for our instance.
|
||||
return self::url($this->getFilename());
|
||||
return $this->getAttachmentViewUrl();
|
||||
}
|
||||
if ($use_local) {
|
||||
// if the file wasn't stored locally (has filename) and we require a local URL
|
||||
@@ -746,7 +849,7 @@ class File extends Managed_DataObject
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
$title = $this->title ?: $this->filename;
|
||||
$title = $this->title ?: MediaFile::getDisplayName($this);
|
||||
|
||||
return $title ?: null;
|
||||
}
|
||||
|
||||
@@ -172,9 +172,9 @@ class File_thumbnail extends Managed_DataObject
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string full filesystem path to the locally stored thumbnail file
|
||||
* @throws
|
||||
* @throws FileNotFoundException
|
||||
* @throws ServerException
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
@@ -244,11 +244,9 @@ class File_thumbnail extends Managed_DataObject
|
||||
*/
|
||||
public function getHtmlAttrs(array $orig=array(), $overwrite=true)
|
||||
{
|
||||
$attrs = [
|
||||
'height' => $this->getHeight(),
|
||||
'width' => $this->getWidth(),
|
||||
'src' => $this->getUrl(),
|
||||
];
|
||||
$attrs = [ 'height' => $this->getHeight(),
|
||||
'width' => $this->getWidth(),
|
||||
'src' => $this->getUrl() ];
|
||||
return $overwrite ? array_merge($orig, $attrs) : array_merge($attrs, $orig);
|
||||
}
|
||||
|
||||
|
||||
+1160
-168
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -42,9 +42,9 @@ class Status_network extends Safe_DataObject
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
static function getKV($k,$v=NULL) {
|
||||
static function getKV($k, $v=NULL) {
|
||||
// TODO: This must probably be turned into a non-static call
|
||||
$i = DB_DataObject::staticGet('Status_network',$k,$v);
|
||||
$i = GS_DataObject::staticGet('Status_network',$k,$v);
|
||||
|
||||
// Don't use local process cache; if we're fetching multiple
|
||||
// times it's because we're reloading it in a long-running
|
||||
@@ -64,17 +64,24 @@ class Status_network extends Safe_DataObject
|
||||
static $wildcard = null;
|
||||
|
||||
/**
|
||||
* @param string $dbscheme
|
||||
* @param string $dbhost
|
||||
* @param string $dbuser
|
||||
* @param string $dbpass
|
||||
* @param string $dbname
|
||||
* @param array $servers memcached servers to use for caching config info
|
||||
*/
|
||||
static function setupDB($dbhost, $dbuser, $dbpass, $dbname, array $servers)
|
||||
static function setupDB(string $dbscheme, string $dbhost, string $dbuser, string $dbpass, string $dbname, array $servers)
|
||||
{
|
||||
global $config;
|
||||
|
||||
$config['db']['database_'.$dbname] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname";
|
||||
if (empty($dbpass)) {
|
||||
$auth = '';
|
||||
} else {
|
||||
$auth = ":$dbpass";
|
||||
}
|
||||
|
||||
$config['db']['database_'.$dbname] = "{$dbscheme}://{$dbuser}{$auth}@{$dbhost}/{$dbname}";
|
||||
$config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/status_network.ini';
|
||||
|
||||
foreach (array('status_network', 'status_network_tag', 'unavailable_status_network') as $table) {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "gnusocial/gnusocial",
|
||||
"description": "Free software social networking platform.",
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0-only",
|
||||
"require": {
|
||||
"php": "^7.0.0",
|
||||
"ext-bcmath": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"apereo/phpcas": "^1.3",
|
||||
"diogocomposer/xmpphp": "^3.0",
|
||||
"embed/embed": "^3.4",
|
||||
"doctrine/dbal": "^2.5",
|
||||
"ezyang/htmlpurifier": "^4.10",
|
||||
"hoa/consistency": "^1.17.05.02",
|
||||
"masterminds/html5": "^2.6",
|
||||
"mf2/mf2": "^0.4.6",
|
||||
"michelf/php-markdown": "^1.8.0",
|
||||
"openid/php-openid": "^2.3",
|
||||
"paragonie/constant_time_encoding": "^1.0.4",
|
||||
"pear/console_getopt": "^1.4",
|
||||
"phpseclib/phpseclib": "dev-master#f815e43077da67d3dd5b4d18a45753f5b79c1ab9",
|
||||
"stomp-php/stomp-php": "^4.5.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpdocumentor/phpdocumentor": "^2.9",
|
||||
"phpunit/phpunit": "^6.5",
|
||||
"psy/psysh": "^0.9.9"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-apache": "*",
|
||||
"ext-gmp": "*",
|
||||
"ext-http": "*",
|
||||
"ext-xmlrpc": "*",
|
||||
"ext-pgsql": "*",
|
||||
"ext-mysql": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-sqlite": "*",
|
||||
"ext-posix": "*",
|
||||
"ext-readline": "*",
|
||||
"ext-pcntl": "*",
|
||||
"ext-ldap": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-interbase": "*",
|
||||
"ext-imagick": "*",
|
||||
"ext-imap": "*",
|
||||
"ext-exif": "*",
|
||||
"ext-mailparse": "*",
|
||||
"ext-oci8": "*",
|
||||
"ext-memcached": "*",
|
||||
"ext-memcache": "*",
|
||||
"ext-mssql": "*",
|
||||
"ext-odbc": "*",
|
||||
"ext-zlib": "*",
|
||||
"ext-sybase": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-libxml": "*"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"platform": {
|
||||
"php": "7.0.0"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-update-cmd": [
|
||||
"@php scripts/upgrade.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
gerado
+5865
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: SASL.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* Client implementation of various SASL mechanisms
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('PEAR.php');
|
||||
|
||||
class Auth_SASL
|
||||
{
|
||||
/**
|
||||
* Factory class. Returns an object of the request
|
||||
* type.
|
||||
*
|
||||
* @param string $type One of: Anonymous
|
||||
* Plain
|
||||
* CramMD5
|
||||
* DigestMD5
|
||||
* Types are not case sensitive
|
||||
*/
|
||||
function &factory($type)
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case 'anonymous':
|
||||
$filename = 'Auth/SASL/Anonymous.php';
|
||||
$classname = 'Auth_SASL_Anonymous';
|
||||
break;
|
||||
|
||||
case 'login':
|
||||
$filename = 'Auth/SASL/Login.php';
|
||||
$classname = 'Auth_SASL_Login';
|
||||
break;
|
||||
|
||||
case 'plain':
|
||||
$filename = 'Auth/SASL/Plain.php';
|
||||
$classname = 'Auth_SASL_Plain';
|
||||
break;
|
||||
|
||||
case 'external':
|
||||
$filename = 'Auth/SASL/External.php';
|
||||
$classname = 'Auth_SASL_External';
|
||||
break;
|
||||
|
||||
case 'crammd5':
|
||||
$filename = 'Auth/SASL/CramMD5.php';
|
||||
$classname = 'Auth_SASL_CramMD5';
|
||||
break;
|
||||
|
||||
case 'digestmd5':
|
||||
$filename = 'Auth/SASL/DigestMD5.php';
|
||||
$classname = 'Auth_SASL_DigestMD5';
|
||||
break;
|
||||
|
||||
default:
|
||||
return PEAR::raiseError('Invalid SASL mechanism type');
|
||||
break;
|
||||
}
|
||||
|
||||
require_once($filename);
|
||||
$obj = new $classname();
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: Anonymous.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* Implmentation of ANONYMOUS SASL mechanism
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_Anonymous extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Not much to do here except return the token supplied.
|
||||
* No encoding, hashing or encryption takes place for this
|
||||
* mechanism, simply one of:
|
||||
* o An email address
|
||||
* o An opaque string not containing "@" that can be interpreted
|
||||
* by the sysadmin
|
||||
* o Nothing
|
||||
*
|
||||
* We could have some logic here for the second option, but this
|
||||
* would by no means create something interpretable.
|
||||
*
|
||||
* @param string $token Optional email address or string to provide
|
||||
* as trace information.
|
||||
* @return string The unaltered input token
|
||||
*/
|
||||
function getResponse($token = '')
|
||||
{
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: Common.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* Common functionality to SASL mechanisms
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
class Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Function which implements HMAC MD5 digest
|
||||
*
|
||||
* @param string $key The secret key
|
||||
* @param string $data The data to protect
|
||||
* @return string The HMAC MD5 digest
|
||||
*/
|
||||
function _HMAC_MD5($key, $data)
|
||||
{
|
||||
if (strlen($key) > 64) {
|
||||
$key = pack('H32', md5($key));
|
||||
}
|
||||
|
||||
if (strlen($key) < 64) {
|
||||
$key = str_pad($key, 64, chr(0));
|
||||
}
|
||||
|
||||
$k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
|
||||
$k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
|
||||
|
||||
$inner = pack('H32', md5($k_ipad . $data));
|
||||
$digest = md5($k_opad . $inner);
|
||||
|
||||
return $digest;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: CramMD5.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* Implmentation of CRAM-MD5 SASL mechanism
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_CramMD5 extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Implements the CRAM-MD5 SASL mechanism
|
||||
* This DOES NOT base64 encode the return value,
|
||||
* you will need to do that yourself.
|
||||
*
|
||||
* @param string $user Username
|
||||
* @param string $pass Password
|
||||
* @param string $challenge The challenge supplied by the server.
|
||||
* this should be already base64_decoded.
|
||||
*
|
||||
* @return string The string to pass back to the server, of the form
|
||||
* "<user> <digest>". This is NOT base64_encoded.
|
||||
*/
|
||||
function getResponse($user, $pass, $challenge)
|
||||
{
|
||||
return $user . ' ' . $this->_HMAC_MD5($pass, $challenge);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,197 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: DigestMD5.php 294702 2010-02-07 16:03:55Z cweiske $
|
||||
|
||||
/**
|
||||
* Implmentation of DIGEST-MD5 SASL mechanism
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_DigestMD5 extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Provides the (main) client response for DIGEST-MD5
|
||||
* requires a few extra parameters than the other
|
||||
* mechanisms, which are unavoidable.
|
||||
*
|
||||
* @param string $authcid Authentication id (username)
|
||||
* @param string $pass Password
|
||||
* @param string $challenge The digest challenge sent by the server
|
||||
* @param string $hostname The hostname of the machine you're connecting to
|
||||
* @param string $service The servicename (eg. imap, pop, acap etc)
|
||||
* @param string $authzid Authorization id (username to proxy as)
|
||||
* @return string The digest response (NOT base64 encoded)
|
||||
* @access public
|
||||
*/
|
||||
function getResponse($authcid, $pass, $challenge, $hostname, $service, $authzid = '')
|
||||
{
|
||||
$challenge = $this->_parseChallenge($challenge);
|
||||
$authzid_string = '';
|
||||
if ($authzid != '') {
|
||||
$authzid_string = ',authzid="' . $authzid . '"';
|
||||
}
|
||||
|
||||
if (!empty($challenge)) {
|
||||
$cnonce = $this->_getCnonce();
|
||||
$digest_uri = sprintf('%s/%s', $service, $hostname);
|
||||
$response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid);
|
||||
|
||||
if ($challenge['realm']) {
|
||||
return sprintf('username="%s",realm="%s"' . $authzid_string .
|
||||
',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
|
||||
} else {
|
||||
return sprintf('username="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
|
||||
}
|
||||
} else {
|
||||
return PEAR::raiseError('Invalid digest challenge');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and verifies the digest challenge*
|
||||
*
|
||||
* @param string $challenge The digest challenge
|
||||
* @return array The parsed challenge as an assoc
|
||||
* array in the form "directive => value".
|
||||
* @access private
|
||||
*/
|
||||
function _parseChallenge($challenge)
|
||||
{
|
||||
$tokens = array();
|
||||
while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) {
|
||||
|
||||
// Ignore these as per rfc2831
|
||||
if ($matches[1] == 'opaque' OR $matches[1] == 'domain') {
|
||||
$challenge = substr($challenge, strlen($matches[0]) + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allowed multiple "realm" and "auth-param"
|
||||
if (!empty($tokens[$matches[1]]) AND ($matches[1] == 'realm' OR $matches[1] == 'auth-param')) {
|
||||
if (is_array($tokens[$matches[1]])) {
|
||||
$tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
|
||||
} else {
|
||||
$tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
|
||||
}
|
||||
|
||||
// Any other multiple instance = failure
|
||||
} elseif (!empty($tokens[$matches[1]])) {
|
||||
$tokens = array();
|
||||
break;
|
||||
|
||||
} else {
|
||||
$tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
|
||||
}
|
||||
|
||||
// Remove the just parsed directive from the challenge
|
||||
$challenge = substr($challenge, strlen($matches[0]) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults and required directives
|
||||
*/
|
||||
// Realm
|
||||
if (empty($tokens['realm'])) {
|
||||
$tokens['realm'] = "";
|
||||
}
|
||||
|
||||
// Maxbuf
|
||||
if (empty($tokens['maxbuf'])) {
|
||||
$tokens['maxbuf'] = 65536;
|
||||
}
|
||||
|
||||
// Required: nonce, algorithm
|
||||
if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the response= part of the digest response
|
||||
*
|
||||
* @param string $authcid Authentication id (username)
|
||||
* @param string $pass Password
|
||||
* @param string $realm Realm as provided by the server
|
||||
* @param string $nonce Nonce as provided by the server
|
||||
* @param string $cnonce Client nonce
|
||||
* @param string $digest_uri The digest-uri= value part of the response
|
||||
* @param string $authzid Authorization id
|
||||
* @return string The response= part of the digest response
|
||||
* @access private
|
||||
*/
|
||||
function _getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '')
|
||||
{
|
||||
if ($authzid == '') {
|
||||
$A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce);
|
||||
} else {
|
||||
$A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid);
|
||||
}
|
||||
$A2 = 'AUTHENTICATE:' . $digest_uri;
|
||||
return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the client nonce for the response
|
||||
*
|
||||
* @return string The cnonce value
|
||||
* @access private
|
||||
*/
|
||||
function _getCnonce()
|
||||
{
|
||||
if (@file_exists('/dev/urandom') && $fd = @fopen('/dev/urandom', 'r')) {
|
||||
return base64_encode(fread($fd, 32));
|
||||
|
||||
} elseif (@file_exists('/dev/random') && $fd = @fopen('/dev/random', 'r')) {
|
||||
return base64_encode(fread($fd, 32));
|
||||
|
||||
} else {
|
||||
$str = '';
|
||||
for ($i=0; $i<32; $i++) {
|
||||
$str .= chr(mt_rand(0, 255));
|
||||
}
|
||||
|
||||
return base64_encode($str);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2008 Christoph Schulz |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Christoph Schulz <develop@kristov.de> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: External.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* Implmentation of EXTERNAL SASL mechanism
|
||||
*
|
||||
* @author Christoph Schulz <develop@kristov.de>
|
||||
* @access public
|
||||
* @version 1.0.3
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_External extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Returns EXTERNAL response
|
||||
*
|
||||
* @param string $authcid Authentication id (username)
|
||||
* @param string $pass Password
|
||||
* @param string $authzid Autorization id
|
||||
* @return string EXTERNAL Response
|
||||
*/
|
||||
function getResponse($authcid, $pass, $authzid = '')
|
||||
{
|
||||
return $authzid;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: Login.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* This is technically not a SASL mechanism, however
|
||||
* it's used by Net_Sieve, Net_Cyrus and potentially
|
||||
* other protocols , so here is a good place to abstract
|
||||
* it.
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_Login extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Pseudo SASL LOGIN mechanism
|
||||
*
|
||||
* @param string $user Username
|
||||
* @param string $pass Password
|
||||
* @return string LOGIN string
|
||||
*/
|
||||
function getResponse($user, $pass)
|
||||
{
|
||||
return sprintf('LOGIN %s %s', $user, $pass);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||
// | All rights reserved. |
|
||||
// | |
|
||||
// | Redistribution and use in source and binary forms, with or without |
|
||||
// | modification, are permitted provided that the following conditions |
|
||||
// | are met: |
|
||||
// | |
|
||||
// | o Redistributions of source code must retain the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer. |
|
||||
// | o Redistributions in binary form must reproduce the above copyright |
|
||||
// | notice, this list of conditions and the following disclaimer in the |
|
||||
// | documentation and/or other materials provided with the distribution.|
|
||||
// | o The names of the authors may not be used to endorse or promote |
|
||||
// | products derived from this software without specific prior written |
|
||||
// | permission. |
|
||||
// | |
|
||||
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||
// | |
|
||||
// +-----------------------------------------------------------------------+
|
||||
// | Author: Richard Heyes <richard@php.net> |
|
||||
// +-----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: Plain.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||
|
||||
/**
|
||||
* Implmentation of PLAIN SASL mechanism
|
||||
*
|
||||
* @author Richard Heyes <richard@php.net>
|
||||
* @access public
|
||||
* @version 1.0
|
||||
* @package Auth_SASL
|
||||
*/
|
||||
|
||||
require_once('Auth/SASL/Common.php');
|
||||
|
||||
class Auth_SASL_Plain extends Auth_SASL_Common
|
||||
{
|
||||
/**
|
||||
* Returns PLAIN response
|
||||
*
|
||||
* @param string $authcid Authentication id (username)
|
||||
* @param string $pass Password
|
||||
* @param string $authzid Autorization id
|
||||
* @return string PLAIN Response
|
||||
*/
|
||||
function getResponse($authcid, $pass, $authzid = '')
|
||||
{
|
||||
return $authzid . chr(0) . $authcid . chr(0) . $pass;
|
||||
}
|
||||
}
|
||||
?>
|
||||
-1506
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,550 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Prototype Castable Object.. for DataObject queries
|
||||
*
|
||||
* Storage for Data that may be cast into a variety of formats.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.01 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_01.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_DataObject
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2008 The PHP Group
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version CVS: $Id: Cast.php 287158 2009-08-12 13:58:31Z alan_k $
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Common usages:
|
||||
* // blobs
|
||||
* $data = DB_DataObject_Cast::blob($somefile);
|
||||
* $data = DB_DataObject_Cast::string($somefile);
|
||||
* $dataObject->someblobfield = $data
|
||||
*
|
||||
* // dates?
|
||||
* $d1 = new DB_DataObject_Cast::date('12/12/2000');
|
||||
* $d2 = new DB_DataObject_Cast::date(2000,12,30);
|
||||
* $d3 = new DB_DataObject_Cast::date($d1->year, $d1->month+30, $d1->day+30);
|
||||
*
|
||||
* // time, datetime.. ?????????
|
||||
*
|
||||
* // raw sql????
|
||||
* $data = DB_DataObject_Cast::sql('cast("123123",datetime)');
|
||||
* $data = DB_DataObject_Cast::sql('NULL');
|
||||
*
|
||||
* // int's/string etc. are proably pretty pointless..!!!!
|
||||
*
|
||||
*
|
||||
* inside DB_DataObject,
|
||||
* if (is_a($v,'db_dataobject_class')) {
|
||||
* $value .= $v->toString(DB_DATAOBJECT_INT,'mysql');
|
||||
* }
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
|
||||
*/
|
||||
class DB_DataObject_Cast
|
||||
{
|
||||
|
||||
/**
|
||||
* Type of data Stored in the object..
|
||||
*
|
||||
* @var string (date|blob|.....?)
|
||||
* @access public
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Data For date representation
|
||||
*
|
||||
* @var int day/month/year
|
||||
* @access public
|
||||
*/
|
||||
public $day;
|
||||
public $month;
|
||||
public $year;
|
||||
|
||||
|
||||
/**
|
||||
* Generic Data..
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public $value;
|
||||
/**
|
||||
* Data For time representation ** does not handle timezones!!
|
||||
*
|
||||
* @var int hour/minute/second
|
||||
* @access public
|
||||
*/
|
||||
public $hour;
|
||||
public $minute;
|
||||
public $second;
|
||||
|
||||
/**
|
||||
* Blob consructor
|
||||
*
|
||||
* create a Cast object from some raw data.. (binary)
|
||||
*
|
||||
*
|
||||
* @param string (with binary data!)
|
||||
*
|
||||
* @return object DB_DataObject_Cast
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public function blob($value)
|
||||
{
|
||||
$r = new DB_DataObject_Cast;
|
||||
$r->type = 'blob';
|
||||
$r->value = $value;
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* String consructor (actually use if for ints and everything else!!!
|
||||
*
|
||||
* create a Cast object from some string (not binary)
|
||||
*
|
||||
*
|
||||
* @param string (with binary data!)
|
||||
*
|
||||
* @return object DB_DataObject_Cast
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public function string($value)
|
||||
{
|
||||
$r = new DB_DataObject_Cast;
|
||||
$r->type = 'string';
|
||||
$r->value = $value;
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL constructor (for raw SQL insert)
|
||||
*
|
||||
* create a Cast object from some sql
|
||||
*
|
||||
* @param string (with binary data!)
|
||||
*
|
||||
* @return object DB_DataObject_Cast
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public function sql($value)
|
||||
{
|
||||
$r = new DB_DataObject_Cast;
|
||||
$r->type = 'sql';
|
||||
$r->value = $value;
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* DateTime Constructor
|
||||
*
|
||||
* create a Cast object from a Date/Time
|
||||
* Maybe should accept a Date object.!
|
||||
* NO VALIDATION DONE, although some crappy re-calcing done!
|
||||
*
|
||||
* @param vargs... accepts
|
||||
* noargs (now)
|
||||
* yyyy-mm-dd HH:MM:SS (Iso)
|
||||
* array(yyyy,mm,dd,HH,MM,SS)
|
||||
*
|
||||
*
|
||||
* @return bool|object
|
||||
* @access public
|
||||
* @author therion 5 at hotmail
|
||||
*/
|
||||
|
||||
public function dateTime()
|
||||
{
|
||||
$args = func_get_args();
|
||||
switch (count($args)) {
|
||||
case 0: // no args = now!
|
||||
$datetime = date('Y-m-d G:i:s', mktime());
|
||||
|
||||
// no break
|
||||
case 1:
|
||||
// continue on from 0 args.
|
||||
if (!isset($datetime)) {
|
||||
$datetime = $args[0];
|
||||
}
|
||||
|
||||
$parts = explode(' ', $datetime);
|
||||
$bits = explode('-', $parts[0]);
|
||||
$bits = array_merge($bits, explode(':', $parts[1]));
|
||||
break;
|
||||
|
||||
default: // 2 or more..
|
||||
$bits = $args;
|
||||
|
||||
}
|
||||
|
||||
if (count($bits) != 6) {
|
||||
// PEAR ERROR?
|
||||
return false;
|
||||
}
|
||||
|
||||
$r = DB_DataObject_Cast::date($bits[0], $bits[1], $bits[2]);
|
||||
if (!$r) {
|
||||
return $r; // pass thru error (False) - doesnt happen at present!
|
||||
}
|
||||
// change the type!
|
||||
$r->type = 'datetime';
|
||||
|
||||
// should we mathematically sort this out..
|
||||
// (or just assume that no-one's dumb enough to enter 26:90:90 as a time!
|
||||
$r->hour = $bits[3];
|
||||
$r->minute = $bits[4];
|
||||
$r->second = $bits[5];
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date Constructor
|
||||
*
|
||||
* create a Cast object from some string (not binary)
|
||||
* NO VALIDATION DONE, although some crappy re-calcing done!
|
||||
*
|
||||
* @param vargs... accepts
|
||||
* dd/mm
|
||||
* dd/mm/yyyy
|
||||
* yyyy-mm
|
||||
* yyyy-mm-dd
|
||||
* array(yyyy,dd)
|
||||
* array(yyyy,dd,mm)
|
||||
*
|
||||
*
|
||||
*
|
||||
* @return object DB_DataObject_Cast
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public function date()
|
||||
{
|
||||
$args = func_get_args();
|
||||
switch (count($args)) {
|
||||
case 0: // no args = today!
|
||||
$bits = explode('-', date('Y-m-d'));
|
||||
break;
|
||||
case 1: // one arg = a string
|
||||
|
||||
if (strpos($args[0], '/') !== false) {
|
||||
$bits = array_reverse(explode('/', $args[0]));
|
||||
} else {
|
||||
$bits = explode('-', $args[0]);
|
||||
}
|
||||
break;
|
||||
default: // 2 or more..
|
||||
$bits = $args;
|
||||
}
|
||||
if (count($bits) == 1) { // if YYYY set day = 1st..
|
||||
$bits[] = 1;
|
||||
}
|
||||
|
||||
if (count($bits) == 2) { // if YYYY-DD set day = 1st..
|
||||
$bits[] = 1;
|
||||
}
|
||||
|
||||
// if year < 1970 we cant use system tools to check it...
|
||||
// so we make a few best gueses....
|
||||
// basically do date calculations for the year 2000!!!
|
||||
// fix me if anyone has more time...
|
||||
if (($bits[0] < 1975) || ($bits[0] > 2030)) {
|
||||
$oldyear = $bits[0];
|
||||
$bits = explode('-', date('Y-m-d', mktime(1, 1, 1, $bits[1], $bits[2], 2000)));
|
||||
$bits[0] = ($bits[0] - 2000) + $oldyear;
|
||||
} else {
|
||||
// now mktime
|
||||
$bits = explode('-', date('Y-m-d', mktime(1, 1, 1, $bits[1], $bits[2], $bits[0])));
|
||||
}
|
||||
$r = new DB_DataObject_Cast;
|
||||
$r->type = 'date';
|
||||
list($r->year, $r->month, $r->day) = $bits;
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* time Constructor
|
||||
*
|
||||
* create a Cast object from a Date/Time
|
||||
* Maybe should accept a Date object.!
|
||||
* NO VALIDATION DONE, and no-recalcing done!
|
||||
*
|
||||
* @param vargs... accepts
|
||||
* noargs (now)
|
||||
* HH:MM:SS (Iso)
|
||||
* array(HH,MM,SS)
|
||||
*
|
||||
*
|
||||
* @return bool|object
|
||||
* @access public
|
||||
* @author therion 5 at hotmail
|
||||
*/
|
||||
public function time()
|
||||
{
|
||||
$args = func_get_args();
|
||||
switch (count($args)) {
|
||||
case 0: // no args = now!
|
||||
$time = date('G:i:s', mktime());
|
||||
|
||||
// no break
|
||||
case 1:
|
||||
// continue on from 0 args.
|
||||
if (!isset($time)) {
|
||||
$time = $args[0];
|
||||
}
|
||||
$bits = explode(':', $time);
|
||||
break;
|
||||
|
||||
default: // 2 or more..
|
||||
$bits = $args;
|
||||
|
||||
}
|
||||
|
||||
if (count($bits) != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// now take data from bits into object fields
|
||||
$r = new DB_DataObject_Cast;
|
||||
$r->type = 'time';
|
||||
$r->hour = $bits[0];
|
||||
$r->minute = $bits[1];
|
||||
$r->second = $bits[2];
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement for this...
|
||||
*
|
||||
*
|
||||
* @param bool $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public function toString($to = false, $db)
|
||||
{
|
||||
// if $this->type is not set, we are in serious trouble!!!!
|
||||
// values for to:
|
||||
$method = 'toStringFrom' . $this->type;
|
||||
return $this->$method($to, $db);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement from a blob of binary data
|
||||
* ** Suppots only blob->postgres::bytea
|
||||
*
|
||||
* @param int $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
public function toStringFromBlob($to, $db)
|
||||
{
|
||||
// first weed out invalid casts..
|
||||
// in blobs can only be cast to blobs.!
|
||||
|
||||
// perhaps we should support TEXT fields???
|
||||
|
||||
if (!($to & DB_DATAOBJECT_BLOB)) {
|
||||
return (new PEAR)->raiseError('Invalid Cast from a DB_DataObject_Cast::blob to something other than a blob!');
|
||||
}
|
||||
|
||||
switch ($db->dsn["phptype"]) {
|
||||
case 'pgsql':
|
||||
return "'" . pg_escape_bytea($this->value) . "'::bytea";
|
||||
|
||||
case 'mysql':
|
||||
return "'" . mysql_real_escape_string($this->value, $db->connection) . "'";
|
||||
|
||||
case 'mysqli':
|
||||
// this is funny - the parameter order is reversed ;)
|
||||
return "'" . mysqli_real_escape_string($db->connection, $this->value) . "'";
|
||||
|
||||
case 'sqlite':
|
||||
// this is funny - the parameter order is reversed ;)
|
||||
return "'" . sqlite_escape_string($this->value) . "'";
|
||||
|
||||
case 'mssql':
|
||||
|
||||
if (is_numeric($this->value)) {
|
||||
return $this->value;
|
||||
}
|
||||
$unpacked = unpack('H*hex', $this->value);
|
||||
return '0x' . $unpacked['hex'];
|
||||
|
||||
|
||||
default:
|
||||
return (new PEAR)->raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement for a blob from a string!
|
||||
* ** Suppots only string->postgres::bytea
|
||||
*
|
||||
*
|
||||
* @param int $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
public function toStringFromString($to, $db)
|
||||
{
|
||||
// first weed out invalid casts..
|
||||
// in blobs can only be cast to blobs.!
|
||||
|
||||
// perhaps we should support TEXT fields???
|
||||
//
|
||||
|
||||
// $to == a string field which is the default type (0)
|
||||
// so we do not test it here. - we assume that number fields
|
||||
// will accept a string?? - which is stretching it a bit ...
|
||||
// should probaly add that test as some point.
|
||||
|
||||
switch ($db->dsn['phptype']) {
|
||||
case 'pgsql':
|
||||
return "'" . pg_escape_string($this->value) . "'::bytea";
|
||||
|
||||
case 'mysql':
|
||||
return "'" . mysql_real_escape_string($this->value, $db->connection) . "'";
|
||||
|
||||
|
||||
case 'mysqli':
|
||||
return "'" . mysqli_real_escape_string($db->connection, $this->value) . "'";
|
||||
|
||||
case 'mssql':
|
||||
// copied from the old DB mssql code...?? not sure how safe this is.
|
||||
return "'" . str_replace(
|
||||
array("'", "\\\r\n", "\\\n"),
|
||||
array("''", "\\\\\r\n\r\n", "\\\\\n\n"),
|
||||
$this->value
|
||||
) . "'";
|
||||
|
||||
|
||||
default:
|
||||
return (new PEAR)->raiseError("DB_DataObject_Cast cant handle blobs for Database:{$db->dsn['phptype']} Yet");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement for a date
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param int $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
public function toStringFromDate($to, $db)
|
||||
{
|
||||
// first weed out invalid casts..
|
||||
// in blobs can only be cast to blobs.!
|
||||
// perhaps we should support TEXT fields???
|
||||
//
|
||||
|
||||
if (($to !== false) && !($to & DB_DATAOBJECT_DATE)) {
|
||||
return (new PEAR)->raiseError('Invalid Cast from a DB_DataObject_Cast::string to something other than a date!' .
|
||||
' (why not just use native features)');
|
||||
}
|
||||
return "'{$this->year}-{$this->month}-{$this->day}'";
|
||||
}
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement for a datetime
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param int $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
* @author therion 5 at hotmail
|
||||
*/
|
||||
|
||||
public function toStringFromDateTime($to, $db)
|
||||
{
|
||||
// first weed out invalid casts..
|
||||
// in blobs can only be cast to blobs.!
|
||||
// perhaps we should support TEXT fields???
|
||||
if (($to !== false) &&
|
||||
!($to & (DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME))) {
|
||||
return (new PEAR)->raiseError('Invalid Cast from a ' .
|
||||
' DB_DataObject_Cast::dateTime to something other than a datetime!' .
|
||||
' (try using native features)');
|
||||
}
|
||||
return "'{$this->year}-{$this->month}-{$this->day} {$this->hour}:{$this->minute}:{$this->second}'";
|
||||
}
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement for a time
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param int $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
* @author therion 5 at hotmail
|
||||
*/
|
||||
|
||||
public function toStringFromTime($to, $db)
|
||||
{
|
||||
// first weed out invalid casts..
|
||||
// in blobs can only be cast to blobs.!
|
||||
// perhaps we should support TEXT fields???
|
||||
if (($to !== false) && !($to & DB_DATAOBJECT_TIME)) {
|
||||
return (new PEAR)->raiseError('Invalid Cast from a' .
|
||||
' DB_DataObject_Cast::time to something other than a time!' .
|
||||
' (try using native features)');
|
||||
}
|
||||
return "'{$this->hour}:{$this->minute}:{$this->second}'";
|
||||
}
|
||||
|
||||
/**
|
||||
* get the string to use in the SQL statement for a raw sql statement.
|
||||
*
|
||||
* @param int $to Type (DB_DATAOBJECT_*
|
||||
* @param object $db DB Connection Object
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
public function toStringFromSql($to, $db)
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* DataObjects error handler, loaded on demand...
|
||||
*
|
||||
* DB_DataObject_Error is a quick wrapper around pear error, so you can distinguish the
|
||||
* error code source.
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.01 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_01.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_DataObject
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version CVS: $Id: Error.php 287158 2009-08-12 13:58:31Z alan_k $
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
|
||||
class DB_DataObject_Error extends PEAR_Error
|
||||
{
|
||||
|
||||
/**
|
||||
* DB_DataObject_Error constructor.
|
||||
*
|
||||
* @param string $message
|
||||
* @param mixed $code DB error code, or string with error message.
|
||||
* @param integer $mode what "error mode" to operate in
|
||||
* @param integer $level what error level to use for $mode & PEAR_ERROR_TRIGGER
|
||||
* @access public
|
||||
*
|
||||
* @see PEAR_Error
|
||||
*/
|
||||
public function __construct(
|
||||
$message = '',
|
||||
$code = DB_ERROR,
|
||||
$mode = PEAR_ERROR_RETURN,
|
||||
$level = E_USER_NOTICE
|
||||
)
|
||||
{
|
||||
$this->PEAR_Error('DB_DataObject Error: ' . $message, $code, $mode, $level);
|
||||
}
|
||||
|
||||
|
||||
// todo : - support code -> message handling, and translated error messages...
|
||||
}
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,450 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Link tool for DB_DataObject
|
||||
*
|
||||
* PHP versions 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.01 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_01.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_DataObject
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version : FIXME
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Example of how this could be used..
|
||||
*
|
||||
* The lind method are now in here.
|
||||
*
|
||||
* Currenly only supports existing methods, and new 'link()' method
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Links class
|
||||
*
|
||||
* @package DB_DataObject
|
||||
*/
|
||||
class DB_DataObject_Links
|
||||
{
|
||||
/**
|
||||
* @property {DB_DataObject} do DataObject to apply this to.
|
||||
*/
|
||||
public $do = false;
|
||||
|
||||
|
||||
/**
|
||||
* @property {Array|String} load What to load, 'all' or an array of properties. (default all)
|
||||
*/
|
||||
public $load = 'all';
|
||||
/**
|
||||
* @property {String|Boolean} scanf use part of column name as resulting
|
||||
* property name. (default false)
|
||||
*/
|
||||
public $scanf = false;
|
||||
/**
|
||||
* @property {String|Boolean} printf use column name as sprintf for resulting property name..
|
||||
* (default %s_link if apply is true, otherwise it is %s)
|
||||
*/
|
||||
public $printf = false;
|
||||
/**
|
||||
* @property {Boolean} cached cache the result, so future queries will use cache rather
|
||||
* than running the expensive sql query.
|
||||
*/
|
||||
public $cached = false;
|
||||
/**
|
||||
* @property {Boolean} apply apply the result to this object, (default true)
|
||||
*/
|
||||
public $apply = true;
|
||||
|
||||
|
||||
//------------------------- RETURN ------------------------------------
|
||||
/**
|
||||
* @property {Array} links key value associative array of links.
|
||||
*/
|
||||
public $links;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* -- good ole style..
|
||||
* @param {DB_DataObject} do DataObject to apply to.
|
||||
* @param array $cfg
|
||||
*/
|
||||
|
||||
public function __construct($do, $cfg = array())
|
||||
{
|
||||
// check if do is set!!!?
|
||||
$this->do = $do;
|
||||
|
||||
foreach ($cfg as $k => $v) {
|
||||
$this->$k = $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a generic geter/setter provider..
|
||||
*
|
||||
* provides a generic getter setter for the referenced object
|
||||
* eg.
|
||||
* $link->link('company_id') returns getLink for the object
|
||||
* if nothing is linked (it will return an empty dataObject)
|
||||
* $link->link('company_id', array(1)) - just sets the
|
||||
*
|
||||
* also array as the field speck supports
|
||||
* $link->link(array('company_id', 'company:id'))
|
||||
*
|
||||
*
|
||||
* @param string|array $field the field to fetch or link spec.
|
||||
* @param array $args
|
||||
* @return mixed true of false on set, the object on getter.
|
||||
* @params array $args the arguments sent to the getter setter
|
||||
*/
|
||||
public function link($field, $args = array())
|
||||
{
|
||||
$info = $this->linkInfo($field);
|
||||
|
||||
if (!$info) {
|
||||
$this->do->raiseError(
|
||||
"getLink:Could not find link for row $field",
|
||||
DB_DATAOBJECT_ERROR_INVALIDCONFIG
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$field = $info[2];
|
||||
|
||||
|
||||
if (empty($args)) { // either an empty array or really empty....
|
||||
|
||||
if (!isset($this->do->$field)) {
|
||||
return $info[0]; // empty dataobject.
|
||||
}
|
||||
|
||||
$ret = $this->getLink($field);
|
||||
// nothing linked -- return new object..
|
||||
return ($ret === 0) ? $info[0] : $ret;
|
||||
}
|
||||
$assign = is_array($args) ? $args[0] : $args;
|
||||
|
||||
// otherwise it's a set call..
|
||||
if (!is_a($assign, 'DB_DataObject')) {
|
||||
if (is_numeric($assign) && is_integer($assign * 1)) {
|
||||
if ($assign > 0) {
|
||||
if (!$info) {
|
||||
return false;
|
||||
}
|
||||
// check that record exists..
|
||||
if (!$info[0]->get($info[1], $assign)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->do->$field = $assign;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// otherwise we are assigning it ...
|
||||
|
||||
$this->do->$field = $assign->{$info[1]};
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get link information for a field or field specification
|
||||
*
|
||||
* alll link (and join methods accept the 'link' info ) in various ways
|
||||
* string : 'field' = which field to get (uses ???.links.ini to work out what)
|
||||
* array(2) : 'field', 'table:remote_col' << just like the links.ini def.
|
||||
* array(3) : 'field', $dataobject, 'remote_col' (handy for joinAdd to do nested joins.)
|
||||
*
|
||||
* @param string|array $field or link spec to use.
|
||||
* @return array|bool (false|array) array of dataobject and linked field or false.
|
||||
*
|
||||
*/
|
||||
|
||||
public function linkInfo($field)
|
||||
{
|
||||
if (is_array($field)) {
|
||||
if (count($field) == 3) {
|
||||
// array with 3 args:
|
||||
// local_col , dataobject, remote_col
|
||||
return array(
|
||||
$field[1],
|
||||
$field[2],
|
||||
$field[0]
|
||||
);
|
||||
}
|
||||
list($table, $link) = explode(':', $field[1]);
|
||||
|
||||
return array(
|
||||
$this->do->factory($table),
|
||||
$link,
|
||||
$field[0]
|
||||
);
|
||||
}
|
||||
// work out the link.. (classic way)
|
||||
|
||||
$links = $this->do->links();
|
||||
|
||||
if (empty($links) || !is_array($links)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!isset($links[$field])) {
|
||||
return false;
|
||||
}
|
||||
list($table, $link) = explode(':', $links[$field]);
|
||||
|
||||
|
||||
//??? needed???
|
||||
if ($p = strpos($field, ".")) {
|
||||
$field = substr($field, 0, $p);
|
||||
}
|
||||
|
||||
return array(
|
||||
$this->do->factory($table),
|
||||
$link,
|
||||
$field
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* return name from related object
|
||||
*
|
||||
* The relies on a <dbname>.links.ini file, unless you specify the arguments.
|
||||
*
|
||||
* you can also use $this->getLink('thisColumnName','otherTable','otherTableColumnName')
|
||||
*
|
||||
*
|
||||
* @param string $field |array either row or row.xxxxx or links spec.
|
||||
* @param bool $table (optional) name of table to look up value in
|
||||
* @param string $link (optional) name of column in other table to match
|
||||
* @return mixed object on success false on failure or '0' when not linked
|
||||
* @author Tim White <tim@cyface.com>
|
||||
* @access public
|
||||
*/
|
||||
public function getLink($field, $table = false, $link = '')
|
||||
{
|
||||
static $cache = array();
|
||||
|
||||
// GUESS THE LINKED TABLE.. (if found - recursevly call self)
|
||||
|
||||
if ($table == false) {
|
||||
$info = $this->linkInfo($field);
|
||||
|
||||
if ($info) {
|
||||
return $this->getLink($field, $info[0], $link === false ? $info[1] : $link);
|
||||
}
|
||||
|
||||
// no links defined.. - use borked BC method...
|
||||
// use the old _ method - this shouldnt happen if called via getLinks()
|
||||
if (!($p = strpos($field, '_'))) {
|
||||
return false;
|
||||
}
|
||||
$table = substr($field, 0, $p);
|
||||
return $this->getLink($field, $table);
|
||||
}
|
||||
|
||||
$tn = is_string($table) ? $table : $table->tableName();
|
||||
|
||||
|
||||
if (!isset($this->do->$field)) {
|
||||
$this->do->raiseError("getLink: row not set $field", DB_DATAOBJECT_ERROR_NODATA);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check to see if we know anything about this table..
|
||||
|
||||
|
||||
if (empty($this->do->$field) || $this->do->$field < 0) {
|
||||
return 0; // no record.
|
||||
}
|
||||
|
||||
if ($this->cached && isset($cache[$tn . ':' . $link . ':' . $this->do->$field])) {
|
||||
return $cache[$tn . ':' . $link . ':' . $this->do->$field];
|
||||
}
|
||||
|
||||
$obj = is_string($table) ? $this->do->factory($tn) : $table;;
|
||||
|
||||
if (!is_a($obj, 'DB_DataObject')) {
|
||||
$this->do->raiseError(
|
||||
"getLink:Could not find class for row $field, table $tn",
|
||||
DB_DATAOBJECT_ERROR_INVALIDCONFIG
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// -1 or 0 -- no referenced record..
|
||||
|
||||
$ret = false;
|
||||
if ($link) {
|
||||
if ($obj->get($link, $this->do->$field)) {
|
||||
$ret = $obj;
|
||||
}
|
||||
|
||||
|
||||
// this really only happens when no link config is set (old BC stuff)
|
||||
} elseif ($obj->get($this->do->$field)) {
|
||||
$ret = $obj;
|
||||
}
|
||||
if ($this->cached) {
|
||||
$cache[$tn . ':' . $link . ':' . $this->do->$field] = $ret;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* load related objects
|
||||
*
|
||||
* Generally not recommended to use this.
|
||||
* The generator should support creating getter_setter methods which are better suited.
|
||||
*
|
||||
* Relies on <dbname>.links.ini
|
||||
*
|
||||
* Sets properties on the calling dataobject you can change what
|
||||
* object vars the links are stored in by changeing the format parameter
|
||||
*
|
||||
*
|
||||
* @param string format (default _%s) where %s is the table name.
|
||||
* @return boolean , true on success
|
||||
* @author Tim White <tim@cyface.com>
|
||||
* @access public
|
||||
*/
|
||||
|
||||
public function applyLinks($format = '_%s')
|
||||
{
|
||||
|
||||
// get table will load the options.
|
||||
if ($this->do->_link_loaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->do->_link_loaded = false;
|
||||
$cols = $this->do->table();
|
||||
$links = $this->do->links();
|
||||
|
||||
$loaded = array();
|
||||
|
||||
if ($links) {
|
||||
foreach ($links as $key => $match) {
|
||||
list($table, $link) = explode(':', $match);
|
||||
$k = sprintf($format, str_replace('.', '_', $key));
|
||||
// makes sure that '.' is the end of the key;
|
||||
if ($p = strpos($key, '.')) {
|
||||
$key = substr($key, 0, $p);
|
||||
}
|
||||
|
||||
$this->do->$k = $this->getLink($key, $table, $link);
|
||||
|
||||
if (is_object($this->do->$k)) {
|
||||
$loaded[] = $k;
|
||||
}
|
||||
}
|
||||
$this->do->_link_loaded = $loaded;
|
||||
return true;
|
||||
}
|
||||
// this is the autonaming stuff..
|
||||
// it sends the column name down to getLink and lets that sort it out..
|
||||
// if there is a links file then it is not used!
|
||||
// IT IS DEPRECATED!!!! - DO NOT USE
|
||||
if (!is_null($links)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
foreach (array_keys($cols) as $key) {
|
||||
if (!($p = strpos($key, '_'))) {
|
||||
continue;
|
||||
}
|
||||
// does the table exist.
|
||||
$k = sprintf($format, $key);
|
||||
$this->do->$k = $this->getLink($key);
|
||||
if (is_object($this->do->$k)) {
|
||||
$loaded[] = $k;
|
||||
}
|
||||
}
|
||||
$this->do->_link_loaded = $loaded;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* getLinkArray
|
||||
* Fetch an array of related objects. This should be used in conjunction with a
|
||||
* <dbname>.links.ini file configuration (see the introduction on linking for details on this).
|
||||
*
|
||||
* You may also use this with all parameters to specify, the column and related table.
|
||||
*
|
||||
* @access public
|
||||
* @param string $field - either column or column.xxxxx
|
||||
* @param string $table (optional) name of table to look up value in
|
||||
* @param bool $fkey (optional) fetchall key see DB_DataObject::fetchAll()
|
||||
* @param bool $fval (optional) fetchall method DB_DataObject::fetchAll()
|
||||
* @param bool $fmethod
|
||||
* @return array - array of results (empty array on failure)
|
||||
*
|
||||
* Example - Getting the related objects
|
||||
*
|
||||
* $person = new DataObjects_Person;
|
||||
* $person->get(12);
|
||||
* $children = $person->getLinkArray('children');
|
||||
*
|
||||
* echo 'There are ', count($children), ' descendant(s):<br />';
|
||||
* foreach ($children as $child) {
|
||||
* echo $child->name, '<br />';
|
||||
* }
|
||||
*/
|
||||
public function getLinkArray($field, $table = null, $fkey = false, $fval = false, $fmethod = false)
|
||||
{
|
||||
$ret = array();
|
||||
if (!$table) {
|
||||
$links = $this->do->links();
|
||||
|
||||
if (is_array($links)) {
|
||||
if (!isset($links[$field])) {
|
||||
// failed..
|
||||
return $ret;
|
||||
}
|
||||
list($table, $link) = explode(':', $links[$field]);
|
||||
return $this->getLinkArray($field, $table);
|
||||
}
|
||||
if (!($p = strpos($field, '_'))) {
|
||||
return $ret;
|
||||
}
|
||||
return $this->getLinkArray($field, substr($field, 0, $p));
|
||||
}
|
||||
|
||||
$c = $this->do->factory($table);
|
||||
|
||||
if (!is_object($c) || !is_a($c, 'DB_DataObject')) {
|
||||
$this->do->raiseError(
|
||||
"getLinkArray:Could not find class for row $field, table $table",
|
||||
DB_DATAOBJECT_ERROR_INVALIDCONFIG
|
||||
);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// if the user defined method list exists - use it...
|
||||
if (method_exists($c, 'listFind')) {
|
||||
$c->listFind($this->id);
|
||||
while ($c->fetch()) {
|
||||
$ret[] = clone($c);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
return $c->fetchAll($fkey, $fval, $fmethod);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/usr/bin/php -q
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP Version 4 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1997-2003 The PHP Group |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | This source file is subject to version 2.02 of the PHP license, |
|
||||
// | that is bundled with this package in the file LICENSE, and is |
|
||||
// | available at through the world-wide-web at |
|
||||
// | http://www.php.net/license/2_02.txt. |
|
||||
// | If you did not receive a copy of the PHP license and are unable to |
|
||||
// | obtain it through the world-wide-web, please send a note to |
|
||||
// | license@php.net so we can mail you a copy immediately. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Alan Knowles <alan@akbkhome.com>
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: createTables.php 277015 2009-03-12 05:51:03Z alan_k $
|
||||
//
|
||||
|
||||
// since this version doesnt use overload,
|
||||
// and I assume anyone using custom generators should add this..
|
||||
|
||||
define('DB_DATAOBJECT_NO_OVERLOAD', 1);
|
||||
|
||||
//require_once 'DB/DataObject/Generator.php';
|
||||
require_once 'Generator.php';
|
||||
|
||||
if (php_sapi_name() != 'cli') {
|
||||
(new PEAR)->raiseError("\nERROR: You must turn use the cli sapi to run this", null, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
if (!ini_get('register_argc_argv')) {
|
||||
(new PEAR)->raiseError("\nERROR: You must turn register_argc_argv On in you php.ini file for this to work\neg.\n\nregister_argc_argv = On\n\n", null, PEAR_ERROR_DIE);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!@$_SERVER['argv'][1]) {
|
||||
(new PEAR)->raiseError("\nERROR: createTable.php usage:\n\n" . $_SERVER['argv'][0] . " example.ini\n\n", null, PEAR_ERROR_DIE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$config = parse_ini_file($_SERVER['argv'][1], true);
|
||||
foreach ($config as $class => $values) {
|
||||
$options = &(new PEAR)->getStaticProperty($class, 'options');
|
||||
$options = $values;
|
||||
}
|
||||
|
||||
|
||||
$options = &(new PEAR)->getStaticProperty('DB_DataObject', 'options');
|
||||
if (empty($options)) {
|
||||
(new PEAR)->raiseError("\nERROR: could not read ini file\n\n", null, PEAR_ERROR_DIE);
|
||||
exit;
|
||||
}
|
||||
set_time_limit(0);
|
||||
|
||||
// use debug level from file if set..
|
||||
DB_DataObject::debugLevel(isset($options['debug']) ? $options['debug'] : 1);
|
||||
|
||||
$generator = new DB_DataObject_Generator;
|
||||
$generator->start();
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,531 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_dbase extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'dbase';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* A means of emulating result resources
|
||||
* @var array
|
||||
*/
|
||||
public $res_row = array();
|
||||
|
||||
/**
|
||||
* The quantity of results so far
|
||||
*
|
||||
* For emulating result resources.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $types = array(
|
||||
'C' => 'character',
|
||||
'D' => 'date',
|
||||
'L' => 'boolean',
|
||||
'M' => 'memo',
|
||||
'N' => 'number',
|
||||
);
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 ((new PEAR)->isError($db)) {
|
||||
* die($db->getMessage());
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @dbase_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ &query()
|
||||
|
||||
public 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()
|
||||
*/
|
||||
public 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()
|
||||
*/
|
||||
public 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 $foo
|
||||
* @return int the number of columns. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public 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 $foo
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public 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.
|
||||
*/
|
||||
public 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
@@ -1,795 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @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
|
||||
*/
|
||||
public $phptype = 'fbsql';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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)
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @fbsql_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return @fbsql_next_result($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? fbsql_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function autoCommit($onoff = false)
|
||||
{
|
||||
if ($onoff) {
|
||||
$this->query("SET COMMIT TRUE");
|
||||
} else {
|
||||
$this->query("SET COMMIT FALSE");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
@fbsql_commit($this->connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
@fbsql_rollback($this->connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @fbsql_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @fbsql_num_rows($result);
|
||||
if ($rows === null) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
$result = @fbsql_affected_rows($this->connection);
|
||||
} else {
|
||||
$result = 0;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_fbsql::createSequence(), DB_fbsql::dropSequence()
|
||||
*/
|
||||
public 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];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ modifyLimitQuery()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)
|
||||
. ' RESTRICT');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteBoolean()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteFloat()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function quoteBoolean($boolean)
|
||||
{
|
||||
return $boolean ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fbsqlRaiseError()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function quoteFloat($float)
|
||||
{
|
||||
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code produced by the last query
|
||||
*
|
||||
* @return int the DBMS' error code
|
||||
*/
|
||||
public 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
*/
|
||||
public 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()
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,686 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_ifx extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'ifx';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* Should data manipulation queries be committed automatically?
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $transaction_opcount = 0;
|
||||
|
||||
/**
|
||||
* The number of rows affected by a data manipulation query
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $affected = 0;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function ifxRaiseError($errno = null)
|
||||
{
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode(ifx_error());
|
||||
}
|
||||
return $this->raiseError(
|
||||
$errno,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$this->errorNative()
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function errorCode($nativecode)
|
||||
{
|
||||
if (preg_match('/SQLCODE=(.*)]/', $nativecode, $match)) {
|
||||
$code = $match[1];
|
||||
if (isset($this->errorcode_map[$code])) {
|
||||
return $this->errorcode_map[$code];
|
||||
}
|
||||
}
|
||||
return DB_ERROR;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code and message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error code and message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @ifx_error() . ' ' . @ifx_errormsg();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @ifx_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
return $this->affected;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
if (!$cols = @ifx_num_fields($result)) {
|
||||
return $this->ifxRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? ifx_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ ifxRaiseError()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public 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()
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
@@ -1,845 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @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
|
||||
*/
|
||||
public $phptype = 'msql';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $_result;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 ((new PEAR)->isError($db)) {
|
||||
* die($db->getMessage());
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function msqlRaiseError($errno = null)
|
||||
{
|
||||
$native = $this->errorNative();
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode($native);
|
||||
}
|
||||
return $this->raiseError($errno, null, null, null, $native);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @msql_error();
|
||||
}
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @msql_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affected()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? msql_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @msql_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ createSequence()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @msql_num_rows($result);
|
||||
if ($rows === false) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if (!$this->_result) {
|
||||
return 0;
|
||||
}
|
||||
return msql_affected_rows($this->_result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteIdentifier()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_msql::createSequence(), DB_msql::dropSequence()
|
||||
*/
|
||||
public 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];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteFloat()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ escapeSimple()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ msqlRaiseError()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function quoteIdentifier($str)
|
||||
{
|
||||
return $this->raiseError(DB_ERROR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function quoteFloat($float)
|
||||
{
|
||||
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function escapeSimple($str)
|
||||
{
|
||||
return addslashes($str);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::setOption()
|
||||
*/
|
||||
public 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|object
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
@@ -1,994 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_mssql extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'mssql';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
public $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
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* Should data manipulation queries be committed automatically?
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $_db = null;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param null $code
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_mssql::errorNative(), DB_mssql::errorCode()
|
||||
*/
|
||||
public 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"
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code produced by the last query
|
||||
*
|
||||
* @return int the DBMS' error code
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
$res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
|
||||
if (!$res) {
|
||||
return DB_ERROR;
|
||||
}
|
||||
$row = @mssql_fetch_row($res);
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param string $msg
|
||||
* @return integer an error number from a DB error constant
|
||||
* @see errorNative()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return @mssql_next_result($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? mssql_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @mssql_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @mssql_num_rows($result);
|
||||
if ($rows === false) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ escapeSimple()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_mssql::createSequence(), DB_mssql::dropSequence()
|
||||
*/
|
||||
public 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];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteIdentifier()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
return $this->query('CREATE TABLE '
|
||||
. $this->getSequenceName($seq_name)
|
||||
. ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
|
||||
. ' [vapor] [int] NULL)');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ mssqlRaiseError()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Escapes a string in a manner suitable for SQL Server.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function escapeSimple($str)
|
||||
{
|
||||
return str_replace(
|
||||
array("'", "\\\r\n", "\\\n"),
|
||||
array("''", "\\\\\r\n\r\n", "\\\\\n\n"),
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function quoteIdentifier($str)
|
||||
{
|
||||
return '[' . str_replace(']', ']]', $str) . ']';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
*/
|
||||
public 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 array|string
|
||||
*
|
||||
* @access private
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
public 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>
|
||||
*/
|
||||
public 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()
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,889 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_odbc extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'odbc';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* The number of rows affected by a data manipulation query
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $affected = 0;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code and message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error code and message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
if (!is_resource($this->connection)) {
|
||||
return @odbc_error() . ' ' . @odbc_errormsg();
|
||||
}
|
||||
return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool|void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$err = @odbc_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $err;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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()
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return @odbc_next_result($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? odbc_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @odbc_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteIdentifier()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_odbc::createSequence(), DB_odbc::dropSequence()
|
||||
*/
|
||||
public 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];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
return $this->query('CREATE TABLE '
|
||||
. $this->getSequenceName($seq_name)
|
||||
. ' (id integer NOT NULL,'
|
||||
. ' PRIMARY KEY(id))');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Enables or disables automatic commits
|
||||
*
|
||||
* @param bool $onoff true turns it on, false turns it off
|
||||
*
|
||||
* @return int|object
|
||||
* doesn't support auto-committing transactions.
|
||||
*/
|
||||
public function autoCommit($onoff = false)
|
||||
{
|
||||
if (!@odbc_autocommit($this->connection, $onoff)) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ odbcRaiseError()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if (!@odbc_commit($this->connection)) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if (!@odbc_rollback($this->connection)) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public 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 array|string
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,978 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_sqlite extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'sqlite';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* SQLite data types
|
||||
*
|
||||
* @link http://www.sqlite.org/datatypes.html
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $_lasterror = '';
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 ((new PEAR)->isError($db)) {
|
||||
* die($db->getMessage());
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return $this->_lasterror;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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,
|
||||
'/no column named/' => 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool|void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @sqlite_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @sqlite_num_rows($result);
|
||||
if ($rows === null) {
|
||||
return $this->sqliteRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affected()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult(&$result)
|
||||
{
|
||||
// XXX No native free?
|
||||
if (!is_resource($result)) {
|
||||
return false;
|
||||
}
|
||||
$result = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @sqlite_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->sqliteRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getDbFileStats()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
return @sqlite_changes($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ escapeSimple()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ modifyLimitQuery()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_sqlite::createSequence(), DB_sqlite::dropSequence()
|
||||
*/
|
||||
public 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);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ modifyQuery()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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);
|
||||
//}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ sqliteRaiseError()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function escapeSimple($str)
|
||||
{
|
||||
return @sqlite_escape_string($str);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function modifyLimitQuery($query, $from, $count, $params = array())
|
||||
{
|
||||
return "$query LIMIT $count OFFSET $from";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public 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 (strtoupper($type) == 'INTEGER') {
|
||||
$flags .= 'auto_increment ';
|
||||
}
|
||||
}
|
||||
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()
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
@@ -1,548 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Provides an object interface to a table row
|
||||
*
|
||||
* PHP version 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$
|
||||
* @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.9.2
|
||||
* @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 */
|
||||
public $_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 */
|
||||
public $_keycolumn = null;
|
||||
|
||||
/** DB connection handle used for all transactions */
|
||||
public $_dbh = null;
|
||||
|
||||
/** an assoc with the names of database fields stored as properties
|
||||
* in this object */
|
||||
public $_properties = array();
|
||||
|
||||
/** an assoc with the names of the properties in this object that
|
||||
* have been changed since they were fetched from the database */
|
||||
public $_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. */
|
||||
public $_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 */
|
||||
public $_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
|
||||
*
|
||||
*/
|
||||
public function __construct($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()
|
||||
|
||||
/**
|
||||
* Create a new (empty) row in the configured table for this
|
||||
* object.
|
||||
* @param $newpk
|
||||
* @return |null
|
||||
*/
|
||||
public 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);
|
||||
return null;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* Utility method to build a "WHERE" clause to locate ourselves in
|
||||
* the table.
|
||||
*
|
||||
* XXX future improvement: use rowids?
|
||||
*
|
||||
* @access private
|
||||
* @param null $keyval
|
||||
* @return mixed|string|null
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ toString()
|
||||
|
||||
/**
|
||||
* Output a simple description of this DB_storage object.
|
||||
* @return string object description
|
||||
*/
|
||||
public 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".
|
||||
*/
|
||||
public 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 $table
|
||||
* @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
|
||||
*/
|
||||
public 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.
|
||||
* @param $property
|
||||
* @param $newvalue
|
||||
* @return bool|object
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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.
|
||||
*/
|
||||
public 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|int
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
@@ -1,955 +0,0 @@
|
||||
<?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 version 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$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once '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.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_sybase extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'sybase';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* Should data manipulation queries be committed automatically?
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public $_db = '';
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function sybaseRaiseError($errno = null)
|
||||
{
|
||||
$native = $this->errorNative();
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode($native);
|
||||
}
|
||||
return $this->raiseError($errno, null, null, null, $native);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @sybase_get_last_message();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? sybase_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @sybase_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @sybase_num_rows($result);
|
||||
if ($rows === false) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
$result = @sybase_affected_rows($this->connection);
|
||||
} else {
|
||||
$result = 0;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteFloat()
|
||||
|
||||
/**
|
||||
* 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_sybase::createSequence(), DB_sybase::dropSequence()
|
||||
*/
|
||||
public 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];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
return $this->query('CREATE TABLE '
|
||||
. $this->getSequenceName($seq_name)
|
||||
. ' (id numeric(10, 0) IDENTITY NOT NULL,'
|
||||
. ' vapor int NULL)');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function quoteFloat($float)
|
||||
{
|
||||
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ sybaseRaiseError()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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()
|
||||
*/
|
||||
public 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:
|
||||
*/
|
||||
Arquivo binário não exibido.
@@ -1,29 +0,0 @@
|
||||
Core.ColorKeywords
|
||||
TYPE: hash
|
||||
VERSION: 2.0.0
|
||||
--DEFAULT--
|
||||
array (
|
||||
'maroon' => '#800000',
|
||||
'red' => '#FF0000',
|
||||
'orange' => '#FFA500',
|
||||
'yellow' => '#FFFF00',
|
||||
'olive' => '#808000',
|
||||
'purple' => '#800080',
|
||||
'fuchsia' => '#FF00FF',
|
||||
'white' => '#FFFFFF',
|
||||
'lime' => '#00FF00',
|
||||
'green' => '#008000',
|
||||
'navy' => '#000080',
|
||||
'blue' => '#0000FF',
|
||||
'aqua' => '#00FFFF',
|
||||
'teal' => '#008080',
|
||||
'black' => '#000000',
|
||||
'silver' => '#C0C0C0',
|
||||
'gray' => '#808080',
|
||||
)
|
||||
--DESCRIPTION--
|
||||
|
||||
Lookup array of color names to six digit hexadecimal number corresponding
|
||||
to color, with preceding hash mark. Used when parsing colors. The lookup
|
||||
is done in a case-insensitive manner.
|
||||
--# vim: et sw=4 sts=4
|
||||
@@ -1 +0,0 @@
|
||||
4.10.0
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
#
|
||||
# Markdown - A text-to-HTML conversion tool for web writers
|
||||
#
|
||||
# PHP Markdown
|
||||
# Copyright (c) 2004-2015 Michel Fortin
|
||||
# <https://michelf.ca/projects/php-markdown/>
|
||||
#
|
||||
# Original Markdown
|
||||
# Copyright (c) 2004-2006 John Gruber
|
||||
# <https://daringfireball.net/projects/markdown/>
|
||||
#
|
||||
namespace Michelf;
|
||||
|
||||
|
||||
#
|
||||
# Markdown Parser Interface
|
||||
#
|
||||
|
||||
interface MarkdownInterface {
|
||||
|
||||
#
|
||||
# Initialize the parser and return the result of its transform method.
|
||||
# This will work fine for derived classes too.
|
||||
#
|
||||
public static function defaultTransform($text);
|
||||
|
||||
#
|
||||
# Main function. Performs some preprocessing on the input text
|
||||
# and pass it through the document gamut.
|
||||
#
|
||||
public function transform($text);
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
// {{{ license
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
|
||||
//
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
|
||||
// }}}
|
||||
|
||||
|
||||
/**
|
||||
* Encode/decode Internationalized Domain Names.
|
||||
* Factory class to get correct implementation either for php4 or php5.
|
||||
*
|
||||
* @author Markus Nix <mnix@docuverse.de>
|
||||
* @author Matthias Sommerfeld <mso@phlylabs.de>
|
||||
* @package Net
|
||||
* @version $Id: IDNA.php 284681 2009-07-24 04:24:27Z clockwerx $
|
||||
*/
|
||||
|
||||
class Net_IDNA
|
||||
{
|
||||
// {{{ factory
|
||||
/**
|
||||
* Attempts to return a concrete IDNA instance for either php4 or php5.
|
||||
*
|
||||
* @param array $params Set of paramaters
|
||||
* @return object IDNA The newly created concrete Log instance, or an
|
||||
* false on an error.
|
||||
* @access public
|
||||
*/
|
||||
function getInstance($params = array())
|
||||
{
|
||||
$version = explode( '.', phpversion() );
|
||||
$handler = ((int)$version[0] > 4) ? 'php5' : 'php4';
|
||||
$class = 'Net_IDNA_' . $handler;
|
||||
$classfile = 'Net/IDNA/' . $handler . '.php';
|
||||
|
||||
/*
|
||||
* Attempt to include our version of the named class, but don't treat
|
||||
* a failure as fatal. The caller may have already included their own
|
||||
* version of the named class.
|
||||
*/
|
||||
@include_once $classfile;
|
||||
|
||||
/* If the class exists, return a new instance of it. */
|
||||
if (class_exists($class)) {
|
||||
return new $class($params);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// {{{ singleton
|
||||
/**
|
||||
* Attempts to return a concrete IDNA instance for either php4 or php5,
|
||||
* only creating a new instance if no IDNA instance with the same
|
||||
* parameters currently exists.
|
||||
*
|
||||
* @param array $params Set of paramaters
|
||||
* @return object IDNA The newly created concrete Log instance, or an
|
||||
* false on an error.
|
||||
* @access public
|
||||
*/
|
||||
function singleton($params = array())
|
||||
{
|
||||
static $instances;
|
||||
if (!isset($instances)) {
|
||||
$instances = array();
|
||||
}
|
||||
|
||||
$signature = serialize($params);
|
||||
if (!isset($instances[$signature])) {
|
||||
$instances[$signature] = Net_IDNA::getInstance($params);
|
||||
}
|
||||
|
||||
return $instances[$signature];
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
class Net_IDNA2_Exception extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
require_once 'Net/IDNA2/Exception.php';
|
||||
|
||||
class Net_IDNA2_Exception_Nameprep extends Net_IDNA2_Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
require_once 'Net/IDNA2.php';
|
||||
|
||||
class Net_IDNA2Test extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Initialise tests
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
$this->idn = new Net_IDNA2();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a complete URL consisting also of port-number etc. will be decoded just fine, test 1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testShouldDecodePortNumbersFragmentsAndUrisCorrectly1()
|
||||
{
|
||||
$result = $this->idn->decode('http://www.xn--ml-6kctd8d6a.org:8080/test.php?arg1=1&arg2=2#fragment');
|
||||
$this->assertSame("http://www.\xD0\xB5\xD1\x85\xD0\xB0m\xD1\x80l\xD0\xB5.org:8080/test.php?arg1=1&arg2=2#fragment", $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a complete URL consisting also of port-number etc. will be decoded just fine, test 2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testShouldDecodePortNumbersFragmentsAndUrisCorrectly2()
|
||||
{
|
||||
$result = $this->idn->decode('http://xn--tst-qla.example.com:8080/test.php?arg1=1&arg2=2#fragment');
|
||||
$this->assertSame("http://täst.example.com:8080/test.php?arg1=1&arg2=2#fragment", $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test encoding of German letter Eszett according to the original standard (IDNA2003)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEncodingForGermanEszettUsingIDNA2003()
|
||||
{
|
||||
// make sure to use 2003-encoding
|
||||
$this->idn->setParams('version', '2003');
|
||||
$result = $this->idn->encode('http://www.straße.example.com/');
|
||||
|
||||
$this->assertSame("http://www.strasse.example.com/", $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test encoding of German letter Eszett according to the "new" standard (IDNA2005/IDNAbis)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEncodingForGermanEszettUsingIDNA2008()
|
||||
{
|
||||
// make sure to use 2008-encoding
|
||||
$this->idn->setParams('version', '2008');
|
||||
$result = $this->idn->encode('http://www.straße.example.com/');
|
||||
// switch back for other testcases
|
||||
$this->idn->setParams('version', '2003');
|
||||
|
||||
$this->assertSame("http://www.xn--strae-oqa.example.com/", $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
<?php
|
||||
require_once 'Net/IDNA2.php';
|
||||
|
||||
// Test cases from https://www.gnu.org/software/libidn/draft-josefsson-idn-test-vectors.html
|
||||
|
||||
define('IDNA_ACE_PREFIX', 'xn--');
|
||||
|
||||
class IDNATest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->idn = new Net_IDNA2();
|
||||
}
|
||||
|
||||
public static function unichr($chr)
|
||||
{
|
||||
return mb_convert_encoding('&#' . intval($chr) . ';', 'UTF-8', 'HTML-ENTITIES');
|
||||
}
|
||||
|
||||
private function hexarray2string($arr)
|
||||
{
|
||||
return implode('', array_map(array('self', 'unichr'), $arr));
|
||||
}
|
||||
|
||||
public function testDecode1()
|
||||
{
|
||||
// Arabic (Egyptian)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0644, 0x064A, 0x0647, 0x0645, 0x0627, 0x0628, 0x062A, 0x0643,
|
||||
0x0644, 0x0645, 0x0648, 0x0634, 0x0639, 0x0631, 0x0628, 0x064A,
|
||||
0x061F
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "egbpdaj6bu4bxfgehfvwxn");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode2()
|
||||
{
|
||||
// Chinese (simplified)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x4ED6, 0x4EEC, 0x4E3A, 0x4EC0, 0x4E48, 0x4E0D, 0x8BF4, 0x4E2D, 0x6587
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "ihqwcrb4cv8a8dqg056pqjye");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode3()
|
||||
{
|
||||
// Chinese (traditional)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x4ED6, 0x5011, 0x7232, 0x4EC0, 0x9EBD, 0x4E0D, 0x8AAA, 0x4E2D, 0x6587
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "ihqwctvzc91f659drss3x8bo0yb");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode4()
|
||||
{
|
||||
// Czech
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0050, 0x0072, 0x006F, 0x010D, 0x0070, 0x0072, 0x006F, 0x0073,
|
||||
0x0074, 0x011B, 0x006E, 0x0065, 0x006D, 0x006C, 0x0075, 0x0076,
|
||||
0x00ED, 0x010D, 0x0065, 0x0073, 0x006B, 0x0079
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "Proprostnemluvesky-uyb24dma41a");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode5()
|
||||
{
|
||||
// Hebrew
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x05DC, 0x05DE, 0x05D4, 0x05D4, 0x05DD, 0x05E4, 0x05E9, 0x05D5,
|
||||
0x05D8, 0x05DC, 0x05D0, 0x05DE, 0x05D3, 0x05D1, 0x05E8, 0x05D9,
|
||||
0x05DD, 0x05E2, 0x05D1, 0x05E8, 0x05D9, 0x05EA
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "4dbcagdahymbxekheh6e0a7fei0b");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode6()
|
||||
{
|
||||
// Hindi (Devanagari)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x092F, 0x0939, 0x0932, 0x094B, 0x0917, 0x0939, 0x093F, 0x0928,
|
||||
0x094D, 0x0926, 0x0940, 0x0915, 0x094D, 0x092F, 0x094B, 0x0902,
|
||||
0x0928, 0x0939, 0x0940, 0x0902, 0x092C, 0x094B, 0x0932, 0x0938,
|
||||
0x0915, 0x0924, 0x0947, 0x0939, 0x0948, 0x0902
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode7()
|
||||
{
|
||||
// Japanese (kanji and hiragana)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x306A, 0x305C, 0x307F, 0x3093, 0x306A, 0x65E5, 0x672C, 0x8A9E,
|
||||
0x3092, 0x8A71, 0x3057, 0x3066, 0x304F, 0x308C, 0x306A, 0x3044,
|
||||
0x306E, 0x304B
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode8()
|
||||
{
|
||||
// Russian (Cyrillic)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x043F, 0x043E, 0x0447, 0x0435, 0x043C, 0x0443, 0x0436, 0x0435,
|
||||
0x043E, 0x043D, 0x0438, 0x043D, 0x0435, 0x0433, 0x043E, 0x0432,
|
||||
0x043E, 0x0440, 0x044F, 0x0442, 0x043F, 0x043E, 0x0440, 0x0443,
|
||||
0x0441, 0x0441, 0x043A, 0x0438
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "b1abfaaepdrnnbgefbadotcwatmq2g4l");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode9()
|
||||
{
|
||||
// Spanish
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0050, 0x006F, 0x0072, 0x0071, 0x0075, 0x00E9, 0x006E, 0x006F,
|
||||
0x0070, 0x0075, 0x0065, 0x0064, 0x0065, 0x006E, 0x0073, 0x0069,
|
||||
0x006D, 0x0070, 0x006C, 0x0065, 0x006D, 0x0065, 0x006E, 0x0074,
|
||||
0x0065, 0x0068, 0x0061, 0x0062, 0x006C, 0x0061, 0x0072, 0x0065,
|
||||
0x006E, 0x0045, 0x0073, 0x0070, 0x0061, 0x00F1, 0x006F, 0x006C
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "PorqunopuedensimplementehablarenEspaol-fmd56a");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode10()
|
||||
{
|
||||
// Vietnamese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0054, 0x1EA1, 0x0069, 0x0073, 0x0061, 0x006F, 0x0068, 0x1ECD,
|
||||
0x006B, 0x0068, 0x00F4, 0x006E, 0x0067, 0x0074, 0x0068, 0x1EC3,
|
||||
0x0063, 0x0068, 0x1EC9, 0x006E, 0x00F3, 0x0069, 0x0074, 0x0069,
|
||||
0x1EBF, 0x006E, 0x0067, 0x0056, 0x0069, 0x1EC7, 0x0074
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode11()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "3B-ww4c5e180e575a65lsy2b");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode12()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x5B89, 0x5BA4, 0x5948, 0x7F8E, 0x6075, 0x002D, 0x0077, 0x0069,
|
||||
0x0074, 0x0068, 0x002D, 0x0053, 0x0055, 0x0050, 0x0045, 0x0052,
|
||||
0x002D, 0x004D, 0x004F, 0x004E, 0x004B, 0x0045, 0x0059, 0x0053
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode13()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0048, 0x0065, 0x006C, 0x006C, 0x006F, 0x002D, 0x0041, 0x006E,
|
||||
0x006F, 0x0074, 0x0068, 0x0065, 0x0072, 0x002D, 0x0057, 0x0061,
|
||||
0x0079, 0x002D, 0x305D, 0x308C, 0x305E, 0x308C, 0x306E, 0x5834,
|
||||
0x6240
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "Hello-Another-Way--fc4qua05auwb3674vfr0b");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode14()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x3072, 0x3068, 0x3064, 0x5C4B, 0x6839, 0x306E, 0x4E0B, 0x0032
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "2-u9tlzr9756bt3uc0v");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode15()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x004D, 0x0061, 0x006A, 0x0069, 0x3067, 0x004B, 0x006F, 0x0069,
|
||||
0x3059, 0x308B, 0x0035, 0x79D2, 0x524D
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "MajiKoi5-783gue6qz075azm5e");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode16()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x30D1, 0x30D5, 0x30A3, 0x30FC, 0x0064, 0x0065, 0x30EB, 0x30F3, 0x30D0
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "de-jg4avhby1noc0d");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode17()
|
||||
{
|
||||
// Japanese
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x305D, 0x306E, 0x30B9, 0x30D4, 0x30FC, 0x30C9, 0x3067
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "d9juau41awczczp");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode18()
|
||||
{
|
||||
// Greek
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x03b5, 0x03bb, 0x03bb, 0x03b7, 0x03bd, 0x03b9, 0x03ba, 0x03ac
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "hxargifdar");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode19()
|
||||
{
|
||||
// Maltese (Malti)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x0062, 0x006f, 0x006e, 0x0121, 0x0075, 0x0073, 0x0061, 0x0127,
|
||||
0x0127, 0x0061
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "bonusaa-5bb1da");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testDecode20()
|
||||
{
|
||||
// Russian (Cyrillic)
|
||||
$expected = $this->hexarray2string(array(
|
||||
0x043f, 0x043e, 0x0447, 0x0435, 0x043c, 0x0443, 0x0436, 0x0435,
|
||||
0x043e, 0x043d, 0x0438, 0x043d, 0x0435, 0x0433, 0x043e, 0x0432,
|
||||
0x043e, 0x0440, 0x044f, 0x0442, 0x043f, 0x043e, 0x0440, 0x0443,
|
||||
0x0441, 0x0441, 0x043a, 0x0438
|
||||
));
|
||||
$result = $this->idn->decode(IDNA_ACE_PREFIX . "b1abfaaepdrnnbgefbadotcwatmq2g4l");
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
public function testEncode1()
|
||||
{
|
||||
// Arabic (Egyptian)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0644, 0x064A, 0x0647, 0x0645, 0x0627, 0x0628, 0x062A, 0x0643,
|
||||
0x0644, 0x0645, 0x0648, 0x0634, 0x0639, 0x0631, 0x0628, 0x064A,
|
||||
0x061F
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "egbpdaj6bu4bxfgehfvwxn", $result);
|
||||
}
|
||||
|
||||
public function testEncode2()
|
||||
{
|
||||
// Chinese (simplified)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x4ED6, 0x4EEC, 0x4E3A, 0x4EC0, 0x4E48, 0x4E0D, 0x8BF4, 0x4E2D, 0x6587
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "ihqwcrb4cv8a8dqg056pqjye", $result);
|
||||
}
|
||||
|
||||
public function testEncode3()
|
||||
{
|
||||
// Chinese (traditional)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x4ED6, 0x5011, 0x7232, 0x4EC0, 0x9EBD, 0x4E0D, 0x8AAA, 0x4E2D, 0x6587
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "ihqwctvzc91f659drss3x8bo0yb", $result);
|
||||
}
|
||||
|
||||
public function testEncode4()
|
||||
{
|
||||
// Czech
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0050, 0x0072, 0x006F, 0x010D, 0x0070, 0x0072, 0x006F, 0x0073,
|
||||
0x0074, 0x011B, 0x006E, 0x0065, 0x006D, 0x006C, 0x0075, 0x0076,
|
||||
0x00ED, 0x010D, 0x0065, 0x0073, 0x006B, 0x0079
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "proprostnemluvesky-uyb24dma41a", $result);
|
||||
}
|
||||
|
||||
public function testEncode5()
|
||||
{
|
||||
// Hebrew
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x05DC, 0x05DE, 0x05D4, 0x05D4, 0x05DD, 0x05E4, 0x05E9, 0x05D5,
|
||||
0x05D8, 0x05DC, 0x05D0, 0x05DE, 0x05D3, 0x05D1, 0x05E8, 0x05D9,
|
||||
0x05DD, 0x05E2, 0x05D1, 0x05E8, 0x05D9, 0x05EA
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "4dbcagdahymbxekheh6e0a7fei0b", $result);
|
||||
}
|
||||
|
||||
public function testEncode6()
|
||||
{
|
||||
// Hindi (Devanagari)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x092F, 0x0939, 0x0932, 0x094B, 0x0917, 0x0939, 0x093F, 0x0928,
|
||||
0x094D, 0x0926, 0x0940, 0x0915, 0x094D, 0x092F, 0x094B, 0x0902,
|
||||
0x0928, 0x0939, 0x0940, 0x0902, 0x092C, 0x094B, 0x0932, 0x0938,
|
||||
0x0915, 0x0924, 0x0947, 0x0939, 0x0948, 0x0902
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd", $result);
|
||||
}
|
||||
|
||||
public function testEncode7()
|
||||
{
|
||||
// Japanese (kanji and hiragana)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x306A, 0x305C, 0x307F, 0x3093, 0x306A, 0x65E5, 0x672C, 0x8A9E,
|
||||
0x3092, 0x8A71, 0x3057, 0x3066, 0x304F, 0x308C, 0x306A, 0x3044,
|
||||
0x306E, 0x304B
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa", $result);
|
||||
}
|
||||
|
||||
public function testEncode8()
|
||||
{
|
||||
// Russian (Cyrillic)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x043F, 0x043E, 0x0447, 0x0435, 0x043C, 0x0443, 0x0436, 0x0435,
|
||||
0x043E, 0x043D, 0x0438, 0x043D, 0x0435, 0x0433, 0x043E, 0x0432,
|
||||
0x043E, 0x0440, 0x044F, 0x0442, 0x043F, 0x043E, 0x0440, 0x0443,
|
||||
0x0441, 0x0441, 0x043A, 0x0438
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "b1abfaaepdrnnbgefbadotcwatmq2g4l", $result);
|
||||
}
|
||||
|
||||
public function testEncode9()
|
||||
{
|
||||
// Spanish
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0050, 0x006F, 0x0072, 0x0071, 0x0075, 0x00E9, 0x006E, 0x006F,
|
||||
0x0070, 0x0075, 0x0065, 0x0064, 0x0065, 0x006E, 0x0073, 0x0069,
|
||||
0x006D, 0x0070, 0x006C, 0x0065, 0x006D, 0x0065, 0x006E, 0x0074,
|
||||
0x0065, 0x0068, 0x0061, 0x0062, 0x006C, 0x0061, 0x0072, 0x0065,
|
||||
0x006E, 0x0045, 0x0073, 0x0070, 0x0061, 0x00F1, 0x006F, 0x006C
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "porqunopuedensimplementehablarenespaol-fmd56a", $result);
|
||||
}
|
||||
|
||||
public function testEncode10()
|
||||
{
|
||||
// Vietnamese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0054, 0x1EA1, 0x0069, 0x0073, 0x0061, 0x006F, 0x0068, 0x1ECD,
|
||||
0x006B, 0x0068, 0x00F4, 0x006E, 0x0067, 0x0074, 0x0068, 0x1EC3,
|
||||
0x0063, 0x0068, 0x1EC9, 0x006E, 0x00F3, 0x0069, 0x0074, 0x0069,
|
||||
0x1EBF, 0x006E, 0x0067, 0x0056, 0x0069, 0x1EC7, 0x0074
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "tisaohkhngthchnitingvit-kjcr8268qyxafd2f1b9g", $result);
|
||||
}
|
||||
|
||||
public function testEncode11()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "3b-ww4c5e180e575a65lsy2b", $result);
|
||||
}
|
||||
|
||||
public function testEncode12()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x5B89, 0x5BA4, 0x5948, 0x7F8E, 0x6075, 0x002D, 0x0077, 0x0069,
|
||||
0x0074, 0x0068, 0x002D, 0x0053, 0x0055, 0x0050, 0x0045, 0x0052,
|
||||
0x002D, 0x004D, 0x004F, 0x004E, 0x004B, 0x0045, 0x0059, 0x0053
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "-with-super-monkeys-pc58ag80a8qai00g7n9n", $result);
|
||||
}
|
||||
|
||||
public function testEncode13()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0048, 0x0065, 0x006C, 0x006C, 0x006F, 0x002D, 0x0041, 0x006E,
|
||||
0x006F, 0x0074, 0x0068, 0x0065, 0x0072, 0x002D, 0x0057, 0x0061,
|
||||
0x0079, 0x002D, 0x305D, 0x308C, 0x305E, 0x308C, 0x306E, 0x5834,
|
||||
0x6240
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "hello-another-way--fc4qua05auwb3674vfr0b", $result);
|
||||
}
|
||||
|
||||
public function testEncode14()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x3072, 0x3068, 0x3064, 0x5C4B, 0x6839, 0x306E, 0x4E0B, 0x0032
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "2-u9tlzr9756bt3uc0v", $result);
|
||||
}
|
||||
|
||||
public function testEncode15()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x004D, 0x0061, 0x006A, 0x0069, 0x3067, 0x004B, 0x006F, 0x0069,
|
||||
0x3059, 0x308B, 0x0035, 0x79D2, 0x524D
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "majikoi5-783gue6qz075azm5e", $result);
|
||||
}
|
||||
|
||||
public function testEncode16()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x30D1, 0x30D5, 0x30A3, 0x30FC, 0x0064, 0x0065, 0x30EB, 0x30F3, 0x30D0
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "de-jg4avhby1noc0d", $result);
|
||||
}
|
||||
|
||||
public function testEncode17()
|
||||
{
|
||||
// Japanese
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x305D, 0x306E, 0x30B9, 0x30D4, 0x30FC, 0x30C9, 0x3067
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "d9juau41awczczp", $result);
|
||||
}
|
||||
|
||||
public function testEncode18()
|
||||
{
|
||||
// Greek
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x03b5, 0x03bb, 0x03bb, 0x03b7, 0x03bd, 0x03b9, 0x03ba, 0x03ac
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "hxargifdar", $result);
|
||||
}
|
||||
|
||||
public function testEncode19()
|
||||
{
|
||||
// Maltese (Malti)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x0062, 0x006f, 0x006e, 0x0121, 0x0075, 0x0073, 0x0061, 0x0127,
|
||||
0x0127, 0x0061
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "bonusaa-5bb1da", $result);
|
||||
}
|
||||
|
||||
public function testEncode20()
|
||||
{
|
||||
// Russian (Cyrillic)
|
||||
$idna = $this->hexarray2string(array(
|
||||
0x043f, 0x043e, 0x0447, 0x0435, 0x043c, 0x0443, 0x0436, 0x0435,
|
||||
0x043e, 0x043d, 0x0438, 0x043d, 0x0435, 0x0433, 0x043e, 0x0432,
|
||||
0x043e, 0x0440, 0x044f, 0x0442, 0x043f, 0x043e, 0x0440, 0x0443,
|
||||
0x0441, 0x0441, 0x043a, 0x0438
|
||||
));
|
||||
$result = $this->idn->encode($idna);
|
||||
$this->assertSame(IDNA_ACE_PREFIX . "b1abfaaepdrnnbgefbadotcwatmq2g4l", $result);
|
||||
}
|
||||
}
|
||||
+546
-546
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+96
-103
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Error Stack Implementation
|
||||
*
|
||||
*
|
||||
* This is an incredibly simple implementation of a very complex error handling
|
||||
* facility. It contains the ability
|
||||
* to track multiple errors from multiple packages simultaneously. In addition,
|
||||
@@ -9,10 +9,10 @@
|
||||
* information such as the exact file, line number, class and function that
|
||||
* generated the error, and if necessary, it can raise a traditional PEAR_Error.
|
||||
* It has built-in support for PEAR::Log, to log errors as they occur
|
||||
*
|
||||
*
|
||||
* Since version 0.2alpha, it is also possible to selectively ignore errors,
|
||||
* through the use of an error callback, see {@link pushCallback()}
|
||||
*
|
||||
*
|
||||
* Since version 0.3alpha, it is possible to specify the exception class
|
||||
* returned from {@link push()}
|
||||
*
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/**
|
||||
* Singleton storage
|
||||
*
|
||||
*
|
||||
* Format:
|
||||
* <pre>
|
||||
* array(
|
||||
@@ -44,7 +44,7 @@ $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
|
||||
|
||||
/**
|
||||
* Global error callback (default)
|
||||
*
|
||||
*
|
||||
* This is only used if set to non-false. * is the default callback for
|
||||
* all packages, whereas specific packages may set a default callback
|
||||
* for all instances, regardless of whether they are a singleton or not.
|
||||
@@ -60,7 +60,7 @@ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
|
||||
|
||||
/**
|
||||
* Global Log object (default)
|
||||
*
|
||||
*
|
||||
* This is only used if set to non-false. Use to set a default log object for
|
||||
* all stacks, regardless of instantiation order or location
|
||||
* @see PEAR_ErrorStack::setDefaultLogger()
|
||||
@@ -71,7 +71,7 @@ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
|
||||
|
||||
/**
|
||||
* Global Overriding Callback
|
||||
*
|
||||
*
|
||||
* This callback will override any error callbacks that specific loggers have set.
|
||||
* Use with EXTREME caution
|
||||
* @see PEAR_ErrorStack::staticPushCallback()
|
||||
@@ -165,14 +165,14 @@ class PEAR_ErrorStack {
|
||||
* @access protected
|
||||
*/
|
||||
var $_package;
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether a PEAR_Error is thrown upon every error addition
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $_compat = false;
|
||||
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be used to generate the error
|
||||
* message from the error code, otherwise the message passed in will be
|
||||
@@ -181,7 +181,7 @@ class PEAR_ErrorStack {
|
||||
* @access private
|
||||
*/
|
||||
var $_msgCallback = false;
|
||||
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be used to generate the error
|
||||
* context for an error. For PHP-related errors, this will be a file
|
||||
@@ -236,10 +236,10 @@ class PEAR_ErrorStack {
|
||||
$this->setContextCallback($contextCallback);
|
||||
$this->_compat = $throwPEAR_Error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a single error stack for this package.
|
||||
*
|
||||
*
|
||||
* Note that all parameters are ignored if the stack for package $package
|
||||
* has already been instantiated
|
||||
* @param string $package name of the package this error stack represents
|
||||
@@ -275,7 +275,7 @@ class PEAR_ErrorStack {
|
||||
|
||||
/**
|
||||
* Internal error handler for PEAR_ErrorStack class
|
||||
*
|
||||
*
|
||||
* Dies if the error is an exception (and would have died anyway)
|
||||
* @access private
|
||||
*/
|
||||
@@ -292,10 +292,10 @@ class PEAR_ErrorStack {
|
||||
die($message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up a PEAR::Log object for all error stacks that don't have one
|
||||
* @param Log $log
|
||||
* @param Log $log
|
||||
*/
|
||||
public static function setDefaultLogger(&$log)
|
||||
{
|
||||
@@ -305,10 +305,10 @@ class PEAR_ErrorStack {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up a PEAR::Log object for this error stack
|
||||
* @param Log $log
|
||||
* @param Log $log
|
||||
*/
|
||||
function setLogger(&$log)
|
||||
{
|
||||
@@ -318,10 +318,10 @@ class PEAR_ErrorStack {
|
||||
$this->_logger = &$log;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set an error code => error message mapping callback
|
||||
*
|
||||
*
|
||||
* This method sets the callback that can be used to generate error
|
||||
* messages for any instance
|
||||
* @param array|string Callback function/method
|
||||
@@ -336,10 +336,10 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an error code => error message mapping callback
|
||||
*
|
||||
*
|
||||
* This method returns the current callback that can be used to generate error
|
||||
* messages
|
||||
* @return array|string|false Callback function/method or false if none
|
||||
@@ -348,10 +348,10 @@ class PEAR_ErrorStack {
|
||||
{
|
||||
return $this->_msgCallback;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a default callback to be used by all error stacks
|
||||
*
|
||||
*
|
||||
* This method sets the callback that can be used to generate error
|
||||
* messages for a singleton
|
||||
* @param array|string Callback function/method
|
||||
@@ -365,16 +365,14 @@ class PEAR_ErrorStack {
|
||||
$package = $package ? $package : '*';
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a callback that generates context information (location of error) for an error stack
|
||||
*
|
||||
*
|
||||
* This method sets the callback that can be used to generate context
|
||||
* information for an error. Passing in NULL will disable context generation
|
||||
* and remove the expensive call to debug_backtrace()
|
||||
* @param array|string|null Callback function/method
|
||||
* @return bool
|
||||
* @return array|bool|callable|false|string
|
||||
*/
|
||||
function setContextCallback($contextCallback)
|
||||
{
|
||||
@@ -382,23 +380,22 @@ class PEAR_ErrorStack {
|
||||
return $this->_contextCallback = false;
|
||||
}
|
||||
if (!$contextCallback) {
|
||||
$this->_contextCallback = [&$this, 'getFileLine'];
|
||||
$this->_contextCallback = array(&$this, 'getFileLine');
|
||||
} else {
|
||||
if (is_callable($contextCallback)) {
|
||||
$this->_contextCallback = $contextCallback;
|
||||
}
|
||||
}
|
||||
return $this->_contextCallback;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set an error Callback
|
||||
* If set to a valid callback, this will be called every time an error
|
||||
* is pushed onto the stack. The return value will be used to determine
|
||||
* whether to allow an error to be pushed or logged.
|
||||
*
|
||||
*
|
||||
* The return value must be one of the ERRORSTACK_* constants.
|
||||
*
|
||||
*
|
||||
* This functionality can be used to emulate PEAR's pushErrorHandling, and
|
||||
* the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
|
||||
* the error stack or logging
|
||||
@@ -410,7 +407,7 @@ class PEAR_ErrorStack {
|
||||
{
|
||||
array_push($this->_errorCallback, $cb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a callback from the error callback stack
|
||||
* @see pushCallback()
|
||||
@@ -423,7 +420,7 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return array_pop($this->_errorCallback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a temporary overriding error callback for every package error stack
|
||||
*
|
||||
@@ -437,7 +434,7 @@ class PEAR_ErrorStack {
|
||||
{
|
||||
array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a temporary overriding error callback
|
||||
* @see staticPushCallback()
|
||||
@@ -451,15 +448,15 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an error to the stack
|
||||
*
|
||||
*
|
||||
* If the message generator exists, it is called with 2 parameters.
|
||||
* - the current Error Stack object
|
||||
* - an array that is in the same format as an error. Available indices
|
||||
* are 'code', 'package', 'time', 'params', 'level', and 'context'
|
||||
*
|
||||
*
|
||||
* Next, if the error should contain context information, this is
|
||||
* handled by the context grabbing method.
|
||||
* Finally, the error is pushed onto the proper error stack
|
||||
@@ -477,7 +474,7 @@ class PEAR_ErrorStack {
|
||||
* @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
|
||||
* thrown. If a PEAR_Error is returned, the userinfo
|
||||
* property is set to the following array:
|
||||
*
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'code' => $code,
|
||||
@@ -490,7 +487,7 @@ class PEAR_ErrorStack {
|
||||
* //['repackage' => $err] repackaged error array/Exception class
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
*
|
||||
* Normally, the previous array is returned.
|
||||
*/
|
||||
function push($code, $level = 'error', $params = array(), $msg = false,
|
||||
@@ -504,19 +501,19 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
$context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
|
||||
}
|
||||
|
||||
|
||||
// save error
|
||||
$time = explode(' ', microtime());
|
||||
$time = $time[1] + $time[0];
|
||||
$err = array(
|
||||
'code' => $code,
|
||||
'params' => $params,
|
||||
'package' => $this->_package,
|
||||
'level' => $level,
|
||||
'time' => $time,
|
||||
'context' => $context,
|
||||
'message' => $msg,
|
||||
);
|
||||
'code' => $code,
|
||||
'params' => $params,
|
||||
'package' => $this->_package,
|
||||
'level' => $level,
|
||||
'time' => $time,
|
||||
'context' => $context,
|
||||
'message' => $msg,
|
||||
);
|
||||
|
||||
if ($repackage) {
|
||||
$err['repackage'] = $repackage;
|
||||
@@ -525,9 +522,9 @@ class PEAR_ErrorStack {
|
||||
// set up the error message, if necessary
|
||||
if ($this->_msgCallback) {
|
||||
$msg = call_user_func_array($this->_msgCallback,
|
||||
array(&$this, $err));
|
||||
array(&$this, $err));
|
||||
$err['message'] = $msg;
|
||||
}
|
||||
}
|
||||
$push = $log = true;
|
||||
$die = false;
|
||||
// try the overriding callback first
|
||||
@@ -549,18 +546,18 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
if (is_callable($callback)) {
|
||||
switch(call_user_func($callback, $err)){
|
||||
case PEAR_ERRORSTACK_IGNORE:
|
||||
return $err;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_PUSH:
|
||||
$log = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_LOG:
|
||||
$push = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_DIE:
|
||||
$die = true;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_IGNORE:
|
||||
return $err;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_PUSH:
|
||||
$log = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_LOG:
|
||||
$push = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_DIE:
|
||||
$die = true;
|
||||
break;
|
||||
// anything else returned has the same effect as pushandlog
|
||||
}
|
||||
}
|
||||
@@ -584,10 +581,10 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Static version of {@link push()}
|
||||
*
|
||||
*
|
||||
* @param string $package Package name this error belongs to
|
||||
* @param int $code Package-specific error code
|
||||
* @param string $level Error level. This is NOT spell-checked
|
||||
@@ -617,7 +614,7 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log an error using PEAR::Log
|
||||
* @param array $err Error array
|
||||
@@ -652,10 +649,10 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pop an error off of the error stack
|
||||
*
|
||||
*
|
||||
* @return false|array
|
||||
* @since 0.4alpha it is no longer possible to specify a specific error
|
||||
* level to return - the last error pushed will be returned, instead
|
||||
@@ -687,12 +684,11 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether there are any errors on the stack
|
||||
* @param string|array|bool $level name. Use to determine if any errors
|
||||
* @param string|array Level name. Use to determine if any errors
|
||||
* of level (string), or levels (array) have been pushed
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -703,10 +699,10 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return count($this->_errors);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve all errors since last purge
|
||||
*
|
||||
*
|
||||
* @param boolean set in order to empty the error stack
|
||||
* @param string level name, to return only errors of a particular severity
|
||||
* @return array
|
||||
@@ -740,7 +736,7 @@ class PEAR_ErrorStack {
|
||||
$this->_errorsByLevel = array();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether there are any errors on a single error stack, or on any error stack
|
||||
*
|
||||
@@ -765,7 +761,7 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of all errors since last purge, organized by package
|
||||
* @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
|
||||
@@ -775,7 +771,7 @@ class PEAR_ErrorStack {
|
||||
* @param array $sortfunc Function used to sort a merged array - default
|
||||
* sorts by time, and should be good for most cases
|
||||
*
|
||||
* @return array
|
||||
* @return array
|
||||
*/
|
||||
public static function staticGetErrors(
|
||||
$purge = false, $level = false, $merge = false,
|
||||
@@ -800,7 +796,7 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error sorting function, sorts by time
|
||||
* @access private
|
||||
@@ -840,8 +836,8 @@ class PEAR_ErrorStack {
|
||||
$functionframe = 0;
|
||||
} else {
|
||||
while (isset($backtrace[$functionframe]['function']) &&
|
||||
$backtrace[$functionframe]['function'] == 'eval' &&
|
||||
isset($backtrace[$functionframe + 1])) {
|
||||
$backtrace[$functionframe]['function'] == 'eval' &&
|
||||
isset($backtrace[$functionframe + 1])) {
|
||||
$functionframe++;
|
||||
}
|
||||
}
|
||||
@@ -852,11 +848,11 @@ class PEAR_ErrorStack {
|
||||
$funcbacktrace = $backtrace[$functionframe];
|
||||
$filebacktrace = $backtrace[$frame];
|
||||
$ret = array('file' => $filebacktrace['file'],
|
||||
'line' => $filebacktrace['line']);
|
||||
'line' => $filebacktrace['line']);
|
||||
// rearrange for eval'd code or create function errors
|
||||
if (strpos($filebacktrace['file'], '(') &&
|
||||
preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
|
||||
$matches)) {
|
||||
if (strpos($filebacktrace['file'], '(') &&
|
||||
preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
|
||||
$matches)) {
|
||||
$ret['file'] = $matches[1];
|
||||
$ret['line'] = $matches[2] + 0;
|
||||
}
|
||||
@@ -876,26 +872,26 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Standard error message generation callback
|
||||
*
|
||||
*
|
||||
* This method may also be called by a custom error message generator
|
||||
* to fill in template values from the params array, simply
|
||||
* set the third parameter to the error message template string to use
|
||||
*
|
||||
*
|
||||
* The special variable %__msg% is reserved: use it only to specify
|
||||
* where a message passed in by the user should be placed in the template,
|
||||
* like so:
|
||||
*
|
||||
*
|
||||
* Error message: %msg% - internal error
|
||||
*
|
||||
*
|
||||
* If the message passed like so:
|
||||
*
|
||||
*
|
||||
* <code>
|
||||
* $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
|
||||
* </code>
|
||||
*
|
||||
*
|
||||
* The returned error message will be "Error message: server error 500 -
|
||||
* internal error"
|
||||
* @param PEAR_ErrorStack
|
||||
@@ -933,7 +929,7 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $mainmsg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Standard Error Message Template generator from code
|
||||
* @return string
|
||||
@@ -945,42 +941,39 @@ class PEAR_ErrorStack {
|
||||
}
|
||||
return $this->_errorMsgs[$code];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the Error Message Template array
|
||||
*
|
||||
*
|
||||
* The array format must be:
|
||||
* <pre>
|
||||
* array(error code => 'message template',...)
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* Error message parameters passed into {@link push()} will be used as input
|
||||
* for the error message. If the template is 'message %foo% was %bar%', and the
|
||||
* parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
|
||||
* be 'message one was six'
|
||||
*
|
||||
* Returns string via property
|
||||
* @param $template
|
||||
* @return null
|
||||
* @return string
|
||||
*/
|
||||
function setErrorMessageTemplate($template)
|
||||
{
|
||||
$this->_errorMsgs = $template;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* emulate PEAR::raiseError()
|
||||
*
|
||||
*
|
||||
* @return PEAR_Error
|
||||
*/
|
||||
function raiseError()
|
||||
{
|
||||
require_once '../PEAR.php';
|
||||
require_once 'PEAR.php';
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array('PEAR', 'raiseError'), $args);
|
||||
}
|
||||
}
|
||||
$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
|
||||
$stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
|
||||
$stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
|
||||
?>
|
||||
|
||||
+122
-124
@@ -13,7 +13,6 @@
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Exception.php 313023 2011-07-06 19:17:11Z dufuz $
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since File available since Release 1.3.3
|
||||
*/
|
||||
@@ -89,7 +88,7 @@
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: 1.9.4
|
||||
* @version Release: @package_version@
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 1.3.3
|
||||
*
|
||||
@@ -99,9 +98,9 @@ class PEAR_Exception extends Exception
|
||||
const OBSERVER_PRINT = -2;
|
||||
const OBSERVER_TRIGGER = -4;
|
||||
const OBSERVER_DIE = -8;
|
||||
protected $cause;
|
||||
private static $_observers = array();
|
||||
private static $_uniqueid = 0;
|
||||
protected $cause;
|
||||
private $_trace;
|
||||
|
||||
/**
|
||||
@@ -117,7 +116,6 @@ class PEAR_Exception extends Exception
|
||||
* @param string exception message
|
||||
* @param int|Exception|PEAR_Error|array|null exception cause
|
||||
* @param int|null exception code or null
|
||||
* @throws PEAR_Exception
|
||||
*/
|
||||
public function __construct($message, $p2 = null, $p3 = null)
|
||||
{
|
||||
@@ -146,6 +144,32 @@ class PEAR_Exception extends Exception
|
||||
$this->signal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $callback - A valid php callback, see php func is_callable()
|
||||
* - A PEAR_Exception::OBSERVER_* constant
|
||||
* - An array(const PEAR_Exception::OBSERVER_*,
|
||||
* mixed $options)
|
||||
* @param string $label The name of the observer. Use this if you want
|
||||
* to remove it later with removeObserver()
|
||||
*/
|
||||
public static function addObserver($callback, $label = 'default')
|
||||
{
|
||||
self::$_observers[$label] = $callback;
|
||||
}
|
||||
|
||||
public static function removeObserver($label = 'default')
|
||||
{
|
||||
unset(self::$_observers[$label]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int unique identifier for an observer
|
||||
*/
|
||||
public static function getUniqueId()
|
||||
{
|
||||
return self::$_uniqueid++;
|
||||
}
|
||||
|
||||
private function signal()
|
||||
{
|
||||
foreach (self::$_observers as $func) {
|
||||
@@ -173,32 +197,6 @@ class PEAR_Exception extends Exception
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $callback - A valid php callback, see php func is_callable()
|
||||
* - A PEAR_Exception::OBSERVER_* constant
|
||||
* - An array(const PEAR_Exception::OBSERVER_*,
|
||||
* mixed $options)
|
||||
* @param string $label The name of the observer. Use this if you want
|
||||
* to remove it later with removeObserver()
|
||||
*/
|
||||
public static function addObserver($callback, $label = 'default')
|
||||
{
|
||||
self::$_observers[$label] = $callback;
|
||||
}
|
||||
|
||||
public static function removeObserver($label = 'default')
|
||||
{
|
||||
unset(self::$_observers[$label]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int unique identifier for an observer
|
||||
*/
|
||||
public static function getUniqueId()
|
||||
{
|
||||
return self::$_uniqueid++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return specific error information that can be used for more detailed
|
||||
* error messages or translation.
|
||||
@@ -228,6 +226,79 @@ class PEAR_Exception extends Exception
|
||||
return $this->cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function must be public to call on caused exceptions
|
||||
* @param array
|
||||
*/
|
||||
public function getCauseMessage(&$causes)
|
||||
{
|
||||
$trace = $this->getTraceSafe();
|
||||
$cause = array('class' => get_class($this),
|
||||
'message' => $this->message,
|
||||
'file' => 'unknown',
|
||||
'line' => 'unknown');
|
||||
if (isset($trace[0])) {
|
||||
if (isset($trace[0]['file'])) {
|
||||
$cause['file'] = $trace[0]['file'];
|
||||
$cause['line'] = $trace[0]['line'];
|
||||
}
|
||||
}
|
||||
$causes[] = $cause;
|
||||
if ($this->cause instanceof PEAR_Exception) {
|
||||
$this->cause->getCauseMessage($causes);
|
||||
} elseif ($this->cause instanceof Exception) {
|
||||
$causes[] = array('class' => get_class($this->cause),
|
||||
'message' => $this->cause->getMessage(),
|
||||
'file' => $this->cause->getFile(),
|
||||
'line' => $this->cause->getLine());
|
||||
} elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) {
|
||||
$causes[] = array('class' => get_class($this->cause),
|
||||
'message' => $this->cause->getMessage(),
|
||||
'file' => 'unknown',
|
||||
'line' => 'unknown');
|
||||
} elseif (is_array($this->cause)) {
|
||||
foreach ($this->cause as $cause) {
|
||||
if ($cause instanceof PEAR_Exception) {
|
||||
$cause->getCauseMessage($causes);
|
||||
} elseif ($cause instanceof Exception) {
|
||||
$causes[] = array('class' => get_class($cause),
|
||||
'message' => $cause->getMessage(),
|
||||
'file' => $cause->getFile(),
|
||||
'line' => $cause->getLine());
|
||||
} elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) {
|
||||
$causes[] = array('class' => get_class($cause),
|
||||
'message' => $cause->getMessage(),
|
||||
'file' => 'unknown',
|
||||
'line' => 'unknown');
|
||||
} elseif (is_array($cause) && isset($cause['message'])) {
|
||||
// PEAR_ErrorStack warning
|
||||
$causes[] = array(
|
||||
'class' => $cause['package'],
|
||||
'message' => $cause['message'],
|
||||
'file' => isset($cause['context']['file']) ?
|
||||
$cause['context']['file'] :
|
||||
'unknown',
|
||||
'line' => isset($cause['context']['line']) ?
|
||||
$cause['context']['line'] :
|
||||
'unknown',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTraceSafe()
|
||||
{
|
||||
if (!isset($this->_trace)) {
|
||||
$this->_trace = $this->getTrace();
|
||||
if (empty($this->_trace)) {
|
||||
$backtrace = debug_backtrace();
|
||||
$this->_trace = array($backtrace[count($backtrace)-1]);
|
||||
}
|
||||
}
|
||||
return $this->_trace;
|
||||
}
|
||||
|
||||
public function getErrorClass()
|
||||
{
|
||||
$trace = $this->getTraceSafe();
|
||||
@@ -253,22 +324,22 @@ class PEAR_Exception extends Exception
|
||||
$trace = $this->getTraceSafe();
|
||||
$causes = array();
|
||||
$this->getCauseMessage($causes);
|
||||
$html = '<table style="border: 1px" cellspacing="0">' . "\n";
|
||||
$html = '<table style="border: 1px" cellspacing="0">' . "\n";
|
||||
foreach ($causes as $i => $cause) {
|
||||
$html .= '<tr><td colspan="3" style="background: #ff9999">'
|
||||
. str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
|
||||
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
|
||||
. 'on line <b>' . $cause['line'] . '</b>'
|
||||
. "</td></tr>\n";
|
||||
. str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
|
||||
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
|
||||
. 'on line <b>' . $cause['line'] . '</b>'
|
||||
. "</td></tr>\n";
|
||||
}
|
||||
$html .= '<tr><td colspan="3" style="background-color: #aaaaaa; text-align: center; font-weight: bold;">Exception trace</td></tr>' . "\n"
|
||||
. '<tr><td style="text-align: center; background: #cccccc; width:20px; font-weight: bold;">#</td>'
|
||||
. '<td style="text-align: center; background: #cccccc; font-weight: bold;">Function</td>'
|
||||
. '<td style="text-align: center; background: #cccccc; font-weight: bold;">Location</td></tr>' . "\n";
|
||||
. '<tr><td style="text-align: center; background: #cccccc; width:20px; font-weight: bold;">#</td>'
|
||||
. '<td style="text-align: center; background: #cccccc; font-weight: bold;">Function</td>'
|
||||
. '<td style="text-align: center; background: #cccccc; font-weight: bold;">Location</td></tr>' . "\n";
|
||||
|
||||
foreach ($trace as $k => $v) {
|
||||
$html .= '<tr><td style="text-align: center;">' . $k . '</td>'
|
||||
. '<td>';
|
||||
. '<td>';
|
||||
if (!empty($v['class'])) {
|
||||
$html .= $v['class'] . $v['type'];
|
||||
}
|
||||
@@ -278,7 +349,7 @@ class PEAR_Exception extends Exception
|
||||
foreach ($v['args'] as $arg) {
|
||||
if (is_null($arg)) $args[] = 'null';
|
||||
elseif (is_array($arg)) $args[] = 'Array';
|
||||
elseif (is_object($arg)) $args[] = 'Object(' . get_class($arg) . ')';
|
||||
elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
|
||||
elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
|
||||
elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
|
||||
else {
|
||||
@@ -289,92 +360,19 @@ class PEAR_Exception extends Exception
|
||||
}
|
||||
}
|
||||
}
|
||||
$html .= '(' . implode(', ', $args) . ')'
|
||||
. '</td>'
|
||||
. '<td>' . (isset($v['file']) ? $v['file'] : 'unknown')
|
||||
. ':' . (isset($v['line']) ? $v['line'] : 'unknown')
|
||||
. '</td></tr>' . "\n";
|
||||
$html .= '(' . implode(', ',$args) . ')'
|
||||
. '</td>'
|
||||
. '<td>' . (isset($v['file']) ? $v['file'] : 'unknown')
|
||||
. ':' . (isset($v['line']) ? $v['line'] : 'unknown')
|
||||
. '</td></tr>' . "\n";
|
||||
}
|
||||
$html .= '<tr><td style="text-align: center;">' . ($k + 1) . '</td>'
|
||||
. '<td>{main}</td>'
|
||||
. '<td> </td></tr>' . "\n"
|
||||
. '</table>';
|
||||
$html .= '<tr><td style="text-align: center;">' . ($k+1) . '</td>'
|
||||
. '<td>{main}</td>'
|
||||
. '<td> </td></tr>' . "\n"
|
||||
. '</table>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function must be public to call on caused exceptions
|
||||
* @param array
|
||||
*/
|
||||
public function getCauseMessage(&$causes)
|
||||
{
|
||||
$trace = $this->getTraceSafe();
|
||||
$cause = array('class' => get_class($this),
|
||||
'message' => $this->message,
|
||||
'file' => 'unknown',
|
||||
'line' => 'unknown');
|
||||
if (isset($trace[0])) {
|
||||
if (isset($trace[0]['file'])) {
|
||||
$cause['file'] = $trace[0]['file'];
|
||||
$cause['line'] = $trace[0]['line'];
|
||||
}
|
||||
}
|
||||
$causes[] = $cause;
|
||||
if ($this->cause instanceof PEAR_Exception) {
|
||||
$this->cause->getCauseMessage($causes);
|
||||
} elseif ($this->cause instanceof Exception) {
|
||||
$causes[] = array('class' => get_class($this->cause),
|
||||
'message' => $this->cause->getMessage(),
|
||||
'file' => $this->cause->getFile(),
|
||||
'line' => $this->cause->getLine());
|
||||
} elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) {
|
||||
$causes[] = array('class' => get_class($this->cause),
|
||||
'message' => $this->cause->getMessage(),
|
||||
'file' => 'unknown',
|
||||
'line' => 'unknown');
|
||||
} elseif (is_array($this->cause)) {
|
||||
foreach ($this->cause as $cause) {
|
||||
if ($cause instanceof PEAR_Exception) {
|
||||
$cause->getCauseMessage($causes);
|
||||
} elseif ($cause instanceof Exception) {
|
||||
$causes[] = array('class' => get_class($cause),
|
||||
'message' => $cause->getMessage(),
|
||||
'file' => $cause->getFile(),
|
||||
'line' => $cause->getLine());
|
||||
} elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) {
|
||||
$causes[] = array('class' => get_class($cause),
|
||||
'message' => $cause->getMessage(),
|
||||
'file' => 'unknown',
|
||||
'line' => 'unknown');
|
||||
} elseif (is_array($cause) && isset($cause['message'])) {
|
||||
// PEAR_ErrorStack warning
|
||||
$causes[] = array(
|
||||
'class' => $cause['package'],
|
||||
'message' => $cause['message'],
|
||||
'file' => isset($cause['context']['file']) ?
|
||||
$cause['context']['file'] :
|
||||
'unknown',
|
||||
'line' => isset($cause['context']['line']) ?
|
||||
$cause['context']['line'] :
|
||||
'unknown',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTraceSafe()
|
||||
{
|
||||
if (!isset($this->_trace)) {
|
||||
$this->_trace = $this->getTrace();
|
||||
if (empty($this->_trace)) {
|
||||
$backtrace = debug_backtrace();
|
||||
$this->_trace = array($backtrace[count($backtrace) - 1]);
|
||||
}
|
||||
}
|
||||
return $this->_trace;
|
||||
}
|
||||
|
||||
public function toText()
|
||||
{
|
||||
$causes = array();
|
||||
@@ -382,8 +380,8 @@ class PEAR_Exception extends Exception
|
||||
$causeMsg = '';
|
||||
foreach ($causes as $i => $cause) {
|
||||
$causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
|
||||
. $cause['message'] . ' in ' . $cause['file']
|
||||
. ' on line ' . $cause['line'] . "\n";
|
||||
. $cause['message'] . ' in ' . $cause['file']
|
||||
. ' on line ' . $cause['line'] . "\n";
|
||||
}
|
||||
return $causeMsg . $this->getTraceAsString();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 1997-2009,
|
||||
Stig Bakken <ssb@php.net>,
|
||||
Gregory Beaver <cellog@php.net>,
|
||||
Helgi Þormar Þorbjörnsson <helgi@php.net>,
|
||||
Tomas V.V.Cox <cox@idecnet.com>,
|
||||
Martin Jansen <mj@php.net>.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,75 +0,0 @@
|
||||
--------------------------------------------------------------------
|
||||
The PHP License, version 2.02
|
||||
Copyright (c) 1999 - 2002 The PHP Group. All rights reserved.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
3. The name "PHP" must not be used to endorse or promote products
|
||||
derived from this software without prior permission from the
|
||||
PHP Group. This does not apply to add-on libraries or tools
|
||||
that work in conjunction with PHP. In such a case the PHP
|
||||
name may be used to indicate that the product supports PHP.
|
||||
|
||||
4. The PHP Group may publish revised and/or new versions of the
|
||||
license from time to time. Each version will be given a
|
||||
distinguishing version number.
|
||||
Once covered code has been published under a particular version
|
||||
of the license, you may always continue to use it under the
|
||||
terms of that version. You may also choose to use such covered
|
||||
code under the terms of any subsequent version of the license
|
||||
published by the PHP Group. No one other than the PHP Group has
|
||||
the right to modify the terms applicable to covered code created
|
||||
under this License.
|
||||
|
||||
5. Redistributions of any form whatsoever must retain the following
|
||||
acknowledgment:
|
||||
"This product includes PHP, freely available from
|
||||
http://www.php.net/".
|
||||
|
||||
6. The software incorporates the Zend Engine, a product of Zend
|
||||
Technologies, Ltd. ("Zend"). The Zend Engine is licensed to the
|
||||
PHP Association (pursuant to a grant from Zend that can be
|
||||
found at http://www.php.net/license/ZendGrant/) for
|
||||
distribution to you under this license agreement, only as a
|
||||
part of PHP. In the event that you separate the Zend Engine
|
||||
(or any portion thereof) from the rest of the software, or
|
||||
modify the Zend Engine, or any portion thereof, your use of the
|
||||
separated or modified Zend Engine software shall not be governed
|
||||
by this license, and instead shall be governed by the license
|
||||
set forth at http://www.zend.com/license/ZendLicense/.
|
||||
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals on behalf of the PHP Group.
|
||||
|
||||
The PHP Group can be contacted via Email at group@php.net.
|
||||
|
||||
For more information on the PHP Group and the PHP project,
|
||||
please see <http://www.php.net>.
|
||||
@@ -1,68 +0,0 @@
|
||||
--------------------------------------------------------------------
|
||||
The PHP License, version 3.01
|
||||
Copyright (c) 1999 - 2008 The PHP Group. All rights reserved.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
3. The name "PHP" must not be used to endorse or promote products
|
||||
derived from this software without prior written permission. For
|
||||
written permission, please contact group@php.net.
|
||||
|
||||
4. Products derived from this software may not be called "PHP", nor
|
||||
may "PHP" appear in their name, without prior written permission
|
||||
from group@php.net. You may indicate that your software works in
|
||||
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||
it "PHP Foo" or "phpfoo"
|
||||
|
||||
5. The PHP Group may publish revised and/or new versions of the
|
||||
license from time to time. Each version will be given a
|
||||
distinguishing version number.
|
||||
Once covered code has been published under a particular version
|
||||
of the license, you may always continue to use it under the terms
|
||||
of that version. You may also choose to use such covered code
|
||||
under the terms of any subsequent version of the license
|
||||
published by the PHP Group. No one other than the PHP Group has
|
||||
the right to modify the terms applicable to covered code created
|
||||
under this License.
|
||||
|
||||
6. Redistributions of any form whatsoever must retain the following
|
||||
acknowledgment:
|
||||
"This product includes PHP software, freely available from
|
||||
<http://www.php.net/software/>".
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals on behalf of the PHP Group.
|
||||
|
||||
The PHP Group can be contacted via Email at group@php.net.
|
||||
|
||||
For more information on the PHP Group and the PHP project,
|
||||
please see <http://www.php.net>.
|
||||
|
||||
PHP includes the Zend Engine, freely available at
|
||||
<http://www.zend.com>.
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
DO NOT "FIX" CODE IN THIS DIRECTORY.
|
||||
|
||||
ONLY UPSTREAM VERSIONS OF SOFTWARE GO IN THIS DIRECTORY.
|
||||
|
||||
This directory is provided as a courtesy to our users who might be
|
||||
unable or unwilling to find and install libraries we depend on.
|
||||
|
||||
If we "fix" software in this directory, we hamstring users who do the
|
||||
right thing and keep a single version of upstream libraries in a
|
||||
system-wide library. We introduce subtle and maddening bugs where
|
||||
our code is "accidentally" using the "wrong" library version. We may
|
||||
unwittingly interfere with other software that depends on the
|
||||
canonical release versions of those same libraries!
|
||||
|
||||
Forking upstream software for trivial reasons makes us bad citizens in
|
||||
the Open Source community and adds unnecessary heartache for our
|
||||
users. Don't make us "that" project.
|
||||
|
||||
Frequently Asked Questions
|
||||
--------------------------
|
||||
|
||||
Q: What should we do when we find a bug in upstream software?
|
||||
|
||||
A: First and foremost, REPORT THE BUG, and if possible send in a patch.
|
||||
|
||||
Watch for a release of the upstream software and integrate with it
|
||||
when it's released.
|
||||
|
||||
In the meantime, work around the bug, if at all possible. Usually,
|
||||
it's quite possible, if slightly harder or less efficient.
|
||||
|
||||
Q: What if the bug can't be worked around?
|
||||
|
||||
A: If the upstream developers have accepted a bug patch, it's
|
||||
undesirable but acceptable to apply that patch to the library in
|
||||
the extlib dir. Ideally, use a release version for upstream or a
|
||||
version control system snapshot.
|
||||
|
||||
Note that this is a last resort.
|
||||
|
||||
Q: What if upstream is unresponsive or won't accept a patch?
|
||||
|
||||
A: Try again.
|
||||
|
||||
Q: I tried again, and upstream is still unresponsive and nobody's
|
||||
checked on my patch. Now what?
|
||||
|
||||
A: If the upstream project is moribund and there's a way to adopt it,
|
||||
propose having the GNU social dev team adopt the project. Or, adopt
|
||||
it yourself.
|
||||
|
||||
Q: What if there's no upstream authority and it can't be adopted?
|
||||
|
||||
A: Then we fork it. Make a new name and a new version. Include it in
|
||||
lib/ instead of extlib/, and use the GNUsocial_* prefix to change
|
||||
the namespace to avoid collisions.
|
||||
|
||||
This is a last resort; consult with the rest of the dev group
|
||||
before taking this radical step.
|
||||
|
||||
List of external libraries
|
||||
--------------------------
|
||||
|
||||
A number of external PHP libraries are used to provide basic
|
||||
functionality and optional functionality for your system. For your
|
||||
convenience, they are available in the "extlib" directory of this
|
||||
package, and you do not have to download and install them. However,
|
||||
you may want to keep them up-to-date with the latest upstream version,
|
||||
and the URLs are listed here for your convenience.
|
||||
|
||||
- DB_DataObject http://pear.php.net/package/DB_DataObject
|
||||
- Validate http://pear.php.net/package/Validate
|
||||
- OpenID by Janrain, http://janrain.com/openid-enabled/
|
||||
- PEAR DB. Although this is an older data access system (new
|
||||
packages should use PDO), the OpenID libraries depend on PEAR DB
|
||||
or MDB2.
|
||||
- OAuth.php from http://oauth.googlecode.com/svn/code/php/
|
||||
(has been edited to avoid colliding autoload)
|
||||
- markdown.php from http://michelf.com/projects/php-markdown/
|
||||
- PEAR Mail, for sending out mail notifications
|
||||
http://pear.php.net/package/Mail
|
||||
- PEAR Net_SMTP, if you use the SMTP factory for notifications
|
||||
http://pear.php.net/package/Net_SMTP
|
||||
- PEAR Net_Socket, if you use the SMTP factory for notifications
|
||||
http://pear.php.net/package/Net_Socket
|
||||
- XMPPHP, the follow-up to Class.Jabber.php. Probably the best XMPP
|
||||
library available for PHP. https://github.com/heshanlk/XMPPHP. Note that
|
||||
as of this writing the version of this library that is available in
|
||||
the extlib directory is *significantly different* from the upstream
|
||||
version (patches have been submitted). Upgrading to the upstream
|
||||
version may render your GNU social site unable to send or receive XMPP
|
||||
messages.
|
||||
- Facebook library. Used for the Facebook application.
|
||||
- PEAR Validate is used for URL and email validation.
|
||||
- Console_GetOpt for parsing command-line options.
|
||||
- HTTP_Request2, a library for making HTTP requests.
|
||||
- PEAR Net_URL2 is an HTTP_Request2 dependency.
|
||||
- Michelf/Markdown.php Markdown parser library
|
||||
- Mf2/Parser.php microformats2 parser library
|
||||
|
||||
A design goal of GNU Social is that the basic Web functionality should
|
||||
work on even the most restrictive commercial hosting services.
|
||||
However, additional functionality, such as receiving messages by XMPP,
|
||||
require that you be able to run long-running processes on your account.
|
||||
In addition, posting by email require that you be able to install a mail
|
||||
filter in your mail server.
|
||||
@@ -0,0 +1,39 @@
|
||||
Most of this directory contents are patched PEAR libraries (necessary as PEAR packages are no longer maintained)
|
||||
|
||||
List of external libraries
|
||||
--------------------------
|
||||
|
||||
A number of external PHP libraries are used to provide basic
|
||||
functionality and optional functionality for your system. For your
|
||||
convenience, they are available in the "extlib" directory of this
|
||||
package, and you do not have to download and install them. However,
|
||||
you may want to keep them up-to-date with the latest upstream version,
|
||||
and the URLs are listed here for your convenience.
|
||||
|
||||
- DB_DataObject http://pear.php.net/package/DB_DataObject
|
||||
- Validate http://pear.php.net/package/Validate
|
||||
- PEAR Mail, for sending out mail notifications
|
||||
http://pear.php.net/package/Mail
|
||||
- PEAR Net_SMTP, if you use the SMTP factory for notifications
|
||||
http://pear.php.net/package/Net_SMTP
|
||||
- PEAR Net_Socket, if you use the SMTP factory for notifications
|
||||
http://pear.php.net/package/Net_Socket
|
||||
- OAuth.php from http://oauth.googlecode.com/svn/code/php/
|
||||
(has been edited to avoid colliding autoload)
|
||||
|
||||
|
||||
- PEAR Validate is used for URL and email validation.
|
||||
- Console_GetOpt for parsing command-line options.
|
||||
- HTTP_Request2, a library for making HTTP requests.
|
||||
- PEAR Net_URL2 is an HTTP_Request2 dependency.
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
- Port from PEAR NET to Guzzle
|
||||
- Port from PEAR DB to Doctrine DBAL
|
||||
- Port from PEAR mail to PHPMailer
|
||||
- eventually port OAuth to something more modern
|
||||
|
||||
Why not replace all the components with newer ones? We don't think the alternatives really meet our needs or are at
|
||||
all necessary and/or better solutions. The code of these patched libraries that we are maintaing is quite good.
|
||||
@@ -1,615 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright 2005-2006 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* vim: set expandtab tabstop=3 shiftwidth=3: */
|
||||
|
||||
require_once 'Stomp/Frame.php';
|
||||
|
||||
/**
|
||||
* A Stomp Connection
|
||||
*
|
||||
*
|
||||
* @package Stomp
|
||||
* @author Hiram Chirino <hiram@hiramchirino.com>
|
||||
* @author Dejan Bosanac <dejan@nighttale.net>
|
||||
* @author Michael Caplan <mcaplan@labnet.net>
|
||||
* @version $Revision: 43 $
|
||||
*/
|
||||
class Stomp
|
||||
{
|
||||
/**
|
||||
* Perform request synchronously
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $sync = false;
|
||||
|
||||
/**
|
||||
* Default prefetch size
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $prefetchSize = 1;
|
||||
|
||||
/**
|
||||
* Client id used for durable subscriptions
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $clientId = null;
|
||||
|
||||
protected $_brokerUri = null;
|
||||
protected $_socket = null;
|
||||
protected $_hosts = array();
|
||||
protected $_params = array();
|
||||
protected $_subscriptions = array();
|
||||
protected $_defaultPort = 61613;
|
||||
protected $_currentHost = - 1;
|
||||
protected $_attempts = 10;
|
||||
protected $_username = '';
|
||||
protected $_password = '';
|
||||
protected $_sessionId;
|
||||
protected $_read_timeout_seconds = 60;
|
||||
protected $_read_timeout_milliseconds = 0;
|
||||
protected $_connect_timeout_seconds = 60;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $brokerUri Broker URL
|
||||
* @throws StompException
|
||||
*/
|
||||
public function __construct ($brokerUri)
|
||||
{
|
||||
$this->_brokerUri = $brokerUri;
|
||||
$this->_init();
|
||||
}
|
||||
/**
|
||||
* Initialize connection
|
||||
*
|
||||
* @throws StompException
|
||||
*/
|
||||
protected function _init ()
|
||||
{
|
||||
$pattern = "|^(([a-zA-Z]+)://)+\(*([a-zA-Z0-9\.:/i,-]+)\)*\??([a-zA-Z0-9=]*)$|i";
|
||||
if (preg_match($pattern, $this->_brokerUri, $regs)) {
|
||||
$scheme = $regs[2];
|
||||
$hosts = $regs[3];
|
||||
$params = $regs[4];
|
||||
if ($scheme != "failover") {
|
||||
$this->_processUrl($this->_brokerUri);
|
||||
} else {
|
||||
$urls = explode(",", $hosts);
|
||||
foreach ($urls as $url) {
|
||||
$this->_processUrl($url);
|
||||
}
|
||||
}
|
||||
if ($params != null) {
|
||||
parse_str($params, $this->_params);
|
||||
}
|
||||
} else {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException("Bad Broker URL {$this->_brokerUri}");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Process broker URL
|
||||
*
|
||||
* @param string $url Broker URL
|
||||
* @throws StompException
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _processUrl ($url)
|
||||
{
|
||||
$parsed = parse_url($url);
|
||||
if ($parsed) {
|
||||
array_push($this->_hosts, array($parsed['host'] , $parsed['port'] , $parsed['scheme']));
|
||||
} else {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException("Bad Broker URL $url");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Make socket connection to the server
|
||||
*
|
||||
* @throws StompException
|
||||
*/
|
||||
protected function _makeConnection ()
|
||||
{
|
||||
if (count($this->_hosts) == 0) {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException("No broker defined");
|
||||
}
|
||||
|
||||
// force disconnect, if previous established connection exists
|
||||
$this->disconnect();
|
||||
|
||||
$i = $this->_currentHost;
|
||||
$att = 0;
|
||||
$connected = false;
|
||||
$connect_errno = null;
|
||||
$connect_errstr = null;
|
||||
|
||||
while (! $connected && $att ++ < $this->_attempts) {
|
||||
if (isset($this->_params['randomize']) && $this->_params['randomize'] == 'true') {
|
||||
$i = rand(0, count($this->_hosts) - 1);
|
||||
} else {
|
||||
$i = ($i + 1) % count($this->_hosts);
|
||||
}
|
||||
$broker = $this->_hosts[$i];
|
||||
$host = $broker[0];
|
||||
$port = $broker[1];
|
||||
$scheme = $broker[2];
|
||||
if ($port == null) {
|
||||
$port = $this->_defaultPort;
|
||||
}
|
||||
if ($this->_socket != null) {
|
||||
fclose($this->_socket);
|
||||
$this->_socket = null;
|
||||
}
|
||||
$this->_socket = @fsockopen($scheme . '://' . $host, $port, $connect_errno, $connect_errstr, $this->_connect_timeout_seconds);
|
||||
if (!is_resource($this->_socket) && $att >= $this->_attempts && !array_key_exists($i + 1, $this->_hosts)) {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException("Could not connect to $host:$port ($att/{$this->_attempts})");
|
||||
} else if (is_resource($this->_socket)) {
|
||||
$connected = true;
|
||||
$this->_currentHost = $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! $connected) {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException("Could not connect to a broker");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Connect to server
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
public function connect ($username = '', $password = '')
|
||||
{
|
||||
$this->_makeConnection();
|
||||
if ($username != '') {
|
||||
$this->_username = $username;
|
||||
}
|
||||
if ($password != '') {
|
||||
$this->_password = $password;
|
||||
}
|
||||
$headers = array('login' => $this->_username , 'passcode' => $this->_password);
|
||||
if ($this->clientId != null) {
|
||||
$headers["client-id"] = $this->clientId;
|
||||
}
|
||||
$frame = new StompFrame("CONNECT", $headers);
|
||||
$this->_writeFrame($frame);
|
||||
$frame = $this->readFrame();
|
||||
if ($frame instanceof StompFrame && $frame->command == 'CONNECTED') {
|
||||
$this->_sessionId = $frame->headers["session"];
|
||||
return true;
|
||||
} else {
|
||||
require_once 'Stomp/Exception.php';
|
||||
if ($frame instanceof StompFrame) {
|
||||
throw new StompException("Unexpected command: {$frame->command}", 0, $frame->body);
|
||||
} else {
|
||||
throw new StompException("Connection not acknowledged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if client session has ben established
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isConnected ()
|
||||
{
|
||||
return !empty($this->_sessionId) && is_resource($this->_socket);
|
||||
}
|
||||
/**
|
||||
* Current stomp session ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSessionId()
|
||||
{
|
||||
return $this->_sessionId;
|
||||
}
|
||||
/**
|
||||
* Send a message to a destination in the messaging system
|
||||
*
|
||||
* @param string $destination Destination queue
|
||||
* @param string|StompFrame $msg Message
|
||||
* @param array $properties
|
||||
* @param boolean $sync Perform request synchronously
|
||||
* @return boolean
|
||||
*/
|
||||
public function send ($destination, $msg, $properties = array(), $sync = null)
|
||||
{
|
||||
if ($msg instanceof StompFrame) {
|
||||
$msg->headers['destination'] = $destination;
|
||||
if (is_array($properties)) $msg->headers = array_merge($msg->headers, $properties);
|
||||
$frame = $msg;
|
||||
} else {
|
||||
$headers = $properties;
|
||||
$headers['destination'] = $destination;
|
||||
$frame = new StompFrame('SEND', $headers, $msg);
|
||||
}
|
||||
$this->_prepareReceipt($frame, $sync);
|
||||
$this->_writeFrame($frame);
|
||||
return $this->_waitForReceipt($frame, $sync);
|
||||
}
|
||||
/**
|
||||
* Prepair frame receipt
|
||||
*
|
||||
* @param StompFrame $frame
|
||||
* @param boolean $sync
|
||||
*/
|
||||
protected function _prepareReceipt (StompFrame $frame, $sync)
|
||||
{
|
||||
$receive = $this->sync;
|
||||
if ($sync !== null) {
|
||||
$receive = $sync;
|
||||
}
|
||||
if ($receive == true) {
|
||||
$frame->headers['receipt'] = md5(microtime());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Wait for receipt
|
||||
*
|
||||
* @param StompFrame $frame
|
||||
* @param boolean $sync
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
protected function _waitForReceipt (StompFrame $frame, $sync)
|
||||
{
|
||||
|
||||
$receive = $this->sync;
|
||||
if ($sync !== null) {
|
||||
$receive = $sync;
|
||||
}
|
||||
if ($receive == true) {
|
||||
$id = (isset($frame->headers['receipt'])) ? $frame->headers['receipt'] : null;
|
||||
if ($id == null) {
|
||||
return true;
|
||||
}
|
||||
$frame = $this->readFrame();
|
||||
if ($frame instanceof StompFrame && $frame->command == 'RECEIPT') {
|
||||
if ($frame->headers['receipt-id'] == $id) {
|
||||
return true;
|
||||
} else {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException("Unexpected receipt id {$frame->headers['receipt-id']}", 0, $frame->body);
|
||||
}
|
||||
} else {
|
||||
require_once 'Stomp/Exception.php';
|
||||
if ($frame instanceof StompFrame) {
|
||||
throw new StompException("Unexpected command {$frame->command}", 0, $frame->body);
|
||||
} else {
|
||||
throw new StompException("Receipt not received");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Register to listen to a given destination
|
||||
*
|
||||
* @param string $destination Destination queue
|
||||
* @param array $properties
|
||||
* @param boolean $sync Perform request synchronously
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
public function subscribe ($destination, $properties = null, $sync = null)
|
||||
{
|
||||
$headers = array('ack' => 'client');
|
||||
$headers['activemq.prefetchSize'] = $this->prefetchSize;
|
||||
$headers['prefetch-count'] = '1';
|
||||
|
||||
if ($this->clientId != null) {
|
||||
$headers["activemq.subcriptionName"] = $this->clientId;
|
||||
}
|
||||
if (isset($properties)) {
|
||||
foreach ($properties as $name => $value) {
|
||||
$headers[$name] = $value;
|
||||
}
|
||||
}
|
||||
$headers['destination'] = $destination;
|
||||
$frame = new StompFrame('SUBSCRIBE', $headers);
|
||||
$this->_prepareReceipt($frame, $sync);
|
||||
$this->_writeFrame($frame);
|
||||
if ($this->_waitForReceipt($frame, $sync) == true) {
|
||||
$this->_subscriptions[$destination] = $properties;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove an existing subscription
|
||||
*
|
||||
* @param string $destination
|
||||
* @param array $properties
|
||||
* @param boolean $sync Perform request synchronously
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
public function unsubscribe ($destination, $properties = null, $sync = null)
|
||||
{
|
||||
$headers = array();
|
||||
if (isset($properties)) {
|
||||
foreach ($properties as $name => $value) {
|
||||
$headers[$name] = $value;
|
||||
}
|
||||
}
|
||||
$headers['destination'] = $destination;
|
||||
$frame = new StompFrame('UNSUBSCRIBE', $headers);
|
||||
$this->_prepareReceipt($frame, $sync);
|
||||
$this->_writeFrame($frame);
|
||||
if ($this->_waitForReceipt($frame, $sync) == true) {
|
||||
unset($this->_subscriptions[$destination]);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Start a transaction
|
||||
*
|
||||
* @param string $transactionId
|
||||
* @param boolean $sync Perform request synchronously
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
public function begin ($transactionId = null, $sync = null)
|
||||
{
|
||||
$headers = array();
|
||||
if (isset($transactionId)) {
|
||||
$headers['transaction'] = $transactionId;
|
||||
}
|
||||
$frame = new StompFrame('BEGIN', $headers);
|
||||
$this->_prepareReceipt($frame, $sync);
|
||||
$this->_writeFrame($frame);
|
||||
return $this->_waitForReceipt($frame, $sync);
|
||||
}
|
||||
/**
|
||||
* Commit a transaction in progress
|
||||
*
|
||||
* @param string $transactionId
|
||||
* @param boolean $sync Perform request synchronously
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
public function commit ($transactionId = null, $sync = null)
|
||||
{
|
||||
$headers = array();
|
||||
if (isset($transactionId)) {
|
||||
$headers['transaction'] = $transactionId;
|
||||
}
|
||||
$frame = new StompFrame('COMMIT', $headers);
|
||||
$this->_prepareReceipt($frame, $sync);
|
||||
$this->_writeFrame($frame);
|
||||
return $this->_waitForReceipt($frame, $sync);
|
||||
}
|
||||
/**
|
||||
* Roll back a transaction in progress
|
||||
*
|
||||
* @param string $transactionId
|
||||
* @param boolean $sync Perform request synchronously
|
||||
*/
|
||||
public function abort ($transactionId = null, $sync = null)
|
||||
{
|
||||
$headers = array();
|
||||
if (isset($transactionId)) {
|
||||
$headers['transaction'] = $transactionId;
|
||||
}
|
||||
$frame = new StompFrame('ABORT', $headers);
|
||||
$this->_prepareReceipt($frame, $sync);
|
||||
$this->_writeFrame($frame);
|
||||
return $this->_waitForReceipt($frame, $sync);
|
||||
}
|
||||
/**
|
||||
* Acknowledge consumption of a message from a subscription
|
||||
* Note: This operation is always asynchronous
|
||||
*
|
||||
* @param string|StompFrame $messageMessage ID
|
||||
* @param string $transactionId
|
||||
* @return boolean
|
||||
* @throws StompException
|
||||
*/
|
||||
public function ack ($message, $transactionId = null)
|
||||
{
|
||||
if ($message instanceof StompFrame) {
|
||||
$headers = $message->headers;
|
||||
if (isset($transactionId)) {
|
||||
$headers['transaction'] = $transactionId;
|
||||
}
|
||||
$frame = new StompFrame('ACK', $headers);
|
||||
$this->_writeFrame($frame);
|
||||
return true;
|
||||
} else {
|
||||
$headers = array();
|
||||
if (isset($transactionId)) {
|
||||
$headers['transaction'] = $transactionId;
|
||||
}
|
||||
$headers['message-id'] = $message;
|
||||
$frame = new StompFrame('ACK', $headers);
|
||||
$this->_writeFrame($frame);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Graceful disconnect from the server
|
||||
*
|
||||
*/
|
||||
public function disconnect ()
|
||||
{
|
||||
$headers = array();
|
||||
|
||||
if ($this->clientId != null) {
|
||||
$headers["client-id"] = $this->clientId;
|
||||
}
|
||||
|
||||
if (is_resource($this->_socket)) {
|
||||
$this->_writeFrame(new StompFrame('DISCONNECT', $headers));
|
||||
fclose($this->_socket);
|
||||
}
|
||||
$this->_socket = null;
|
||||
$this->_sessionId = null;
|
||||
$this->_currentHost = -1;
|
||||
$this->_subscriptions = array();
|
||||
$this->_username = '';
|
||||
$this->_password = '';
|
||||
}
|
||||
/**
|
||||
* Write frame to server
|
||||
*
|
||||
* @param StompFrame $stompFrame
|
||||
*/
|
||||
protected function _writeFrame (StompFrame $stompFrame)
|
||||
{
|
||||
if (!is_resource($this->_socket)) {
|
||||
require_once 'Stomp/Exception.php';
|
||||
throw new StompException('Socket connection hasn\'t been established');
|
||||
}
|
||||
|
||||
$data = $stompFrame->__toString();
|
||||
$r = fwrite($this->_socket, $data, strlen($data));
|
||||
if ($r === false || $r == 0) {
|
||||
$this->_reconnect();
|
||||
$this->_writeFrame($stompFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set timeout to wait for content to read
|
||||
*
|
||||
* @param int $seconds_to_wait Seconds to wait for a frame
|
||||
* @param int $milliseconds Milliseconds to wait for a frame
|
||||
*/
|
||||
public function setReadTimeout($seconds, $milliseconds = 0)
|
||||
{
|
||||
$this->_read_timeout_seconds = $seconds;
|
||||
$this->_read_timeout_milliseconds = $milliseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read response frame from server
|
||||
*
|
||||
* @return StompFrame False when no frame to read
|
||||
*/
|
||||
public function readFrame ()
|
||||
{
|
||||
if (!$this->hasFrameToRead()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rb = 1024;
|
||||
$data = '';
|
||||
$end = false;
|
||||
|
||||
do {
|
||||
$read = fread($this->_socket, $rb);
|
||||
if ($read === false) {
|
||||
$this->_reconnect();
|
||||
return $this->readFrame();
|
||||
}
|
||||
$data .= $read;
|
||||
if (strpos($data, "\x00") !== false) {
|
||||
$end = true;
|
||||
$data = rtrim($data, "\n");
|
||||
}
|
||||
$len = strlen($data);
|
||||
} while ($len < 2 || $end == false);
|
||||
|
||||
list ($header, $body) = explode("\n\n", $data, 2);
|
||||
$header = explode("\n", $header);
|
||||
$headers = array();
|
||||
$command = null;
|
||||
foreach ($header as $v) {
|
||||
if (isset($command)) {
|
||||
list ($name, $value) = explode(':', $v, 2);
|
||||
$headers[$name] = $value;
|
||||
} else {
|
||||
$command = $v;
|
||||
}
|
||||
}
|
||||
$frame = new StompFrame($command, $headers, trim($body));
|
||||
if (isset($frame->headers['transformation']) && $frame->headers['transformation'] == 'jms-map-json') {
|
||||
require_once 'Stomp/Message/Map.php';
|
||||
return new StompMessageMap($frame);
|
||||
} else {
|
||||
return $frame;
|
||||
}
|
||||
return $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is a frame to read
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasFrameToRead()
|
||||
{
|
||||
$read = array($this->_socket);
|
||||
$write = null;
|
||||
$except = null;
|
||||
|
||||
$has_frame_to_read = @stream_select($read, $write, $except, $this->_read_timeout_seconds, $this->_read_timeout_milliseconds);
|
||||
|
||||
if ($has_frame_to_read !== false)
|
||||
$has_frame_to_read = count($read);
|
||||
|
||||
|
||||
if ($has_frame_to_read === false) {
|
||||
throw new StompException('Check failed to determine if the socket is readable');
|
||||
} else if ($has_frame_to_read > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconnects and renews subscriptions (if there were any)
|
||||
* Call this method when you detect connection problems
|
||||
*/
|
||||
protected function _reconnect ()
|
||||
{
|
||||
$subscriptions = $this->_subscriptions;
|
||||
|
||||
$this->connect($this->_username, $this->_password);
|
||||
foreach ($subscriptions as $dest => $properties) {
|
||||
$this->subscribe($dest, $properties);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Graceful object desruction
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright 2005-2006 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* vim: set expandtab tabstop=3 shiftwidth=3: */
|
||||
|
||||
/**
|
||||
* A Stomp Connection
|
||||
*
|
||||
*
|
||||
* @package Stomp
|
||||
*/
|
||||
class StompException extends Exception
|
||||
{
|
||||
protected $_details;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $code Error code
|
||||
* @param string $details Stomp server error details
|
||||
*/
|
||||
public function __construct($message = null, $code = 0, $details = '')
|
||||
{
|
||||
$this->_details = $details;
|
||||
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stomp server error details
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDetails()
|
||||
{
|
||||
return $this->_details;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright 2005-2006 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* vim: set expandtab tabstop=3 shiftwidth=3: */
|
||||
|
||||
/**
|
||||
* Stomp Frames are messages that are sent and received on a stomp connection.
|
||||
*
|
||||
* @package Stomp
|
||||
*/
|
||||
class StompFrame
|
||||
{
|
||||
public $command;
|
||||
public $headers = array();
|
||||
public $body;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $command
|
||||
* @param array $headers
|
||||
* @param string $body
|
||||
*/
|
||||
public function __construct ($command = null, $headers = null, $body = null)
|
||||
{
|
||||
$this->_init($command, $headers, $body);
|
||||
}
|
||||
|
||||
protected function _init ($command = null, $headers = null, $body = null)
|
||||
{
|
||||
$this->command = $command;
|
||||
if ($headers != null) {
|
||||
$this->headers = $headers;
|
||||
}
|
||||
$this->body = $body;
|
||||
|
||||
if ($this->command == 'ERROR') {
|
||||
require_once 'Exception.php';
|
||||
throw new StompException($this->headers['message'], 0, $this->body);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert frame to transportable string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$data = $this->command . "\n";
|
||||
|
||||
foreach ($this->headers as $name => $value) {
|
||||
$data .= $name . ": " . $value . "\n";
|
||||
}
|
||||
|
||||
$data .= "\n";
|
||||
$data .= $this->body;
|
||||
return $data .= "\x00";
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright 2005-2006 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* vim: set expandtab tabstop=3 shiftwidth=3: */
|
||||
|
||||
require_once 'Stomp/Frame.php';
|
||||
|
||||
/**
|
||||
* Basic text stomp message
|
||||
*
|
||||
* @package Stomp
|
||||
*/
|
||||
class StompMessage extends StompFrame
|
||||
{
|
||||
public function __construct ($body, $headers = null)
|
||||
{
|
||||
$this->_init("SEND", $headers, $body);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright 2005-2006 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* vim: set expandtab tabstop=3 shiftwidth=3: */
|
||||
|
||||
require_once 'Stomp/Message.php';
|
||||
|
||||
/**
|
||||
* Message that contains a stream of uninterpreted bytes
|
||||
*
|
||||
* @package Stomp
|
||||
* @author Dejan Bosanac <dejan@nighttale.net>
|
||||
* @version $Revision: 23 $
|
||||
*/
|
||||
class Stomp_Message_Bytes extends Stomp_Message
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $body
|
||||
* @param array $headers
|
||||
*/
|
||||
function __construct ($body, $headers = null)
|
||||
{
|
||||
$this->_init("SEND", $headers, $body);
|
||||
if ($this->headers == null) {
|
||||
$this->headers = array();
|
||||
}
|
||||
$this->headers['content-length'] = count($body);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright 2005-2006 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* vim: set expandtab tabstop=3 shiftwidth=3: */
|
||||
|
||||
require_once 'Stomp/Message.php';
|
||||
|
||||
/**
|
||||
* Message that contains a set of name-value pairs
|
||||
*
|
||||
* @package Stomp
|
||||
*/
|
||||
class StompMessageMap extends StompMessage
|
||||
{
|
||||
public $map;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param StompFrame|string $msg
|
||||
* @param array $headers
|
||||
*/
|
||||
function __construct ($msg, $headers = null)
|
||||
{
|
||||
if ($msg instanceof StompFrame) {
|
||||
$this->_init($msg->command, $msg->headers, $msg->body);
|
||||
$this->map = json_decode($msg->body, true);
|
||||
} else {
|
||||
$this->_init("SEND", $headers, $msg);
|
||||
if ($this->headers == null) {
|
||||
$this->headers = array();
|
||||
}
|
||||
$this->headers['transformation'] = 'jms-map-json';
|
||||
$this->body = json_encode($msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
+336
-336
@@ -22,194 +22,47 @@ require_once 'Console/Getopt.php';
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
|
||||
/**
|
||||
* System offers cross platform compatible system functions
|
||||
*
|
||||
* Static functions for different operations. Should work under
|
||||
* Unix and Windows. The names and usage has been taken from its respectively
|
||||
* GNU commands. The functions will return (bool) false on error and will
|
||||
* trigger the error with the PHP trigger_error() function (you can silence
|
||||
* the error by prefixing a '@' sign after the function call, but this
|
||||
* is not recommended practice. Instead use an error handler with
|
||||
* {@link set_error_handler()}).
|
||||
*
|
||||
* Documentation on this class you can find in:
|
||||
* http://pear.php.net/manual/
|
||||
*
|
||||
* Example usage:
|
||||
* if (!@System::rm('-r file1 dir1')) {
|
||||
* print "could not delete file1 or dir1";
|
||||
* }
|
||||
*
|
||||
* In case you need to to pass file names with spaces,
|
||||
* pass the params as an array:
|
||||
*
|
||||
* System::rm(array('-r', $file1, $dir1));
|
||||
*
|
||||
* @category pear
|
||||
* @package System
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: @package_version@
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 0.1
|
||||
* @static
|
||||
*/
|
||||
* System offers cross platform compatible system functions
|
||||
*
|
||||
* Static functions for different operations. Should work under
|
||||
* Unix and Windows. The names and usage has been taken from its respectively
|
||||
* GNU commands. The functions will return (bool) false on error and will
|
||||
* trigger the error with the PHP trigger_error() function (you can silence
|
||||
* the error by prefixing a '@' sign after the function call, but this
|
||||
* is not recommended practice. Instead use an error handler with
|
||||
* {@link set_error_handler()}).
|
||||
*
|
||||
* Documentation on this class you can find in:
|
||||
* http://pear.php.net/manual/
|
||||
*
|
||||
* Example usage:
|
||||
* if (!@System::rm('-r file1 dir1')) {
|
||||
* print "could not delete file1 or dir1";
|
||||
* }
|
||||
*
|
||||
* In case you need to to pass file names with spaces,
|
||||
* pass the params as an array:
|
||||
*
|
||||
* System::rm(array('-r', $file1, $dir1));
|
||||
*
|
||||
* @category pear
|
||||
* @package System
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: @package_version@
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 0.1
|
||||
* @static
|
||||
*/
|
||||
class System
|
||||
{
|
||||
/**
|
||||
* Concatenate files
|
||||
*
|
||||
* Usage:
|
||||
* 1) $var = System::cat('sample.txt test.txt');
|
||||
* 2) System::cat('sample.txt test.txt > final.txt');
|
||||
* 3) System::cat('sample.txt test.txt >> final.txt');
|
||||
*
|
||||
* Note: as the class use fopen, urls should work also
|
||||
*
|
||||
* @param string $args the arguments
|
||||
* @return boolean true on success
|
||||
*/
|
||||
public static function &cat($args)
|
||||
{
|
||||
$ret = null;
|
||||
$files = array();
|
||||
if (!is_array($args)) {
|
||||
$args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
$count_args = count($args);
|
||||
for ($i = 0; $i < $count_args; $i++) {
|
||||
if ($args[$i] == '>') {
|
||||
$mode = 'wb';
|
||||
$outputfile = $args[$i + 1];
|
||||
break;
|
||||
} elseif ($args[$i] == '>>') {
|
||||
$mode = 'ab+';
|
||||
$outputfile = $args[$i + 1];
|
||||
break;
|
||||
} else {
|
||||
$files[] = $args[$i];
|
||||
}
|
||||
}
|
||||
$outputfd = false;
|
||||
if (isset($mode)) {
|
||||
if (!$outputfd = fopen($outputfile, $mode)) {
|
||||
$err = System::raiseError("Could not open $outputfile");
|
||||
return $err;
|
||||
}
|
||||
$ret = true;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if (!$fd = fopen($file, 'r')) {
|
||||
System::raiseError("Could not open $file");
|
||||
continue;
|
||||
}
|
||||
while ($cont = fread($fd, 2048)) {
|
||||
if (is_resource($outputfd)) {
|
||||
fwrite($outputfd, $cont);
|
||||
} else {
|
||||
$ret .= $cont;
|
||||
}
|
||||
}
|
||||
fclose($fd);
|
||||
}
|
||||
if (is_resource($outputfd)) {
|
||||
fclose($outputfd);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output errors with PHP trigger_error(). You can silence the errors
|
||||
* with prefixing a "@" sign to the function call: @System::mkdir(..);
|
||||
*
|
||||
* @param mixed $error a PEAR error or a string with the error message
|
||||
* @return bool false
|
||||
*/
|
||||
protected static function raiseError($error)
|
||||
{
|
||||
if (PEAR::isError($error)) {
|
||||
$error = $error->getMessage();
|
||||
}
|
||||
trigger_error($error, E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates temporary files or directories. This function will remove
|
||||
* the created files when the scripts finish its execution.
|
||||
*
|
||||
* Usage:
|
||||
* 1) $tempfile = System::mktemp("prefix");
|
||||
* 2) $tempdir = System::mktemp("-d prefix");
|
||||
* 3) $tempfile = System::mktemp();
|
||||
* 4) $tempfile = System::mktemp("-t /var/tmp prefix");
|
||||
*
|
||||
* prefix -> The string that will be prepended to the temp name
|
||||
* (defaults to "tmp").
|
||||
* -d -> A temporary dir will be created instead of a file.
|
||||
* -t -> The target dir where the temporary (file|dir) will be created. If
|
||||
* this param is missing by default the env vars TMP on Windows or
|
||||
* TMPDIR in Unix will be used. If these vars are also missing
|
||||
* c:\windows\temp or /tmp will be used.
|
||||
*
|
||||
* @param string $args The arguments
|
||||
* @return mixed the full path of the created (file|dir) or false
|
||||
* @see System::tmpdir()
|
||||
*/
|
||||
public static function mktemp($args = null)
|
||||
{
|
||||
static $first_time = true;
|
||||
$opts = System::_parseArgs($args, 't:d');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'd') {
|
||||
$tmp_is_dir = true;
|
||||
} elseif ($opt[0] == 't') {
|
||||
$tmpdir = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
|
||||
if (!isset($tmpdir)) {
|
||||
$tmpdir = System::tmpdir();
|
||||
}
|
||||
|
||||
if (!System::mkDir(['-p', $tmpdir])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp = tempnam($tmpdir, $prefix);
|
||||
if (isset($tmp_is_dir)) {
|
||||
unlink($tmp); // be careful possible race condition here
|
||||
if (!mkdir($tmp, 0700)) {
|
||||
return System::raiseError("Unable to create temporary directory $tmpdir");
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['_System_temp_files'][] = $tmp;
|
||||
/*if (isset($tmp_is_dir)) {
|
||||
//$GLOBALS['_System_temp_files'][] = dirname($tmp);
|
||||
}*/
|
||||
|
||||
if ($first_time) {
|
||||
PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
|
||||
$first_time = false;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the commandline arguments of a function
|
||||
*
|
||||
* @param string $argv the commandline
|
||||
* @param string $short_options the allowed option short-tags
|
||||
* @param string $long_options the allowed option long-tags
|
||||
* @param string $argv the commandline
|
||||
* @param string $short_options the allowed option short-tags
|
||||
* @param string $long_options the allowed option long-tags
|
||||
* @return array the given options and there values
|
||||
*/
|
||||
public static function _parseArgs($argv, $short_options, $long_options = null)
|
||||
@@ -239,126 +92,117 @@ class System
|
||||
if (empty($a)) {
|
||||
continue;
|
||||
}
|
||||
$argv[$k] = trim($a);
|
||||
$argv[$k] = trim($a) ;
|
||||
}
|
||||
}
|
||||
|
||||
return (new Console_Getopt)->getopt2($argv, $short_options, $long_options);
|
||||
return Console_Getopt::getopt2($argv, $short_options, $long_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the temporal directory set in the system
|
||||
* by looking in its environments variables.
|
||||
* Note: php.ini-recommended removes the "E" from the variables_order setting,
|
||||
* making unavaible the $_ENV array, that s why we do tests with _ENV
|
||||
* Output errors with PHP trigger_error(). You can silence the errors
|
||||
* with prefixing a "@" sign to the function call: @System::mkdir(..);
|
||||
*
|
||||
* @return string The temporary directory on the system
|
||||
* @param mixed $error a PEAR error or a string with the error message
|
||||
* @return bool false
|
||||
*/
|
||||
public static function tmpdir()
|
||||
protected static function raiseError($error)
|
||||
{
|
||||
if (OS_WINDOWS) {
|
||||
if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
|
||||
return $var;
|
||||
}
|
||||
return getenv('SystemRoot') . '\temp';
|
||||
if (PEAR::isError($error)) {
|
||||
$error = $error->getMessage();
|
||||
}
|
||||
if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
|
||||
return $var;
|
||||
}
|
||||
return realpath('/tmp');
|
||||
trigger_error($error, E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make directories.
|
||||
* Creates a nested array representing the structure of a directory
|
||||
*
|
||||
* The -p option will create parent directories
|
||||
* @param string $args the name of the director(y|ies) to create
|
||||
* @return bool True for success
|
||||
* System::_dirToStruct('dir1', 0) =>
|
||||
* Array
|
||||
* (
|
||||
* [dirs] => Array
|
||||
* (
|
||||
* [0] => dir1
|
||||
* )
|
||||
*
|
||||
* [files] => Array
|
||||
* (
|
||||
* [0] => dir1/file2
|
||||
* [1] => dir1/file3
|
||||
* )
|
||||
* )
|
||||
* @param string $sPath Name of the directory
|
||||
* @param integer $maxinst max. deep of the lookup
|
||||
* @param integer $aktinst starting deep of the lookup
|
||||
* @param bool $silent if true, do not emit errors.
|
||||
* @return array the structure of the dir
|
||||
*/
|
||||
public static function mkDir($args)
|
||||
protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
|
||||
{
|
||||
$opts = System::_parseArgs($args, 'pm:');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
if (($dir = @opendir($sPath)) === false) {
|
||||
if (!$silent) {
|
||||
System::raiseError("Could not open dir $sPath");
|
||||
}
|
||||
return $struct; // XXX could not open error
|
||||
}
|
||||
|
||||
$mode = 0777; // default mode
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'p') {
|
||||
$create_parents = true;
|
||||
} elseif ($opt[0] == 'm') {
|
||||
// if the mode is clearly an octal number (starts with 0)
|
||||
// convert it to decimal
|
||||
if (strlen($opt[1]) && $opt[1]{0} == '0') {
|
||||
$opt[1] = octdec($opt[1]);
|
||||
$struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
|
||||
$list = array();
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
$list[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
natsort($list);
|
||||
if ($aktinst < $maxinst || $maxinst == 0) {
|
||||
foreach ($list as $val) {
|
||||
$path = $sPath . DIRECTORY_SEPARATOR . $val;
|
||||
if (is_dir($path) && !is_link($path)) {
|
||||
$tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
|
||||
$struct = array_merge_recursive($struct, $tmp);
|
||||
} else {
|
||||
// convert to int
|
||||
$opt[1] += 0;
|
||||
}
|
||||
$mode = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$ret = true;
|
||||
if (isset($create_parents)) {
|
||||
foreach ($opts[1] as $dir) {
|
||||
$dirstack = array();
|
||||
while ((!file_exists($dir) || !is_dir($dir)) &&
|
||||
$dir != DIRECTORY_SEPARATOR) {
|
||||
array_unshift($dirstack, $dir);
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
while ($newdir = array_shift($dirstack)) {
|
||||
if (!is_writeable(dirname($newdir))) {
|
||||
$ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mkdir($newdir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($opts[1] as $dir) {
|
||||
if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
|
||||
$ret = false;
|
||||
$struct['files'][] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
return $struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temporary files created my mkTemp. This function is executed
|
||||
* at script shutdown time
|
||||
* Creates a nested array representing the structure of a directory and files
|
||||
*
|
||||
* @param array $files Array listing files and dirs
|
||||
* @return array
|
||||
* @static
|
||||
* @see System::_dirToStruct()
|
||||
*/
|
||||
public static function _removeTmpFiles()
|
||||
protected static function _multipleToStruct($files)
|
||||
{
|
||||
if (count($GLOBALS['_System_temp_files'])) {
|
||||
$delete = $GLOBALS['_System_temp_files'];
|
||||
array_unshift($delete, '-r');
|
||||
System::rm($delete);
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
settype($files, 'array');
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($file) && !is_link($file)) {
|
||||
$tmp = System::_dirToStruct($file, 0);
|
||||
$struct = array_merge_recursive($tmp, $struct);
|
||||
} else {
|
||||
if (!in_array($file, $struct['files'])) {
|
||||
$struct['files'][] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rm command for removing files.
|
||||
* Supports multiple files and dirs and also recursive deletes
|
||||
*
|
||||
* @param string $args the arguments for rm
|
||||
* @param string $args the arguments for rm
|
||||
* @return mixed PEAR_Error or true for success
|
||||
* @static
|
||||
* @access public
|
||||
@@ -401,93 +245,249 @@ class System
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nested array representing the structure of a directory and files
|
||||
* Make directories.
|
||||
*
|
||||
* @param array $files Array listing files and dirs
|
||||
* @return array
|
||||
* @static
|
||||
* @see System::_dirToStruct()
|
||||
* The -p option will create parent directories
|
||||
* @param string $args the name of the director(y|ies) to create
|
||||
* @return bool True for success
|
||||
*/
|
||||
protected static function _multipleToStruct($files)
|
||||
public static function mkDir($args)
|
||||
{
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
settype($files, 'array');
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($file) && !is_link($file)) {
|
||||
$tmp = System::_dirToStruct($file, 0);
|
||||
$struct = array_merge_recursive($tmp, $struct);
|
||||
} else {
|
||||
if (!in_array($file, $struct['files'])) {
|
||||
$struct['files'][] = $file;
|
||||
$opts = System::_parseArgs($args, 'pm:');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
$mode = 0777; // default mode
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'p') {
|
||||
$create_parents = true;
|
||||
} elseif ($opt[0] == 'm') {
|
||||
// if the mode is clearly an octal number (starts with 0)
|
||||
// convert it to decimal
|
||||
if (strlen($opt[1]) && $opt[1]{0} == '0') {
|
||||
$opt[1] = octdec($opt[1]);
|
||||
} else {
|
||||
// convert to int
|
||||
$opt[1] += 0;
|
||||
}
|
||||
$mode = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$ret = true;
|
||||
if (isset($create_parents)) {
|
||||
foreach ($opts[1] as $dir) {
|
||||
$dirstack = array();
|
||||
while ((!file_exists($dir) || !is_dir($dir)) &&
|
||||
$dir != DIRECTORY_SEPARATOR) {
|
||||
array_unshift($dirstack, $dir);
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
while ($newdir = array_shift($dirstack)) {
|
||||
if (!is_writeable(dirname($newdir))) {
|
||||
$ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mkdir($newdir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach($opts[1] as $dir) {
|
||||
if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $struct;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nested array representing the structure of a directory
|
||||
* Concatenate files
|
||||
*
|
||||
* System::_dirToStruct('dir1', 0) =>
|
||||
* Array
|
||||
* (
|
||||
* [dirs] => Array
|
||||
* (
|
||||
* [0] => dir1
|
||||
* )
|
||||
* Usage:
|
||||
* 1) $var = System::cat('sample.txt test.txt');
|
||||
* 2) System::cat('sample.txt test.txt > final.txt');
|
||||
* 3) System::cat('sample.txt test.txt >> final.txt');
|
||||
*
|
||||
* [files] => Array
|
||||
* (
|
||||
* [0] => dir1/file2
|
||||
* [1] => dir1/file3
|
||||
* )
|
||||
* )
|
||||
* @param string $sPath Name of the directory
|
||||
* @param integer $maxinst max. deep of the lookup
|
||||
* @param integer $aktinst starting deep of the lookup
|
||||
* @param bool $silent if true, do not emit errors.
|
||||
* @return array the structure of the dir
|
||||
* Note: as the class use fopen, urls should work also
|
||||
*
|
||||
* @param string $args the arguments
|
||||
* @return boolean true on success
|
||||
*/
|
||||
protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
|
||||
public static function &cat($args)
|
||||
{
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
if (($dir = @opendir($sPath)) === false) {
|
||||
if (!$silent) {
|
||||
System::raiseError("Could not open dir $sPath");
|
||||
}
|
||||
return $struct; // XXX could not open error
|
||||
$ret = null;
|
||||
$files = array();
|
||||
if (!is_array($args)) {
|
||||
$args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
$struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
|
||||
$list = array();
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
$list[] = $file;
|
||||
$count_args = count($args);
|
||||
for ($i = 0; $i < $count_args; $i++) {
|
||||
if ($args[$i] == '>') {
|
||||
$mode = 'wb';
|
||||
$outputfile = $args[$i+1];
|
||||
break;
|
||||
} elseif ($args[$i] == '>>') {
|
||||
$mode = 'ab+';
|
||||
$outputfile = $args[$i+1];
|
||||
break;
|
||||
} else {
|
||||
$files[] = $args[$i];
|
||||
}
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
natsort($list);
|
||||
if ($aktinst < $maxinst || $maxinst == 0) {
|
||||
foreach ($list as $val) {
|
||||
$path = $sPath . DIRECTORY_SEPARATOR . $val;
|
||||
if (is_dir($path) && !is_link($path)) {
|
||||
$tmp = System::_dirToStruct($path, $maxinst, $aktinst + 1, $silent);
|
||||
$struct = array_merge_recursive($struct, $tmp);
|
||||
$outputfd = false;
|
||||
if (isset($mode)) {
|
||||
if (!$outputfd = fopen($outputfile, $mode)) {
|
||||
$err = System::raiseError("Could not open $outputfile");
|
||||
return $err;
|
||||
}
|
||||
$ret = true;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if (!$fd = fopen($file, 'r')) {
|
||||
System::raiseError("Could not open $file");
|
||||
continue;
|
||||
}
|
||||
while ($cont = fread($fd, 2048)) {
|
||||
if (is_resource($outputfd)) {
|
||||
fwrite($outputfd, $cont);
|
||||
} else {
|
||||
$struct['files'][] = $path;
|
||||
$ret .= $cont;
|
||||
}
|
||||
}
|
||||
fclose($fd);
|
||||
}
|
||||
if (is_resource($outputfd)) {
|
||||
fclose($outputfd);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates temporary files or directories. This function will remove
|
||||
* the created files when the scripts finish its execution.
|
||||
*
|
||||
* Usage:
|
||||
* 1) $tempfile = System::mktemp("prefix");
|
||||
* 2) $tempdir = System::mktemp("-d prefix");
|
||||
* 3) $tempfile = System::mktemp();
|
||||
* 4) $tempfile = System::mktemp("-t /var/tmp prefix");
|
||||
*
|
||||
* prefix -> The string that will be prepended to the temp name
|
||||
* (defaults to "tmp").
|
||||
* -d -> A temporary dir will be created instead of a file.
|
||||
* -t -> The target dir where the temporary (file|dir) will be created. If
|
||||
* this param is missing by default the env vars TMP on Windows or
|
||||
* TMPDIR in Unix will be used. If these vars are also missing
|
||||
* c:\windows\temp or /tmp will be used.
|
||||
*
|
||||
* @param string $args The arguments
|
||||
* @return mixed the full path of the created (file|dir) or false
|
||||
* @see System::tmpdir()
|
||||
*/
|
||||
public static function mktemp($args = null)
|
||||
{
|
||||
static $first_time = true;
|
||||
$opts = System::_parseArgs($args, 't:d');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
return $struct;
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'd') {
|
||||
$tmp_is_dir = true;
|
||||
} elseif ($opt[0] == 't') {
|
||||
$tmpdir = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
|
||||
if (!isset($tmpdir)) {
|
||||
$tmpdir = System::tmpdir();
|
||||
}
|
||||
|
||||
if (!System::mkDir(array('-p', $tmpdir))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp = tempnam($tmpdir, $prefix);
|
||||
if (isset($tmp_is_dir)) {
|
||||
unlink($tmp); // be careful possible race condition here
|
||||
if (!mkdir($tmp, 0700)) {
|
||||
return System::raiseError("Unable to create temporary directory $tmpdir");
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['_System_temp_files'][] = $tmp;
|
||||
if (isset($tmp_is_dir)) {
|
||||
//$GLOBALS['_System_temp_files'][] = dirname($tmp);
|
||||
}
|
||||
|
||||
if ($first_time) {
|
||||
PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
|
||||
$first_time = false;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temporary files created my mkTemp. This function is executed
|
||||
* at script shutdown time
|
||||
*/
|
||||
public static function _removeTmpFiles()
|
||||
{
|
||||
if (count($GLOBALS['_System_temp_files'])) {
|
||||
$delete = $GLOBALS['_System_temp_files'];
|
||||
array_unshift($delete, '-r');
|
||||
System::rm($delete);
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the temporal directory set in the system
|
||||
* by looking in its environments variables.
|
||||
* Note: php.ini-recommended removes the "E" from the variables_order setting,
|
||||
* making unavaible the $_ENV array, that s why we do tests with _ENV
|
||||
*
|
||||
* @return string The temporary directory on the system
|
||||
*/
|
||||
public static function tmpdir()
|
||||
{
|
||||
if (OS_WINDOWS) {
|
||||
if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
|
||||
return $var;
|
||||
}
|
||||
return getenv('SystemRoot') . '\temp';
|
||||
}
|
||||
if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
|
||||
return $var;
|
||||
}
|
||||
return realpath('/tmp');
|
||||
}
|
||||
|
||||
/**
|
||||
* The "which" command (show the full path of a command)
|
||||
*
|
||||
* @param string $program The command to search for
|
||||
* @param mixed $fallback Value to return if $program is not found
|
||||
* @param mixed $fallback Value to return if $program is not found
|
||||
*
|
||||
* @return mixed A string with the full path or false if not found
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
@@ -514,8 +514,8 @@ class System
|
||||
|
||||
if (OS_WINDOWS) {
|
||||
$exe_suffixes = getenv('PATHEXT')
|
||||
? explode(PATH_SEPARATOR, getenv('PATHEXT'))
|
||||
: array('.exe', '.bat', '.cmd', '.com');
|
||||
? explode(PATH_SEPARATOR, getenv('PATHEXT'))
|
||||
: array('.exe','.bat','.cmd','.com');
|
||||
// allow passing a command.exe param
|
||||
if (strpos($program, '.') !== false) {
|
||||
array_unshift($exe_suffixes, '');
|
||||
@@ -560,7 +560,7 @@ class System
|
||||
* -maxdepth <n> -> max depth of recursion
|
||||
* -name <pattern> -> search pattern (bash style). Multiple -name param allowed
|
||||
*
|
||||
* @param mixed Either array or string with the command line
|
||||
* @param mixed Either array or string with the command line
|
||||
* @return array Array of found files
|
||||
*/
|
||||
public static function find($args)
|
||||
@@ -579,8 +579,8 @@ class System
|
||||
for ($i = 0; $i < $args_count; $i++) {
|
||||
switch ($args[$i]) {
|
||||
case '-type':
|
||||
if (in_array($args[$i + 1], array('d', 'f'))) {
|
||||
if ($args[$i + 1] == 'd') {
|
||||
if (in_array($args[$i+1], array('d', 'f'))) {
|
||||
if ($args[$i+1] == 'd') {
|
||||
$do_files = false;
|
||||
} else {
|
||||
$do_dirs = false;
|
||||
@@ -589,15 +589,15 @@ class System
|
||||
$i++;
|
||||
break;
|
||||
case '-name':
|
||||
$name = preg_quote($args[$i + 1], '#');
|
||||
$name = preg_quote($args[$i+1], '#');
|
||||
// our magic characters ? and * have just been escaped,
|
||||
// so now we change the escaped versions to PCRE operators
|
||||
$name = strtr($name, array('\?' => '.', '\*' => '.*'));
|
||||
$patterns[] = '(' . $name . ')';
|
||||
$patterns[] = '('.$name.')';
|
||||
$i++;
|
||||
break;
|
||||
case '-maxdepth':
|
||||
$depth = $args[$i + 1];
|
||||
$depth = $args[$i+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -611,7 +611,7 @@ class System
|
||||
}
|
||||
if (count($patterns)) {
|
||||
$dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
|
||||
$pattern = '#(^|' . $dsq . ')' . implode('|', $patterns) . '($|' . $dsq . ')#';
|
||||
$pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#';
|
||||
$ret = array();
|
||||
$files_count = count($files);
|
||||
for ($i = 0; $i < $files_count; $i++) {
|
||||
|
||||
@@ -1,587 +0,0 @@
|
||||
<?php
|
||||
// {{{ license
|
||||
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP Version 4.0 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1997-2003 The PHP Group |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | This source file is subject to version 2.02 of the PHP license, |
|
||||
// | that is bundled with this package in the file LICENSE, and is |
|
||||
// | available at through the world-wide-web at |
|
||||
// | http://www.php.net/license/2_02.txt. |
|
||||
// | If you did not receive a copy of the PHP license and are unable to |
|
||||
// | obtain it through the world-wide-web, please send a note to |
|
||||
// | license@php.net so we can mail you a copy immediately. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Anders Johannsen <anders@johannsen.com> |
|
||||
// | Author: Dan Allen <dan@mojavelinux.com>
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
// $Id: Command.php,v 1.9 2007/04/20 21:08:48 cconstantine Exp $
|
||||
|
||||
// }}}
|
||||
// {{{ includes
|
||||
|
||||
require_once 'PEAR.php';
|
||||
require_once 'System.php';
|
||||
|
||||
// }}}
|
||||
// {{{ constants
|
||||
|
||||
define('SYSTEM_COMMAND_OK', 1);
|
||||
define('SYSTEM_COMMAND_ERROR', -1);
|
||||
define('SYSTEM_COMMAND_NO_SHELL', -2);
|
||||
define('SYSTEM_COMMAND_INVALID_SHELL', -3);
|
||||
define('SYSTEM_COMMAND_TMPDIR_ERROR', -4);
|
||||
define('SYSTEM_COMMAND_INVALID_OPERATOR', -5);
|
||||
define('SYSTEM_COMMAND_INVALID_COMMAND', -6);
|
||||
define('SYSTEM_COMMAND_OPERATOR_PLACEMENT',-7);
|
||||
define('SYSTEM_COMMAND_COMMAND_PLACEMENT', -8);
|
||||
define('SYSTEM_COMMAND_NOHUP_MISSING', -9);
|
||||
define('SYSTEM_COMMAND_NO_OUTPUT', -10);
|
||||
define('SYSTEM_COMMAND_STDERR', -11);
|
||||
define('SYSTEM_COMMAND_NONZERO_EXIT', -12);
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ class System_Command
|
||||
|
||||
/**
|
||||
* The System_Command:: class implements an abstraction for various ways
|
||||
* of executing commands (directly using the backtick operator,
|
||||
* as a background task after the script has terminated using
|
||||
* register_shutdown_function() or as a detached process using nohup).
|
||||
*
|
||||
* @author Anders Johannsen <anders@johannsen.com>
|
||||
* @author Dan Allen <dan@mojavelinux.com>
|
||||
* @version $Revision: 1.9 $
|
||||
*/
|
||||
|
||||
// }}}
|
||||
class System_Command {
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* Array of settings used when creating the shell command
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $options = array();
|
||||
|
||||
/**
|
||||
* Array of available shells to use to execute the command
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $shells = array();
|
||||
|
||||
/**
|
||||
* Array of available control operators used between commands
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $controlOperators = array();
|
||||
|
||||
/**
|
||||
* The system command to be executed
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $systemCommand = null;
|
||||
|
||||
/**
|
||||
* Previously added part to the command string
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $previousElement = null;
|
||||
|
||||
/**
|
||||
* Directory for writing stderr output
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $tmpDir = null;
|
||||
|
||||
/**
|
||||
* To allow the pear error object to accumulate when building
|
||||
* the command, we use the command status to keep track when
|
||||
* a pear error is raised
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
var $commandStatus = 0;
|
||||
|
||||
/**
|
||||
* Hold initialization PEAR_Error
|
||||
*
|
||||
* @var object
|
||||
* @access private
|
||||
**/
|
||||
var $_initError = null;
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Defines all necessary constants and sets defaults
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function System_Command($in_shell = null)
|
||||
{
|
||||
// Defining constants
|
||||
$this->options = array(
|
||||
'SEQUENCE' => true,
|
||||
'SHUTDOWN' => false,
|
||||
'SHELL' => $this->which($in_shell),
|
||||
'OUTPUT' => true,
|
||||
'NOHUP' => false,
|
||||
'BACKGROUND' => false,
|
||||
'STDERR' => false
|
||||
);
|
||||
|
||||
// prepare the available control operators
|
||||
$this->controlOperators = array(
|
||||
'PIPE' => '|',
|
||||
'AND' => '&&',
|
||||
'OR' => '||',
|
||||
'GROUP' => ';',
|
||||
'LFIFO' => '<',
|
||||
'RFIFO' => '>',
|
||||
);
|
||||
|
||||
// List of allowed/available shells
|
||||
$this->shells = array(
|
||||
'sh',
|
||||
'bash',
|
||||
'zsh',
|
||||
'tcsh',
|
||||
'csh',
|
||||
'ash',
|
||||
'sash',
|
||||
'esh',
|
||||
'ksh'
|
||||
);
|
||||
|
||||
// Find the first available shell
|
||||
if (empty($this->options['SHELL'])) {
|
||||
foreach ($this->shells as $shell) {
|
||||
if ($this->options['SHELL'] = $this->which($shell)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// see if we still have no shell
|
||||
if (empty($this->options['SHELL'])) {
|
||||
$this->_initError =& PEAR::raiseError(null, SYSTEM_COMMAND_NO_SHELL, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Caputre a temporary directory for capturing stderr from commands
|
||||
$this->tmpDir = System::tmpdir();
|
||||
if (!System::mkDir("-p {$this->tmpDir}")) {
|
||||
$this->_initError =& PEAR::raiseError(null, SYSTEM_COMMAND_TMPDIR_ERROR, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ setOption()
|
||||
|
||||
/**
|
||||
* Sets the value for an option. Each option should be set to true
|
||||
* or false; except the 'SHELL' option which should be a string
|
||||
* naming a shell. The options are:
|
||||
*
|
||||
* 'SEQUENCE' Allow a sequence command or not (right now this is always on);
|
||||
*
|
||||
* 'SHUTDOWN' Execute commands via a shutdown function;
|
||||
*
|
||||
* 'SHELL' Path to shell;
|
||||
*
|
||||
* 'OUTPUT' Output stdout from process;
|
||||
*
|
||||
* 'NOHUP' Use nohup to detach process;
|
||||
*
|
||||
* 'BACKGROUND' Run as a background process with &;
|
||||
*
|
||||
* 'STDERR' Output on stderr will raise an error, even if
|
||||
* the command's exit value is zero. The output from
|
||||
* stderr can be retrieved using the getDebugInfo()
|
||||
* method of the Pear_ERROR object returned by
|
||||
* execute().;
|
||||
*
|
||||
* @param string $in_option is a case-sensitive string,
|
||||
* corresponding to the option
|
||||
* that should be changed
|
||||
* @param mixed $in_setting is the new value for the option
|
||||
* @access public
|
||||
* @return bool true if succes, else false
|
||||
*/
|
||||
function setOption($in_option, $in_setting)
|
||||
{
|
||||
if ($this->_initError) {
|
||||
return $this->_initError;
|
||||
}
|
||||
|
||||
$option = strtoupper($in_option);
|
||||
|
||||
if (!isset($this->options[$option])) {
|
||||
PEAR::raiseError(null, SYSTEM_COMMAND_ERROR, null, E_USER_NOTICE, null, 'System_Command_Error', true);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($option) {
|
||||
case 'OUTPUT':
|
||||
case 'SHUTDOWN':
|
||||
case 'SEQUENCE':
|
||||
case 'BACKGROUND':
|
||||
case 'STDERR':
|
||||
$this->options[$option] = !empty($in_setting);
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 'SHELL':
|
||||
if (($shell = $this->which($in_setting)) !== false) {
|
||||
$this->options[$option] = $shell;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
PEAR::raiseError(null, SYSTEM_COMMAND_NO_SHELL, null, E_USER_NOTICE, $in_setting, 'System_Command_Error', true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOHUP':
|
||||
if (empty($in_setting)) {
|
||||
$this->options[$option] = false;
|
||||
}
|
||||
else if ($location = $this->which('nohup')) {
|
||||
$this->options[$option] = $location;
|
||||
}
|
||||
else {
|
||||
PEAR::raiseError(null, SYSTEM_COMMAND_NOHUP_MISSING, null, E_USER_NOTICE, null, 'System_Command_Error', true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ pushCommand()
|
||||
|
||||
/**
|
||||
* Used to push a command onto the running command to be executed
|
||||
*
|
||||
* @param string $in_command binary to be run
|
||||
* @param string $in_argument either an option or argument value, to be handled appropriately
|
||||
* @param string $in_argument
|
||||
* @param ...
|
||||
*
|
||||
* @access public
|
||||
* @return boolean true on success {or System_Command_Error Exception}
|
||||
*/
|
||||
function pushCommand($in_command)
|
||||
{
|
||||
if ($this->_initError) {
|
||||
return $this->_initError;
|
||||
}
|
||||
|
||||
if (!is_null($this->previousElement) && !in_array($this->previousElement, $this->controlOperators)) {
|
||||
$this->commandStatus = -1;
|
||||
$error = PEAR::raiseError(null, SYSTEM_COMMAND_COMMAND_PLACEMENT, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
}
|
||||
|
||||
// check for error here
|
||||
$command = escapeshellcmd($this->which($in_command));
|
||||
if ($command === false) {
|
||||
$error = PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_COMMAND, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
}
|
||||
|
||||
$argv = func_get_args();
|
||||
array_shift($argv);
|
||||
foreach($argv as $arg) {
|
||||
if (strpos($arg, '-') === 0) {
|
||||
$command .= ' ' . $arg;
|
||||
}
|
||||
elseif ($arg != '') {
|
||||
$command .= ' ' . escapeshellarg($arg);
|
||||
}
|
||||
}
|
||||
|
||||
$this->previousElement = $command;
|
||||
$this->systemCommand .= $command;
|
||||
|
||||
return isset($error) ? $error : true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ pushOperator()
|
||||
|
||||
/**
|
||||
* Used to push an operator onto the running command to be executed
|
||||
*
|
||||
* @param string $in_operator Either string reprentation of operator or system character
|
||||
*
|
||||
* @access public
|
||||
* @return boolean true on success {or System_Command_Error Exception}
|
||||
*/
|
||||
function pushOperator($in_operator)
|
||||
{
|
||||
if ($this->_initError) {
|
||||
return $this->_initError;
|
||||
}
|
||||
|
||||
$operator = isset($this->controlOperators[$in_operator]) ? $this->controlOperators[$in_operator] : $in_operator;
|
||||
|
||||
if (is_null($this->previousElement) || in_array($this->previousElement, $this->controlOperators)) {
|
||||
$this->commandStatus = -1;
|
||||
$error = PEAR::raiseError(null, SYSTEM_COMMAND_OPERATOR_PLACEMENT, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
}
|
||||
elseif (!in_array($operator, $this->controlOperators)) {
|
||||
$this->commandStatus = -1;
|
||||
$error = PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_OPERATOR, null, E_USER_WARNING, $operator, 'System_Command_Error', true);
|
||||
}
|
||||
|
||||
$this->previousElement = $operator;
|
||||
$this->systemCommand .= ' ' . $operator . ' ';
|
||||
return isset($error) ? $error : true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ execute()
|
||||
|
||||
/**
|
||||
* Executes the code according to given options
|
||||
*
|
||||
* @return bool true if success {or System_Command_Exception}
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function execute()
|
||||
{
|
||||
if ($this->_initError) {
|
||||
return $this->_initError;
|
||||
}
|
||||
|
||||
// if the command is empty or if the last element was a control operator, we can't continue
|
||||
if (is_null($this->previousElement) || $this->commandStatus == -1 || in_array($this->previousElement, $this->controlOperators)) {
|
||||
return PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_COMMAND, null, E_USER_WARNING, $this->systemCommand, 'System_Command_Error', true);
|
||||
}
|
||||
|
||||
// Warning about impossible mix of options
|
||||
if (!empty($this->options['OUTPUT'])) {
|
||||
if (!empty($this->options['SHUTDOWN']) || !empty($this->options['NOHUP'])) {
|
||||
return PEAR::raiseError(null, SYSTEM_COMMAND_NO_OUTPUT, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
}
|
||||
}
|
||||
|
||||
// if this is not going to stdout, then redirect to /dev/null
|
||||
if (empty($this->options['OUTPUT'])) {
|
||||
$this->systemCommand .= ' >/dev/null';
|
||||
}
|
||||
|
||||
$suffix = '';
|
||||
// run a command immune to hangups, with output to a non-tty
|
||||
if (!empty($this->options['NOHUP'])) {
|
||||
$this->systemCommand = $this->options['NOHUP'] . $this->systemCommand;
|
||||
}
|
||||
// run a background process (only if not nohup)
|
||||
elseif (!empty($this->options['BACKGROUND'])) {
|
||||
$suffix = ' &';
|
||||
}
|
||||
|
||||
// Register to be run on shutdown
|
||||
if (!empty($this->options['SHUTDOWN'])) {
|
||||
$line = "system(\"{$this->systemCommand}$suffix\");";
|
||||
$function = create_function('', $line);
|
||||
register_shutdown_function($function);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// send stderr to a file so that we can reap the error message
|
||||
$tmpFile = tempnam($this->tmpDir, 'System_Command-');
|
||||
$this->systemCommand .= ' 2>' . $tmpFile . $suffix;
|
||||
$shellPipe = $this->which('echo') . ' ' . escapeshellarg($this->systemCommand) . ' | ' . $this->options['SHELL'];
|
||||
exec($shellPipe, $result, $returnVal);
|
||||
|
||||
if ($returnVal !== 0) {
|
||||
// command returned nonzero; that's always an error
|
||||
$return = PEAR::raiseError(null, SYSTEM_COMMAND_NONZERO_EXIT, null, E_USER_WARNING, null, 'System_Command_Error', true);
|
||||
}
|
||||
else if (!$this->options['STDERR']) {
|
||||
// caller does not care about stderr; return success
|
||||
$return = implode("\n", $result);
|
||||
}
|
||||
else {
|
||||
// our caller cares about stderr; check stderr output
|
||||
clearstatcache();
|
||||
if (filesize($tmpFile) > 0) {
|
||||
// the command actually wrote to stderr
|
||||
$stderr_output = file_get_contents($tmpFile);
|
||||
$return = PEAR::raiseError(null, SYSTEM_COMMAND_STDERR, null, E_USER_WARNING, $stderr_output, 'System_Command_Error', true);
|
||||
} else {
|
||||
// total success; return stdout gathered by exec()
|
||||
$return = implode("\n", $result);
|
||||
}
|
||||
}
|
||||
|
||||
unlink($tmpFile);
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ which()
|
||||
|
||||
/**
|
||||
* Functionality similiar to unix 'which'. Searches the path
|
||||
* for the specified program.
|
||||
*
|
||||
* @param $cmd name of the executable to search for
|
||||
*
|
||||
* @access private
|
||||
* @return string returns the full path if found, false if not
|
||||
*/
|
||||
function which($in_cmd)
|
||||
{
|
||||
// only pass non-empty strings to System::which()
|
||||
if (!is_string($in_cmd) || '' === $in_cmd) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
// explicitly pass false as fallback value
|
||||
return System::which($in_cmd, false);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ reset()
|
||||
|
||||
/**
|
||||
* Prepare for a new command to be built
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function reset()
|
||||
{
|
||||
$this->previousElement = null;
|
||||
$this->systemCommand = null;
|
||||
$this->commandStatus = 0;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorMessage()
|
||||
|
||||
/**
|
||||
* Return a textual error message for a System_Command error code
|
||||
*
|
||||
* @param integer error code
|
||||
*
|
||||
* @return string error message, or false if the error code was
|
||||
* not recognized
|
||||
*/
|
||||
function errorMessage($in_value)
|
||||
{
|
||||
static $errorMessages;
|
||||
if (!isset($errorMessages)) {
|
||||
$errorMessages = array(
|
||||
SYSTEM_COMMAND_OK => 'no error',
|
||||
SYSTEM_COMMAND_ERROR => 'unknown error',
|
||||
SYSTEM_COMMAND_NO_SHELL => 'no shell found',
|
||||
SYSTEM_COMMAND_INVALID_SHELL => 'invalid shell',
|
||||
SYSTEM_COMMAND_TMPDIR_ERROR => 'could not create temporary directory',
|
||||
SYSTEM_COMMAND_INVALID_OPERATOR => 'control operator invalid',
|
||||
SYSTEM_COMMAND_INVALID_COMMAND => 'invalid system command',
|
||||
SYSTEM_COMMAND_OPERATOR_PLACEMENT => 'invalid placement of control operator',
|
||||
SYSTEM_COMMAND_COMMAND_PLACEMENT => 'invalid placement of command',
|
||||
SYSTEM_COMMAND_NOHUP_MISSING => 'nohup not found on system',
|
||||
SYSTEM_COMMAND_NO_OUTPUT => 'output not allowed',
|
||||
SYSTEM_COMMAND_STDERR => 'command wrote to stderr',
|
||||
SYSTEM_COMMAND_NONZERO_EXIT => 'non-zero exit value from command',
|
||||
);
|
||||
}
|
||||
|
||||
if (System_Command::isError($in_value)) {
|
||||
$in_value = $in_value->getCode();
|
||||
}
|
||||
|
||||
return isset($errorMessages[$in_value]) ? $errorMessages[$in_value] : $errorMessages[SYSTEM_COMMAND_ERROR];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ isError()
|
||||
|
||||
/**
|
||||
* Tell whether a result code from a System_Command method is an error
|
||||
*
|
||||
* @param int result code
|
||||
*
|
||||
* @return bool whether $in_value is an error
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function isError($in_value)
|
||||
{
|
||||
return (is_object($in_value) &&
|
||||
(strtolower(get_class($in_value)) == 'system_command_error' ||
|
||||
is_subclass_of($in_value, 'system_command_error')));
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
// {{{ class System_Command_Error
|
||||
|
||||
/**
|
||||
* System_Command_Error constructor.
|
||||
*
|
||||
* @param mixed System_Command error code, or string with error message.
|
||||
* @param integer what "error mode" to operate in
|
||||
* @param integer what error level to use for $mode & PEAR_ERROR_TRIGGER
|
||||
* @param mixed additional debug info, such as the last query
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @see PEAR_Error
|
||||
*/
|
||||
|
||||
// }}}
|
||||
class System_Command_Error extends PEAR_Error
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* Message in front of the error message
|
||||
* @var string $error_message_prefix
|
||||
*/
|
||||
var $error_message_prefix = 'System_Command Error: ';
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
function System_Command_Error($code = SYSTEM_COMMAND_ERROR, $mode = PEAR_ERROR_RETURN,
|
||||
$level = E_USER_NOTICE, $debuginfo = null)
|
||||
{
|
||||
if (is_int($code)) {
|
||||
$this->PEAR_Error(System_Command::errorMessage($code), $code, $mode, $level, $debuginfo);
|
||||
} else {
|
||||
$this->PEAR_Error("Invalid error code: $code", SYSTEM_COMMAND_ERROR, $mode, $level, $debuginfo);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
||||
+241
-406
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,22 @@
|
||||
Redistribution and use in source and binary forms, with or without modification
|
||||
, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, th
|
||||
is list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/
|
||||
or other materials provided with the distribution.
|
||||
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WA
|
||||
RRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABIL
|
||||
ITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR C
|
||||
ONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOW
|
||||
EVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILI
|
||||
TY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE U
|
||||
SE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker */
|
||||
// $Id$
|
||||
|
||||
require_once 'PEAR/PackageFileManager2.php';
|
||||
require_once 'PEAR/PackageFileManager/Git.php';
|
||||
|
||||
$pkg = new PEAR_PackageFileManager2;
|
||||
|
||||
$options = array(
|
||||
'simpleoutput' => true,
|
||||
'baseinstalldir' => '/',
|
||||
'packagefile' => 'package.xml',
|
||||
'packagedirectory' => dirname(__FILE__),
|
||||
'filelistgenerator' => 'Git',
|
||||
'dir_roles' => array(
|
||||
'tests' => 'test',
|
||||
'docs' => 'doc',
|
||||
'data' => 'data'
|
||||
),
|
||||
'ignore' => array(
|
||||
'package.xml',
|
||||
'package2.xml',
|
||||
'*.tgz',
|
||||
basename(__FILE__)
|
||||
)
|
||||
);
|
||||
|
||||
$pkg->setOptions($options);
|
||||
|
||||
$desc = <<<EOT
|
||||
Generic classes for representation and manipulation of
|
||||
dates, times and time zones without the need of timestamps,
|
||||
which is a huge limitation for PHP programs. Includes time zone data,
|
||||
time zone conversions and many date/time conversions.
|
||||
It does not rely on 32-bit system date stamps, so
|
||||
you can display calendars and compare dates that date
|
||||
pre 1970 and post 2038.
|
||||
|
||||
EOT;
|
||||
|
||||
$notes = <<<EOT
|
||||
QA release.
|
||||
Users are strongly encouraged to adopt to inbuilt DateTime functionality.
|
||||
|
||||
Bug #17730 Patch: Avoid ereg, using preg_match
|
||||
Doc Bug #15029 large Date_Span's cannot be created
|
||||
Bug #14929 Timezone summertime
|
||||
Bug #14856 America/Moncton longname and dstlongname missing
|
||||
Bug #14084 TZ variable being set wrecks global config
|
||||
Bug #13615 America/Toronto time-zone is missing longname and dstlongname
|
||||
Bug #13545 Date_Span::set() doesn't work when passed an int and format
|
||||
Req #13488 Please rename Methods format2 and format3
|
||||
EOT;
|
||||
|
||||
$summary = <<<EOT
|
||||
Generic date/time handling class for PEAR
|
||||
EOT;
|
||||
|
||||
// Some hard-coded stuffs.
|
||||
$pkg->setPackage('Date');
|
||||
$pkg->setSummary($summary);
|
||||
$pkg->setDescription($desc);
|
||||
$pkg->setChannel('pear.php.net');
|
||||
$pkg->setAPIVersion('1.5.0');
|
||||
$pkg->setReleaseVersion('1.5.0a2');
|
||||
$pkg->setReleaseStability('alpha');
|
||||
$pkg->setAPIStability('alpha');
|
||||
$pkg->setNotes($notes);
|
||||
$pkg->setPackageType('php');
|
||||
$pkg->setLicense('BSD License',
|
||||
'http://www.opensource.org/licenses/bsd-license.php');
|
||||
|
||||
// Add maintainers.
|
||||
$pkg->addMaintainer('lead', 'baba', 'Baba Buehler', 'baba@babaz.com', 'no');
|
||||
$pkg->addMaintainer('lead', 'pajoye', 'Pierre-Alain Joye', 'pajoye@php.net', 'no');
|
||||
$pkg->addMaintainer('lead', 'mohrt', 'Monte Ohrt', 'mohrt@php.net', 'no');
|
||||
$pkg->addMaintainer('lead', 'firman', 'Firman Wandayandi', 'firman@php.net');
|
||||
$pkg->addMaintainer('lead', 'c01234', 'C.A. Woodcock', 'c01234@netcomuk.co.uk');
|
||||
$pkg->addMaintainer('developer', 'alan_k', 'Alan Knowles', 'alan@akbkhome.com');
|
||||
$pkg->addMaintainer('helper', 'scar', 'Leonardo Dutra', 'scar@php.net');
|
||||
|
||||
// Core dependencies.
|
||||
$pkg->setPhpDep('4.3');
|
||||
$pkg->setPearinstallerDep('1.4.0');
|
||||
|
||||
//$pkg->addDependency("Numbers_Words", "0.15.0", "eq", "pkg", true);
|
||||
//$pkg->detectDependencies();
|
||||
|
||||
// Add some replacements.
|
||||
$pkg->addGlobalReplacement('package-info', '@package_version@', 'version');
|
||||
|
||||
// Generate file contents.
|
||||
$pkg->generateContents();
|
||||
|
||||
// Writes a package.xml.
|
||||
if (isset($_GET['make']) || (isset($_SERVER['argv']) && @$_SERVER['argv'][1] == 'make')) {
|
||||
$e = $pkg->writePackageFile();
|
||||
|
||||
// Some errors occurs.
|
||||
if (PEAR::isError($e)) {
|
||||
throw new Exception('Unable to write package file. Got message: ' .
|
||||
$e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$pkg->debugPackageFile();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: php
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* c-hanging-comment-ender-p: nil
|
||||
* End:
|
||||
*/
|
||||
?>
|
||||
@@ -0,0 +1,41 @@
|
||||
PACKAGE = php-gettext-$(VERSION)
|
||||
VERSION = 1.0.12
|
||||
|
||||
DIST_FILES = \
|
||||
gettext.php \
|
||||
gettext.inc \
|
||||
streams.php \
|
||||
AUTHORS \
|
||||
README \
|
||||
COPYING \
|
||||
Makefile \
|
||||
examples/index.php \
|
||||
examples/pigs_dropin.php \
|
||||
examples/pigs_fallback.php \
|
||||
examples/locale/sr_CS/LC_MESSAGES/messages.po \
|
||||
examples/locale/sr_CS/LC_MESSAGES/messages.mo \
|
||||
examples/locale/de_CH/LC_MESSAGES/messages.po \
|
||||
examples/locale/de_CH/LC_MESSAGES/messages.mo \
|
||||
examples/update \
|
||||
tests/LocalesTest.php \
|
||||
tests/ParsingTest.php
|
||||
|
||||
check:
|
||||
phpunit --verbose tests
|
||||
|
||||
dist: check
|
||||
if [ -d $(PACKAGE) ]; then \
|
||||
rm -rf $(PACKAGE); \
|
||||
fi; \
|
||||
mkdir $(PACKAGE); \
|
||||
if [ -d $(PACKAGE) ]; then \
|
||||
cp -rp --parents $(DIST_FILES) $(PACKAGE); \
|
||||
tar cvzf $(PACKAGE).tar.gz $(PACKAGE); \
|
||||
rm -rf $(PACKAGE); \
|
||||
fi;
|
||||
|
||||
sign: dist
|
||||
gpg --armor --sign --detach-sig $(PACKAGE).tar.gz
|
||||
|
||||
clean:
|
||||
rm -f $(PACKAGE).tar.gz $(PACKAGE).tar.gz.asc
|
||||
@@ -1,4 +1,4 @@
|
||||
PHP-gettext 1.0 (https://launchpad.net/php-gettext)
|
||||
PHP-gettext 1.0.12 (https://launchpad.net/php-gettext)
|
||||
|
||||
Copyright 2003, 2006, 2009 -- Danilo "angry with PHP[1]" Segan
|
||||
Licensed under GPLv2 (or any later version, see COPYING)
|
||||
@@ -28,7 +28,7 @@ Why?
|
||||
|
||||
I got used to having gettext work even without gettext
|
||||
library. It's there in my favourite language Python, so I was
|
||||
surprised that I couldn't find it in PHP. I even searched for it,
|
||||
surprised that I couldn't find it in PHP. I even Googled for it,
|
||||
but to no avail.
|
||||
|
||||
So, I said, what the heck, I'm going to write it for this
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>PHP-gettext examples</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>PHP-gettext</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>PHP-gettext provides a simple gettext replacement that works independently from the system's gettext abilities.
|
||||
It can read MO files and use them for translating strings.</p>
|
||||
<p>This version has the ability to cache all strings and translations to speed up the string lookup.
|
||||
While the cache is enabled by default, it can be switched off with the second parameter in the constructor (e.g. when using very large MO files
|
||||
that you don't want to keep in memory)</p>
|
||||
|
||||
|
||||
<h2>Examples</h2>
|
||||
<ul>
|
||||
<li><a href="pigs_dropin.php">PHP-gettext as a dropin replacement</a></li>
|
||||
<li><a href="pigs_fallback.php">PHP-gettext as a fallback solution</a></li>
|
||||
</ul>
|
||||
|
||||
<hr />
|
||||
<p>Copyright (c) 2003-2006 Danilo Segan</p>
|
||||
<p>Copyright (c) 2005-2006 Steven Armstrong</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,30 @@
|
||||
# Sample translation for PHP-gettext 1.0
|
||||
# Copyright (c) 2003 Danilo Segan <danilo@kvota.net>
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pigs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2003-10-23 04:50+0200\n"
|
||||
"PO-Revision-Date: 2003-11-01 23:40+0100\n"
|
||||
"Last-Translator: Danilo Segan <danilo@kvota.net>\n"
|
||||
"Language-Team: Serbian (sr) <danilo@kvota.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
#"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
#: pigs.php:19
|
||||
msgid ""
|
||||
"This is how the story goes.\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
"Und so geht die Geschichte.\n"
|
||||
"\n"
|
||||
|
||||
#: pigs.php:21
|
||||
#, php-format
|
||||
msgid "%d pig went to the market\n"
|
||||
msgid_plural "%d pigs went to the market\n"
|
||||
msgstr[0] "%d Schwein ging zum Markt\n"
|
||||
msgstr[1] "%d Schweine gingen zum Markt\n"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Sample translation for PHP-gettext 1.0
|
||||
# Copyright (c) 2003,2006 Danilo Segan <danilo@kvota.net>
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pigs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2003-10-23 04:50+0200\n"
|
||||
"PO-Revision-Date: 2006-02-02 21:06+0100\n"
|
||||
"Last-Translator: Danilo Segan <danilo@kvota.net>\n"
|
||||
"Language-Team: Serbian (sr) <danilo@kvota.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
|
||||
#: pigs.php:19
|
||||
msgid ""
|
||||
"This is how the story goes.\n"
|
||||
"\n"
|
||||
msgstr "Овако иде прича.\n\n"
|
||||
|
||||
#: pigs.php:21
|
||||
#, php-format
|
||||
msgid "%d pig went to the market\n"
|
||||
msgid_plural "%d pigs went to the market\n"
|
||||
msgstr[0] "%d мало прасе је отишло на пијац\n"
|
||||
msgstr[1] "%d мала прасета су отишла на пијац\n"
|
||||
msgstr[2] "%d малих прасића је отишло на пијац\n"
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
|
||||
Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
|
||||
|
||||
This file is part of PHP-gettext.
|
||||
|
||||
PHP-gettext is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
PHP-gettext 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with PHP-gettext; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// define constants
|
||||
define('PROJECT_DIR', realpath('./'));
|
||||
define('LOCALE_DIR', PROJECT_DIR .'/locale');
|
||||
define('DEFAULT_LOCALE', 'en_US');
|
||||
|
||||
require_once('../gettext.inc');
|
||||
|
||||
$supported_locales = array('en_US', 'sr_CS', 'de_CH');
|
||||
$encoding = 'UTF-8';
|
||||
|
||||
$locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
|
||||
|
||||
// gettext setup
|
||||
T_setlocale(LC_MESSAGES, $locale);
|
||||
// Set the text domain as 'messages'
|
||||
$domain = 'messages';
|
||||
bindtextdomain($domain, LOCALE_DIR);
|
||||
// bind_textdomain_codeset is supported only in PHP 4.2.0+
|
||||
if (function_exists('bind_textdomain_codeset')) {
|
||||
bind_textdomain_codeset($domain, $encoding);
|
||||
}
|
||||
textdomain($domain);
|
||||
|
||||
header("Content-type: text/html; charset=$encoding");
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>PHP-gettext dropin example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>PHP-gettext as a dropin replacement</h1>
|
||||
<p>Example showing how to use PHP-gettext as a dropin replacement for the native gettext library.</p>
|
||||
<?php
|
||||
print "<p>";
|
||||
foreach ($supported_locales as $l) {
|
||||
print "[<a href=\"?lang=$l\">$l</a>] ";
|
||||
}
|
||||
print "</p>\n";
|
||||
|
||||
if (!locale_emulation()) {
|
||||
print "<p>locale '$locale' is supported by your system, using native gettext implementation.</p>\n";
|
||||
} else {
|
||||
print "<p>locale '$locale' is _not_ supported on your system, using the default locale '". DEFAULT_LOCALE ."'.</p>\n";
|
||||
}
|
||||
?>
|
||||
|
||||
<hr />
|
||||
|
||||
<?php
|
||||
// using PHP-gettext
|
||||
print "<pre>";
|
||||
print _("This is how the story goes.\n\n");
|
||||
for ($number=6; $number>=0; $number--) {
|
||||
print sprintf(
|
||||
T_ngettext(
|
||||
"%d pig went to the market\n",
|
||||
"%d pigs went to the market\n",
|
||||
$number
|
||||
),
|
||||
$number
|
||||
);
|
||||
}
|
||||
print "</pre>\n";
|
||||
?>
|
||||
|
||||
<hr />
|
||||
<p>« <a href="./">back</a></p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
|
||||
Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
|
||||
|
||||
This file is part of PHP-gettext.
|
||||
|
||||
PHP-gettext is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
PHP-gettext 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with PHP-gettext; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// define constants
|
||||
define('PROJECT_DIR', realpath('./'));
|
||||
define('LOCALE_DIR', PROJECT_DIR .'/locale');
|
||||
define('DEFAULT_LOCALE', 'en_US');
|
||||
|
||||
require_once('../gettext.inc');
|
||||
|
||||
$supported_locales = array('en_US', 'sr_CS', 'de_CH');
|
||||
$encoding = 'UTF-8';
|
||||
|
||||
$locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
|
||||
|
||||
// gettext setup
|
||||
T_setlocale(LC_MESSAGES, $locale);
|
||||
// Set the text domain as 'messages'
|
||||
$domain = 'messages';
|
||||
T_bindtextdomain($domain, LOCALE_DIR);
|
||||
T_bind_textdomain_codeset($domain, $encoding);
|
||||
T_textdomain($domain);
|
||||
|
||||
header("Content-type: text/html; charset=$encoding");
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<title>PHP-gettext fallback example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>PHP-gettext as a fallback solution</h1>
|
||||
<p>Example showing how to use PHP-gettext as a fallback solution if the native gettext library is not available or the system does not support the requested locale.</p>
|
||||
|
||||
<?php
|
||||
print "<p>";
|
||||
foreach ($supported_locales as $l) {
|
||||
print "[<a href=\"?lang=$l\">$l</a>] ";
|
||||
}
|
||||
print "</p>\n";
|
||||
|
||||
if (!locale_emulation()) {
|
||||
print "<p>locale '$locale' is supported by your system, using native gettext implementation.</p>\n";
|
||||
} else {
|
||||
print "<p>locale '$locale' is <strong>not</strong> supported on your system, using custom gettext implementation.</p>\n";
|
||||
}
|
||||
?>
|
||||
|
||||
<hr />
|
||||
|
||||
<?php
|
||||
// using PHP-gettext
|
||||
print "<pre>";
|
||||
print T_("This is how the story goes.\n\n");
|
||||
for ($number=6; $number>=0; $number--) {
|
||||
print sprintf(
|
||||
T_ngettext(
|
||||
"%d pig went to the market\n",
|
||||
"%d pigs went to the market\n",
|
||||
$number
|
||||
),
|
||||
$number
|
||||
);
|
||||
}
|
||||
print "</pre>\n";
|
||||
?>
|
||||
|
||||
<hr />
|
||||
<p>« <a href="./">back</a></p>
|
||||
</body>
|
||||
</html>
|
||||
Arquivo executável
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
TEMPLATE=pigs.pot
|
||||
xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs_dropin.php
|
||||
if [ "x$1" = "x-p" ]; then
|
||||
msgfmt --statistics $TEMPLATE
|
||||
else
|
||||
if [ -f $1.po ]; then
|
||||
msgmerge -o .tmp$1.po $1.po $TEMPLATE
|
||||
mv .tmp$1.po $1.po
|
||||
msgfmt --statistics $1.po
|
||||
else
|
||||
echo "Usage: $0 [-p|<basename>]"
|
||||
fi
|
||||
fi
|
||||
Arquivo normal → Arquivo executável
+370
-343
@@ -33,259 +33,278 @@
|
||||
* second parameter in the constructor (e.g. whenusing very large MO files
|
||||
* that you don't want to keep in memory)
|
||||
*/
|
||||
class gettext_reader {
|
||||
//public:
|
||||
var $error = 0; // public variable that holds error code (0 if no error)
|
||||
class gettext_reader
|
||||
{
|
||||
//public:
|
||||
public $error = 0; // public variable that holds error code (0 if no error)
|
||||
|
||||
//private:
|
||||
var $BYTEORDER = 0; // 0: low endian, 1: big endian
|
||||
var $STREAM = NULL;
|
||||
var $short_circuit = false;
|
||||
var $enable_cache = false;
|
||||
var $originals = NULL; // offset of original table
|
||||
var $translations = NULL; // offset of translation table
|
||||
var $pluralheader = NULL; // cache header field for plural forms
|
||||
var $total = 0; // total string count
|
||||
var $table_originals = NULL; // table for original strings (offsets)
|
||||
var $table_translations = NULL; // table for translated strings (offsets)
|
||||
var $cache_translations = NULL; // original -> translation mapping
|
||||
public $BYTEORDER = 0; // 0: low endian, 1: big endian
|
||||
public $STREAM = null;
|
||||
public $short_circuit = false;
|
||||
public $enable_cache = false;
|
||||
public $originals = null; // offset of original table
|
||||
public $translations = null; // offset of translation table
|
||||
public $pluralheader = null; // cache header field for plural forms
|
||||
public $total = 0; // total string count
|
||||
public $table_originals = null; // table for original strings (offsets)
|
||||
public $table_translations = null; // table for translated strings (offsets)
|
||||
public $cache_translations = null; // original -> translation mapping
|
||||
|
||||
|
||||
/* Methods */
|
||||
|
||||
|
||||
/**
|
||||
* Reads a 32bit Integer from the Stream
|
||||
*
|
||||
* @access private
|
||||
* @return Integer from the Stream
|
||||
*/
|
||||
function readint() {
|
||||
if ($this->BYTEORDER == 0) {
|
||||
// low endian
|
||||
$input=unpack('V', $this->STREAM->read(4));
|
||||
return array_shift($input);
|
||||
} else {
|
||||
// big endian
|
||||
$input=unpack('N', $this->STREAM->read(4));
|
||||
return array_shift($input);
|
||||
}
|
||||
/**
|
||||
* Reads a 32bit Integer from the Stream
|
||||
*
|
||||
* @access private
|
||||
* @return Integer from the Stream
|
||||
*/
|
||||
public function readint()
|
||||
{
|
||||
if ($this->BYTEORDER == 0) {
|
||||
// low endian
|
||||
$input=unpack('V', $this->STREAM->read(4));
|
||||
return array_shift($input);
|
||||
} else {
|
||||
// big endian
|
||||
$input=unpack('N', $this->STREAM->read(4));
|
||||
return array_shift($input);
|
||||
}
|
||||
}
|
||||
|
||||
function read($bytes) {
|
||||
return $this->STREAM->read($bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array of Integers from the Stream
|
||||
*
|
||||
* @param int count How many elements should be read
|
||||
* @return Array of Integers
|
||||
*/
|
||||
function readintarray($count) {
|
||||
if ($this->BYTEORDER == 0) {
|
||||
// low endian
|
||||
return unpack('V'.$count, $this->STREAM->read(4 * $count));
|
||||
} else {
|
||||
// big endian
|
||||
return unpack('N'.$count, $this->STREAM->read(4 * $count));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object Reader the StreamReader object
|
||||
* @param boolean enable_cache Enable or disable caching of strings (default on)
|
||||
*/
|
||||
function gettext_reader($Reader, $enable_cache = true) {
|
||||
// If there isn't a StreamReader, turn on short circuit mode.
|
||||
if (! $Reader || isset($Reader->error) ) {
|
||||
$this->short_circuit = true;
|
||||
return;
|
||||
public function read($bytes)
|
||||
{
|
||||
return $this->STREAM->read($bytes);
|
||||
}
|
||||
|
||||
// Caching can be turned off
|
||||
$this->enable_cache = $enable_cache;
|
||||
|
||||
$MAGIC1 = "\x95\x04\x12\xde";
|
||||
$MAGIC2 = "\xde\x12\x04\x95";
|
||||
|
||||
$this->STREAM = $Reader;
|
||||
$magic = $this->read(4);
|
||||
if ($magic == $MAGIC1) {
|
||||
$this->BYTEORDER = 1;
|
||||
} elseif ($magic == $MAGIC2) {
|
||||
$this->BYTEORDER = 0;
|
||||
} else {
|
||||
$this->error = 1; // not MO file
|
||||
return false;
|
||||
/**
|
||||
* Reads an array of Integers from the Stream
|
||||
*
|
||||
* @param int count How many elements should be read
|
||||
* @return Array of Integers
|
||||
*/
|
||||
public function readintarray($count)
|
||||
{
|
||||
if ($this->BYTEORDER == 0) {
|
||||
// low endian
|
||||
return unpack('V'.$count, $this->STREAM->read(4 * $count));
|
||||
} else {
|
||||
// big endian
|
||||
return unpack('N'.$count, $this->STREAM->read(4 * $count));
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Do we care about revision? We should.
|
||||
$revision = $this->readint();
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object Reader the StreamReader object
|
||||
* @param boolean enable_cache Enable or disable caching of strings (default on)
|
||||
*/
|
||||
public function gettext_reader($Reader, $enable_cache = true)
|
||||
{
|
||||
// If there isn't a StreamReader, turn on short circuit mode.
|
||||
if (! $Reader || isset($Reader->error)) {
|
||||
$this->short_circuit = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->total = $this->readint();
|
||||
$this->originals = $this->readint();
|
||||
$this->translations = $this->readint();
|
||||
}
|
||||
// Caching can be turned off
|
||||
$this->enable_cache = $enable_cache;
|
||||
|
||||
/**
|
||||
* Loads the translation tables from the MO file into the cache
|
||||
* If caching is enabled, also loads all strings into a cache
|
||||
* to speed up translation lookups
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function load_tables() {
|
||||
if (is_array($this->cache_translations) &&
|
||||
$MAGIC1 = "\x95\x04\x12\xde";
|
||||
$MAGIC2 = "\xde\x12\x04\x95";
|
||||
|
||||
$this->STREAM = $Reader;
|
||||
$magic = $this->read(4);
|
||||
if ($magic == $MAGIC1) {
|
||||
$this->BYTEORDER = 1;
|
||||
} elseif ($magic == $MAGIC2) {
|
||||
$this->BYTEORDER = 0;
|
||||
} else {
|
||||
$this->error = 1; // not MO file
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: Do we care about revision? We should.
|
||||
$revision = $this->readint();
|
||||
|
||||
$this->total = $this->readint();
|
||||
$this->originals = $this->readint();
|
||||
$this->translations = $this->readint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the translation tables from the MO file into the cache
|
||||
* If caching is enabled, also loads all strings into a cache
|
||||
* to speed up translation lookups
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
public function load_tables()
|
||||
{
|
||||
if (is_array($this->cache_translations) &&
|
||||
is_array($this->table_originals) &&
|
||||
is_array($this->table_translations))
|
||||
return;
|
||||
is_array($this->table_translations)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* get original and translations tables */
|
||||
if (!is_array($this->table_originals)) {
|
||||
$this->STREAM->seekto($this->originals);
|
||||
$this->table_originals = $this->readintarray($this->total * 2);
|
||||
}
|
||||
if (!is_array($this->table_translations)) {
|
||||
$this->STREAM->seekto($this->translations);
|
||||
$this->table_translations = $this->readintarray($this->total * 2);
|
||||
/* get original and translations tables */
|
||||
if (!is_array($this->table_originals)) {
|
||||
$this->STREAM->seekto($this->originals);
|
||||
$this->table_originals = $this->readintarray($this->total * 2);
|
||||
}
|
||||
if (!is_array($this->table_translations)) {
|
||||
$this->STREAM->seekto($this->translations);
|
||||
$this->table_translations = $this->readintarray($this->total * 2);
|
||||
}
|
||||
|
||||
if ($this->enable_cache) {
|
||||
$this->cache_translations = array();
|
||||
/* read all strings in the cache */
|
||||
for ($i = 0; $i < $this->total; $i++) {
|
||||
$this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
|
||||
$original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
|
||||
$this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
|
||||
$translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
|
||||
$this->cache_translations[$original] = $translation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->enable_cache) {
|
||||
$this->cache_translations = array ();
|
||||
/* read all strings in the cache */
|
||||
for ($i = 0; $i < $this->total; $i++) {
|
||||
$this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
|
||||
$original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
|
||||
$this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
|
||||
$translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
|
||||
$this->cache_translations[$original] = $translation;
|
||||
}
|
||||
/**
|
||||
* Returns a string from the "originals" table
|
||||
*
|
||||
* @access private
|
||||
* @param int num Offset number of original string
|
||||
* @return string Requested string if found, otherwise ''
|
||||
*/
|
||||
public function get_original_string($num)
|
||||
{
|
||||
$length = $this->table_originals[$num * 2 + 1];
|
||||
$offset = $this->table_originals[$num * 2 + 2];
|
||||
if (! $length) {
|
||||
return '';
|
||||
}
|
||||
$this->STREAM->seekto($offset);
|
||||
$data = $this->STREAM->read($length);
|
||||
return (string)$data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string from the "originals" table
|
||||
*
|
||||
* @access private
|
||||
* @param int num Offset number of original string
|
||||
* @return string Requested string if found, otherwise ''
|
||||
*/
|
||||
function get_original_string($num) {
|
||||
$length = $this->table_originals[$num * 2 + 1];
|
||||
$offset = $this->table_originals[$num * 2 + 2];
|
||||
if (! $length)
|
||||
return '';
|
||||
$this->STREAM->seekto($offset);
|
||||
$data = $this->STREAM->read($length);
|
||||
return (string)$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string from the "translations" table
|
||||
*
|
||||
* @access private
|
||||
* @param int num Offset number of original string
|
||||
* @return string Requested string if found, otherwise ''
|
||||
*/
|
||||
function get_translation_string($num) {
|
||||
$length = $this->table_translations[$num * 2 + 1];
|
||||
$offset = $this->table_translations[$num * 2 + 2];
|
||||
if (! $length)
|
||||
return '';
|
||||
$this->STREAM->seekto($offset);
|
||||
$data = $this->STREAM->read($length);
|
||||
return (string)$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary search for string
|
||||
*
|
||||
* @access private
|
||||
* @param string string
|
||||
* @param int start (internally used in recursive function)
|
||||
* @param int end (internally used in recursive function)
|
||||
* @return int string number (offset in originals table)
|
||||
*/
|
||||
function find_string($string, $start = -1, $end = -1) {
|
||||
if (($start == -1) or ($end == -1)) {
|
||||
// find_string is called with only one parameter, set start end end
|
||||
$start = 0;
|
||||
$end = $this->total;
|
||||
/**
|
||||
* Returns a string from the "translations" table
|
||||
*
|
||||
* @access private
|
||||
* @param int num Offset number of original string
|
||||
* @return string Requested string if found, otherwise ''
|
||||
*/
|
||||
public function get_translation_string($num)
|
||||
{
|
||||
$length = $this->table_translations[$num * 2 + 1];
|
||||
$offset = $this->table_translations[$num * 2 + 2];
|
||||
if (! $length) {
|
||||
return '';
|
||||
}
|
||||
$this->STREAM->seekto($offset);
|
||||
$data = $this->STREAM->read($length);
|
||||
return (string)$data;
|
||||
}
|
||||
if (abs($start - $end) <= 1) {
|
||||
// We're done, now we either found the string, or it doesn't exist
|
||||
$txt = $this->get_original_string($start);
|
||||
if ($string == $txt)
|
||||
return $start;
|
||||
else
|
||||
return -1;
|
||||
} else if ($start > $end) {
|
||||
// start > end -> turn around and start over
|
||||
return $this->find_string($string, $end, $start);
|
||||
} else {
|
||||
// Divide table in two parts
|
||||
$half = (int)(($start + $end) / 2);
|
||||
$cmp = strcmp($string, $this->get_original_string($half));
|
||||
if ($cmp == 0)
|
||||
// string is exactly in the middle => return it
|
||||
return $half;
|
||||
else if ($cmp < 0)
|
||||
// The string is in the upper half
|
||||
return $this->find_string($string, $start, $half);
|
||||
else
|
||||
// The string is in the lower half
|
||||
return $this->find_string($string, $half, $end);
|
||||
|
||||
/**
|
||||
* Binary search for string
|
||||
*
|
||||
* @access private
|
||||
* @param string string
|
||||
* @param int start (internally used in recursive function)
|
||||
* @param int end (internally used in recursive function)
|
||||
* @return int string number (offset in originals table)
|
||||
*/
|
||||
public function find_string($string, $start = -1, $end = -1)
|
||||
{
|
||||
if (($start == -1) or ($end == -1)) {
|
||||
// find_string is called with only one parameter, set start end end
|
||||
$start = 0;
|
||||
$end = $this->total;
|
||||
}
|
||||
if (abs($start - $end) <= 1) {
|
||||
// We're done, now we either found the string, or it doesn't exist
|
||||
$txt = $this->get_original_string($start);
|
||||
if ($string == $txt) {
|
||||
return $start;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} elseif ($start > $end) {
|
||||
// start > end -> turn around and start over
|
||||
return $this->find_string($string, $end, $start);
|
||||
} else {
|
||||
// Divide table in two parts
|
||||
$half = (int)(($start + $end) / 2);
|
||||
$cmp = strcmp($string, $this->get_original_string($half));
|
||||
if ($cmp == 0) {
|
||||
// string is exactly in the middle => return it
|
||||
return $half;
|
||||
} elseif ($cmp < 0) {
|
||||
// The string is in the upper half
|
||||
return $this->find_string($string, $start, $half);
|
||||
} else {
|
||||
// The string is in the lower half
|
||||
return $this->find_string($string, $half, $end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a string
|
||||
*
|
||||
* @access public
|
||||
* @param string string to be translated
|
||||
* @return string translated string (or original, if not found)
|
||||
*/
|
||||
function translate($string) {
|
||||
if ($this->short_circuit)
|
||||
return $string;
|
||||
$this->load_tables();
|
||||
/**
|
||||
* Translates a string
|
||||
*
|
||||
* @access public
|
||||
* @param string string to be translated
|
||||
* @return string translated string (or original, if not found)
|
||||
*/
|
||||
public function translate($string)
|
||||
{
|
||||
if ($this->short_circuit) {
|
||||
return $string;
|
||||
}
|
||||
$this->load_tables();
|
||||
|
||||
if ($this->enable_cache) {
|
||||
// Caching enabled, get translated string from cache
|
||||
if (array_key_exists($string, $this->cache_translations))
|
||||
return $this->cache_translations[$string];
|
||||
else
|
||||
return $string;
|
||||
} else {
|
||||
// Caching not enabled, try to find string
|
||||
$num = $this->find_string($string);
|
||||
if ($num == -1)
|
||||
return $string;
|
||||
else
|
||||
return $this->get_translation_string($num);
|
||||
if ($this->enable_cache) {
|
||||
// Caching enabled, get translated string from cache
|
||||
if (array_key_exists($string, $this->cache_translations)) {
|
||||
return $this->cache_translations[$string];
|
||||
} else {
|
||||
return $string;
|
||||
}
|
||||
} else {
|
||||
// Caching not enabled, try to find string
|
||||
$num = $this->find_string($string);
|
||||
if ($num == -1) {
|
||||
return $string;
|
||||
} else {
|
||||
return $this->get_translation_string($num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize plural form expression for use in PHP eval call.
|
||||
*
|
||||
* @access private
|
||||
* @return string sanitized plural form expression
|
||||
*/
|
||||
function sanitize_plural_expression($expr) {
|
||||
// Get rid of disallowed characters.
|
||||
$expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
|
||||
/**
|
||||
* Sanitize plural form expression for use in PHP eval call.
|
||||
*
|
||||
* @access private
|
||||
* @return string sanitized plural form expression
|
||||
*/
|
||||
public function sanitize_plural_expression($expr)
|
||||
{
|
||||
// Get rid of disallowed characters.
|
||||
$expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
|
||||
|
||||
// Add parenthesis for tertiary '?' operator.
|
||||
$expr .= ';';
|
||||
$res = '';
|
||||
$p = 0;
|
||||
for ($i = 0; $i < strlen($expr); $i++) {
|
||||
$ch = $expr[$i];
|
||||
switch ($ch) {
|
||||
// Add parenthesis for tertiary '?' operator.
|
||||
$expr .= ';';
|
||||
$res = '';
|
||||
$p = 0;
|
||||
for ($i = 0; $i < strlen($expr); $i++) {
|
||||
$ch = $expr[$i];
|
||||
switch ($ch) {
|
||||
case '?':
|
||||
$res .= ' ? (';
|
||||
$p++;
|
||||
@@ -294,143 +313,151 @@ class gettext_reader {
|
||||
$res .= ') : (';
|
||||
break;
|
||||
case ';':
|
||||
$res .= str_repeat( ')', $p) . ';';
|
||||
$res .= str_repeat(')', $p) . ';';
|
||||
$p = 0;
|
||||
break;
|
||||
default:
|
||||
$res .= $ch;
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse full PO header and extract only plural forms line.
|
||||
*
|
||||
* @access private
|
||||
* @return string verbatim plural form header field
|
||||
*/
|
||||
function extract_plural_forms_header_from_po_header($header) {
|
||||
if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs))
|
||||
$expr = $regs[2];
|
||||
else
|
||||
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
|
||||
return $expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get possible plural forms from MO header
|
||||
*
|
||||
* @access private
|
||||
* @return string plural form header
|
||||
*/
|
||||
function get_plural_forms() {
|
||||
// lets assume message number 0 is header
|
||||
// this is true, right?
|
||||
$this->load_tables();
|
||||
|
||||
// cache header field for plural forms
|
||||
if (! is_string($this->pluralheader)) {
|
||||
if ($this->enable_cache) {
|
||||
$header = $this->cache_translations[""];
|
||||
} else {
|
||||
$header = $this->get_translation_string(0);
|
||||
}
|
||||
$expr = $this->extract_plural_forms_header_from_po_header($header);
|
||||
$this->pluralheader = $this->sanitize_plural_expression($expr);
|
||||
/**
|
||||
* Parse full PO header and extract only plural forms line.
|
||||
*
|
||||
* @access private
|
||||
* @return string verbatim plural form header field
|
||||
*/
|
||||
public function extract_plural_forms_header_from_po_header($header)
|
||||
{
|
||||
if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) {
|
||||
$expr = $regs[2];
|
||||
} else {
|
||||
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
|
||||
}
|
||||
return $expr;
|
||||
}
|
||||
return $this->pluralheader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects which plural form to take
|
||||
*
|
||||
* @access private
|
||||
* @param n count
|
||||
* @return int array index of the right plural form
|
||||
*/
|
||||
function select_string($n) {
|
||||
if (!is_int($n)) {
|
||||
throw new InvalidArgumentException(
|
||||
"Select_string only accepts integers: " . $n);
|
||||
/**
|
||||
* Get possible plural forms from MO header
|
||||
*
|
||||
* @access private
|
||||
* @return string plural form header
|
||||
*/
|
||||
public function get_plural_forms()
|
||||
{
|
||||
// lets assume message number 0 is header
|
||||
// this is true, right?
|
||||
$this->load_tables();
|
||||
|
||||
// cache header field for plural forms
|
||||
if (! is_string($this->pluralheader)) {
|
||||
if ($this->enable_cache) {
|
||||
$header = $this->cache_translations[""];
|
||||
} else {
|
||||
$header = $this->get_translation_string(0);
|
||||
}
|
||||
$expr = $this->extract_plural_forms_header_from_po_header($header);
|
||||
$this->pluralheader = $this->sanitize_plural_expression($expr);
|
||||
}
|
||||
return $this->pluralheader;
|
||||
}
|
||||
$string = $this->get_plural_forms();
|
||||
$string = str_replace('nplurals',"\$total",$string);
|
||||
$string = str_replace("n",$n,$string);
|
||||
$string = str_replace('plural',"\$plural",$string);
|
||||
|
||||
$total = 0;
|
||||
$plural = 0;
|
||||
/**
|
||||
* Detects which plural form to take
|
||||
*
|
||||
* @access private
|
||||
* @param n count
|
||||
* @return int array index of the right plural form
|
||||
*/
|
||||
public function select_string($n)
|
||||
{
|
||||
if (!is_int($n)) {
|
||||
throw new InvalidArgumentException(
|
||||
"Select_string only accepts integers: " . $n
|
||||
);
|
||||
}
|
||||
$string = $this->get_plural_forms();
|
||||
$string = str_replace('nplurals', "\$total", $string);
|
||||
$string = str_replace("n", $n, $string);
|
||||
$string = str_replace('plural', "\$plural", $string);
|
||||
|
||||
eval("$string");
|
||||
if ($plural >= $total) $plural = $total - 1;
|
||||
return $plural;
|
||||
}
|
||||
$total = 0;
|
||||
$plural = 0;
|
||||
|
||||
/**
|
||||
* Plural version of gettext
|
||||
*
|
||||
* @access public
|
||||
* @param string single
|
||||
* @param string plural
|
||||
* @param string number
|
||||
* @return translated plural form
|
||||
*/
|
||||
function ngettext($single, $plural, $number) {
|
||||
if ($this->short_circuit) {
|
||||
if ($number != 1)
|
||||
eval("$string");
|
||||
if ($plural >= $total) {
|
||||
$plural = $total - 1;
|
||||
}
|
||||
return $plural;
|
||||
else
|
||||
return $single;
|
||||
}
|
||||
|
||||
// find out the appropriate form
|
||||
$select = $this->select_string($number);
|
||||
/**
|
||||
* Plural version of gettext
|
||||
*
|
||||
* @access public
|
||||
* @param string single
|
||||
* @param string plural
|
||||
* @param string number
|
||||
* @return translated plural form
|
||||
*/
|
||||
public function ngettext($single, $plural, $number)
|
||||
{
|
||||
if ($this->short_circuit) {
|
||||
if ($number != 1) {
|
||||
return $plural;
|
||||
} else {
|
||||
return $single;
|
||||
}
|
||||
}
|
||||
|
||||
// this should contains all strings separated by NULLs
|
||||
$key = $single . chr(0) . $plural;
|
||||
// find out the appropriate form
|
||||
$select = $this->select_string($number);
|
||||
|
||||
// this should contains all strings separated by NULLs
|
||||
$key = $single . chr(0) . $plural;
|
||||
|
||||
|
||||
if ($this->enable_cache) {
|
||||
if (! array_key_exists($key, $this->cache_translations)) {
|
||||
return ($number != 1) ? $plural : $single;
|
||||
} else {
|
||||
$result = $this->cache_translations[$key];
|
||||
$list = explode(chr(0), $result);
|
||||
return $list[$select];
|
||||
}
|
||||
} else {
|
||||
$num = $this->find_string($key);
|
||||
if ($num == -1) {
|
||||
return ($number != 1) ? $plural : $single;
|
||||
} else {
|
||||
$result = $this->get_translation_string($num);
|
||||
$list = explode(chr(0), $result);
|
||||
return $list[$select];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pgettext($context, $msgid) {
|
||||
$key = $context . chr(4) . $msgid;
|
||||
$ret = $this->translate($key);
|
||||
if (strpos($ret, "\004") !== FALSE) {
|
||||
return $msgid;
|
||||
} else {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
function npgettext($context, $singular, $plural, $number) {
|
||||
$key = $context . chr(4) . $singular;
|
||||
$ret = $this->ngettext($key, $plural, $number);
|
||||
if (strpos($ret, "\004") !== FALSE) {
|
||||
return $singular;
|
||||
} else {
|
||||
return $ret;
|
||||
if ($this->enable_cache) {
|
||||
if (! array_key_exists($key, $this->cache_translations)) {
|
||||
return ($number != 1) ? $plural : $single;
|
||||
} else {
|
||||
$result = $this->cache_translations[$key];
|
||||
$list = explode(chr(0), $result);
|
||||
return $list[$select];
|
||||
}
|
||||
} else {
|
||||
$num = $this->find_string($key);
|
||||
if ($num == -1) {
|
||||
return ($number != 1) ? $plural : $single;
|
||||
} else {
|
||||
$result = $this->get_translation_string($num);
|
||||
$list = explode(chr(0), $result);
|
||||
return $list[$select];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public function pgettext($context, $msgid)
|
||||
{
|
||||
$key = $context . chr(4) . $msgid;
|
||||
$ret = $this->translate($key);
|
||||
if (strpos($ret, "\004") !== false) {
|
||||
return $msgid;
|
||||
} else {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
public function npgettext($context, $singular, $plural, $number)
|
||||
{
|
||||
$key = $context . chr(4) . $singular;
|
||||
$ret = $this->ngettext($key, $plural, $number);
|
||||
if (strpos($ret, "\004") !== false) {
|
||||
return $singular;
|
||||
} else {
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
+141
-125
@@ -23,145 +23,161 @@
|
||||
|
||||
// Simple class to wrap file streams, string streams, etc.
|
||||
// seek is essential, and it should be byte stream
|
||||
class StreamReader {
|
||||
// should return a string [FIXME: perhaps return array of bytes?]
|
||||
function read($bytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// should return new position
|
||||
function seekto($position) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns current position
|
||||
function currentpos() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns length of entire stream (limit for seekto()s)
|
||||
function length() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class StringReader {
|
||||
var $_pos;
|
||||
var $_str;
|
||||
|
||||
function StringReader($str='') {
|
||||
$this->_str = $str;
|
||||
$this->_pos = 0;
|
||||
}
|
||||
|
||||
function read($bytes) {
|
||||
$data = substr($this->_str, $this->_pos, $bytes);
|
||||
$this->_pos += $bytes;
|
||||
if (strlen($this->_str)<$this->_pos)
|
||||
$this->_pos = strlen($this->_str);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function seekto($pos) {
|
||||
$this->_pos = $pos;
|
||||
if (strlen($this->_str)<$this->_pos)
|
||||
$this->_pos = strlen($this->_str);
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
function currentpos() {
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
function length() {
|
||||
return strlen($this->_str);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class FileReader {
|
||||
var $_pos;
|
||||
var $_fd;
|
||||
var $_length;
|
||||
|
||||
function FileReader($filename) {
|
||||
if (file_exists($filename)) {
|
||||
|
||||
$this->_length=filesize($filename);
|
||||
$this->_pos = 0;
|
||||
$this->_fd = fopen($filename,'rb');
|
||||
if (!$this->_fd) {
|
||||
$this->error = 3; // Cannot read file, probably permissions
|
||||
class StreamReader
|
||||
{
|
||||
// should return a string [FIXME: perhaps return array of bytes?]
|
||||
public function read($bytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->error = 2; // File doesn't exist
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function read($bytes) {
|
||||
if ($bytes) {
|
||||
fseek($this->_fd, $this->_pos);
|
||||
// should return new position
|
||||
public function seekto($position)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// PHP 5.1.1 does not read more than 8192 bytes in one fread()
|
||||
// the discussions at PHP Bugs suggest it's the intended behaviour
|
||||
$data = '';
|
||||
while ($bytes > 0) {
|
||||
$chunk = fread($this->_fd, $bytes);
|
||||
$data .= $chunk;
|
||||
$bytes -= strlen($chunk);
|
||||
}
|
||||
$this->_pos = ftell($this->_fd);
|
||||
// returns current position
|
||||
public function currentpos()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $data;
|
||||
} else return '';
|
||||
}
|
||||
// returns length of entire stream (limit for seekto()s)
|
||||
public function length()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function seekto($pos) {
|
||||
fseek($this->_fd, $pos);
|
||||
$this->_pos = ftell($this->_fd);
|
||||
return $this->_pos;
|
||||
}
|
||||
class StringReader
|
||||
{
|
||||
public $_pos;
|
||||
public $_str;
|
||||
|
||||
function currentpos() {
|
||||
return $this->_pos;
|
||||
}
|
||||
public function StringReader($str='')
|
||||
{
|
||||
$this->_str = $str;
|
||||
$this->_pos = 0;
|
||||
}
|
||||
|
||||
function length() {
|
||||
return $this->_length;
|
||||
}
|
||||
public function read($bytes)
|
||||
{
|
||||
$data = substr($this->_str, $this->_pos, $bytes);
|
||||
$this->_pos += $bytes;
|
||||
if (strlen($this->_str)<$this->_pos) {
|
||||
$this->_pos = strlen($this->_str);
|
||||
}
|
||||
|
||||
function close() {
|
||||
fclose($this->_fd);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function seekto($pos)
|
||||
{
|
||||
$this->_pos = $pos;
|
||||
if (strlen($this->_str)<$this->_pos) {
|
||||
$this->_pos = strlen($this->_str);
|
||||
}
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
public function currentpos()
|
||||
{
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
public function length()
|
||||
{
|
||||
return strlen($this->_str);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FileReader
|
||||
{
|
||||
public $_pos;
|
||||
public $_fd;
|
||||
public $_length;
|
||||
|
||||
public function FileReader($filename)
|
||||
{
|
||||
if (file_exists($filename)) {
|
||||
$this->_length=filesize($filename);
|
||||
$this->_pos = 0;
|
||||
$this->_fd = fopen($filename, 'rb');
|
||||
if (!$this->_fd) {
|
||||
$this->error = 3; // Cannot read file, probably permissions
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->error = 2; // File doesn't exist
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function read($bytes)
|
||||
{
|
||||
if ($bytes) {
|
||||
fseek($this->_fd, $this->_pos);
|
||||
|
||||
// PHP 5.1.1 does not read more than 8192 bytes in one fread()
|
||||
// the discussions at PHP Bugs suggest it's the intended behaviour
|
||||
$data = '';
|
||||
while ($bytes > 0) {
|
||||
$chunk = fread($this->_fd, $bytes);
|
||||
$data .= $chunk;
|
||||
$bytes -= strlen($chunk);
|
||||
}
|
||||
$this->_pos = ftell($this->_fd);
|
||||
|
||||
return $data;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function seekto($pos)
|
||||
{
|
||||
fseek($this->_fd, $pos);
|
||||
$this->_pos = ftell($this->_fd);
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
public function currentpos()
|
||||
{
|
||||
return $this->_pos;
|
||||
}
|
||||
|
||||
public function length()
|
||||
{
|
||||
return $this->_length;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
fclose($this->_fd);
|
||||
}
|
||||
};
|
||||
|
||||
// Preloads entire file in memory first, then creates a StringReader
|
||||
// over it (it assumes knowledge of StringReader internals)
|
||||
class CachedFileReader extends StringReader {
|
||||
function CachedFileReader($filename) {
|
||||
if (file_exists($filename)) {
|
||||
class CachedFileReader extends StringReader
|
||||
{
|
||||
public function CachedFileReader($filename)
|
||||
{
|
||||
if (file_exists($filename)) {
|
||||
$length=filesize($filename);
|
||||
$fd = fopen($filename, 'rb');
|
||||
|
||||
$length=filesize($filename);
|
||||
$fd = fopen($filename,'rb');
|
||||
|
||||
if (!$fd) {
|
||||
$this->error = 3; // Cannot read file, probably permissions
|
||||
return false;
|
||||
}
|
||||
$this->_str = fread($fd, $length);
|
||||
fclose($fd);
|
||||
|
||||
} else {
|
||||
$this->error = 2; // File doesn't exist
|
||||
return false;
|
||||
if (!$fd) {
|
||||
$this->error = 3; // Cannot read file, probably permissions
|
||||
return false;
|
||||
}
|
||||
$this->_str = fread($fd, $length);
|
||||
fclose($fd);
|
||||
} else {
|
||||
$this->error = 2; // File doesn't exist
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
require_once('gettext.inc');
|
||||
|
||||
class LocaleTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function test_setlocale()
|
||||
{
|
||||
putenv("LC_ALL=");
|
||||
// _setlocale defaults to a locale name from environment variable LANG.
|
||||
putenv("LANG=sr_RS");
|
||||
$this->assertEquals('sr_RS', _setlocale(LC_MESSAGES, 0));
|
||||
}
|
||||
|
||||
public function test_setlocale_system()
|
||||
{
|
||||
putenv("LC_ALL=");
|
||||
// For an existing locale, it never needs emulation.
|
||||
putenv("LANG=C");
|
||||
_setlocale(LC_MESSAGES, "");
|
||||
$this->assertEquals(0, locale_emulation());
|
||||
}
|
||||
|
||||
public function test_setlocale_emulation()
|
||||
{
|
||||
putenv("LC_ALL=");
|
||||
// If we set it to a non-existent locale, it still works, but uses
|
||||
// emulation.
|
||||
_setlocale(LC_MESSAGES, "xxx_XXX");
|
||||
$this->assertEquals('xxx_XXX', _setlocale(LC_MESSAGES, 0));
|
||||
$this->assertEquals(1, locale_emulation());
|
||||
}
|
||||
|
||||
public function test_get_list_of_locales()
|
||||
{
|
||||
// For a locale containing country code, we prefer
|
||||
// full locale name, but if that's not found, fall back
|
||||
// to the language only locale name.
|
||||
$this->assertEquals(
|
||||
array("sr_RS", "sr"),
|
||||
get_list_of_locales("sr_RS")
|
||||
);
|
||||
|
||||
// If language code is used, it's the only thing returned.
|
||||
$this->assertEquals(
|
||||
array("sr"),
|
||||
get_list_of_locales("sr")
|
||||
);
|
||||
|
||||
// There is support for language and charset only.
|
||||
$this->assertEquals(
|
||||
array("sr.UTF-8", "sr"),
|
||||
get_list_of_locales("sr.UTF-8")
|
||||
);
|
||||
|
||||
// It can also split out character set from the full locale name.
|
||||
$this->assertEquals(
|
||||
array("sr_RS.UTF-8", "sr_RS", "sr"),
|
||||
get_list_of_locales("sr_RS.UTF-8")
|
||||
);
|
||||
|
||||
// There is support for @modifier in locale names as well.
|
||||
$this->assertEquals(
|
||||
array("sr_RS.UTF-8@latin", "sr_RS@latin", "sr@latin",
|
||||
"sr_RS.UTF-8", "sr_RS", "sr"),
|
||||
get_list_of_locales("sr_RS.UTF-8@latin")
|
||||
);
|
||||
|
||||
// We can pass in only language and modifier.
|
||||
$this->assertEquals(
|
||||
array("sr@latin", "sr"),
|
||||
get_list_of_locales("sr@latin")
|
||||
);
|
||||
|
||||
|
||||
// If locale name is not following the regular POSIX pattern,
|
||||
// it's used verbatim.
|
||||
$this->assertEquals(
|
||||
array("something"),
|
||||
get_list_of_locales("something")
|
||||
);
|
||||
|
||||
// Passing in an empty string returns an empty array.
|
||||
$this->assertEquals(
|
||||
array(),
|
||||
get_list_of_locales("")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
class ParsingTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function test_extract_plural_forms_header_from_po_header()
|
||||
{
|
||||
$parser = new gettext_reader(null);
|
||||
// It defaults to a "Western-style" plural header.
|
||||
$this->assertEquals(
|
||||
'nplurals=2; plural=n == 1 ? 0 : 1;',
|
||||
$parser->extract_plural_forms_header_from_po_header("")
|
||||
);
|
||||
|
||||
// Extracting it from the middle of the header works.
|
||||
$this->assertEquals(
|
||||
'nplurals=1; plural=0;',
|
||||
$parser->extract_plural_forms_header_from_po_header(
|
||||
"Content-type: text/html; charset=UTF-8\n"
|
||||
."Plural-Forms: nplurals=1; plural=0;\n"
|
||||
."Last-Translator: nobody\n"
|
||||
)
|
||||
);
|
||||
|
||||
// It's also case-insensitive.
|
||||
$this->assertEquals(
|
||||
'nplurals=1; plural=0;',
|
||||
$parser->extract_plural_forms_header_from_po_header(
|
||||
"PLURAL-forms: nplurals=1; plural=0;\n"
|
||||
)
|
||||
);
|
||||
|
||||
// It falls back to default if it's not on a separate line.
|
||||
$this->assertEquals(
|
||||
'nplurals=2; plural=n == 1 ? 0 : 1;',
|
||||
$parser->extract_plural_forms_header_from_po_header(
|
||||
"Content-type: text/html; charset=UTF-8" // note the missing \n here
|
||||
."Plural-Forms: nplurals=1; plural=0;\n"
|
||||
."Last-Translator: nobody\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function test_select_string_disallows_nonint_numbers()
|
||||
{
|
||||
$pofile_data = ''
|
||||
."msgid \"\"\n"
|
||||
."msgstr \"\"\n"
|
||||
."\"Content-Type: text/plain; charset=utf-8\\n\"\n"
|
||||
."\"Plural-Forms: nplurals=2; plural= n == 1 ? 0 : 1;\\n\"\n";
|
||||
$mofile = tempnam(sys_get_temp_dir(), "pg");
|
||||
$msgfmt = popen("msgfmt -o $mofile -", "w");
|
||||
fwrite($msgfmt, $pofile_data);
|
||||
pclose($msgfmt);
|
||||
|
||||
$modata = new CachedFileReader($mofile);
|
||||
unlink($mofile);
|
||||
$parser = new gettext_reader($modata);
|
||||
// It defaults to a "Western-style" plural header.
|
||||
$this->assertEquals(
|
||||
'nplurals=2; plural=n == 1 ? 0 : 1;',
|
||||
$parser->extract_plural_forms_header_from_po_header("")
|
||||
);
|
||||
|
||||
$new_tempfile = tempnam(sys_get_temp_dir(), "pg");
|
||||
$parser->select_string(
|
||||
"(file_put_contents('$new_tempfile', 'boom'))"
|
||||
);
|
||||
|
||||
$this->assertEquals("", file_get_contents($new_tempfile));
|
||||
unlink($new_tempfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_provider_test_npgettext
|
||||
*/
|
||||
public function test_npgettext($number, $expected)
|
||||
{
|
||||
$parser = new gettext_reader(null);
|
||||
$result = $parser->npgettext(
|
||||
"context",
|
||||
"%d pig went to the market\n",
|
||||
"%d pigs went to the market\n",
|
||||
$number
|
||||
);
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
public static function data_provider_test_npgettext()
|
||||
{
|
||||
return array(
|
||||
array(1, "%d pig went to the market\n"),
|
||||
array(2, "%d pigs went to the market\n"),
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -249,7 +249,7 @@ class Action extends HTMLOutputter // lawsuit
|
||||
if ($this->needLogin) {
|
||||
$this->checkLogin(); // if not logged in, this redirs/excepts
|
||||
}
|
||||
|
||||
|
||||
if ($this->redirectAfterLogin) {
|
||||
common_set_returnto($this->selfUrl());
|
||||
}
|
||||
|
||||
@@ -56,6 +56,6 @@ class Attachment extends AttachmentListItem
|
||||
}
|
||||
|
||||
function linkAttr() {
|
||||
return array('rel' => 'external', 'href' => $this->attachment->getUrl());
|
||||
return array('rel' => 'external', 'href' => $this->attachment->getAttachmentDownloadUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class AttachmentList extends Widget
|
||||
$attachments = $this->notice->attachments();
|
||||
foreach ($attachments as $key=>$att) {
|
||||
// Remove attachments which are not representable with neither a title nor thumbnail
|
||||
if ($att->getTitle() === null && !$att->hasThumbnail()) {
|
||||
if ($att->getTitle() === _('Untitled attachment') && !$att->hasThumbnail()) {
|
||||
unset($attachments[$key]);
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,8 @@ class AttachmentList extends Widget
|
||||
|
||||
if ($this->notice->getProfile()->isSilenced()) {
|
||||
// TRANS: Message for inline attachments list in notices when the author has been silenced.
|
||||
$this->element('div', ['class'=>'error'], _('Attachments are hidden because this profile has been silenced.'));
|
||||
$this->element('div', ['class'=>'error'],
|
||||
_('Attachments are hidden because this profile has been silenced.'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class AttachmentListItem extends Widget
|
||||
}
|
||||
|
||||
function title() {
|
||||
return $this->attachment->getTitle() ?: _('Untitled attachment');
|
||||
return $this->attachment->getTitle() ?: MediaFile::getDisplayName($this->attachment);
|
||||
}
|
||||
|
||||
function linkTitle() {
|
||||
@@ -146,7 +146,9 @@ class AttachmentListItem extends Widget
|
||||
} else {
|
||||
try {
|
||||
// getUrl(true) because we don't want to hotlink, could be made configurable
|
||||
$this->out->element('img', ['class'=>'u-photo', 'src'=>$this->attachment->getUrl(true), 'alt' => $this->attachment->getTitle()]);
|
||||
$this->out->element('img', ['class'=>'u-photo',
|
||||
'src'=>$this->attachment->getUrl(true),
|
||||
'alt' => $this->attachment->getTitle()]);
|
||||
} catch (FileNotStoredLocallyException $e) {
|
||||
$url = $e->file->getUrl(false);
|
||||
$this->out->element('a', ['href'=>$url, 'rel'=>'external'], $url);
|
||||
@@ -166,12 +168,12 @@ class AttachmentListItem extends Widget
|
||||
}
|
||||
|
||||
$this->out->elementStart($mediatype,
|
||||
array('class'=>"attachment_player u-{$mediatype}",
|
||||
'poster'=>$poster,
|
||||
'controls'=>'controls'));
|
||||
array('class'=>"attachment_player u-{$mediatype}",
|
||||
'poster'=>$poster,
|
||||
'controls'=>'controls'));
|
||||
$this->out->element('source',
|
||||
array('src'=>$this->attachment->getUrl(),
|
||||
'type'=>$this->attachment->mimetype));
|
||||
'type'=>$this->attachment->mimetype));
|
||||
$this->out->elementEnd($mediatype);
|
||||
break;
|
||||
|
||||
@@ -179,7 +181,8 @@ class AttachmentListItem extends Widget
|
||||
unset($thumb); // there's no need carrying this along
|
||||
switch (common_bare_mime($this->attachment->mimetype)) {
|
||||
case 'text/plain':
|
||||
$this->element('div', ['class'=>'e-content plaintext'], file_get_contents($this->attachment->getPath()));
|
||||
$this->element('div', ['class'=>'e-content plaintext'],
|
||||
file_get_contents($this->attachment->getPath()));
|
||||
break;
|
||||
case 'text/html':
|
||||
if (!empty($this->attachment->filename)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* @param ... any remaining arguments will be appended to call-time params
|
||||
* @return callback
|
||||
*/
|
||||
function curry($fn) {
|
||||
function callableLeftCurry($fn) {
|
||||
$extra_args = func_get_args();
|
||||
array_shift($extra_args);
|
||||
return function() use ($fn, $extra_args) {
|
||||
+22
-19
@@ -1,25 +1,28 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008-2010, StatusNet, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
defined('GNUSOCIAL') || die();
|
||||
|
||||
// All the fun stuff to actually initialize StatusNet's framework code,
|
||||
/* Work internally in UTC */
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
/* Work internally with UTF-8 */
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
// All the fun stuff to actually initialize GNU social's framework code,
|
||||
// without loading up a site configuration.
|
||||
require_once INSTALLDIR . '/lib/framework.php';
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* DB error action.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/servererroraction.php';
|
||||
|
||||
/**
|
||||
* Class for displaying DB Errors
|
||||
*
|
||||
* This only occurs if there's been a DB_DataObject_Error that's
|
||||
* reported through PEAR, so we try to avoid doing anything that connects
|
||||
* to the DB, so we don't trigger it again.
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class DBErrorAction extends ServerErrorAction
|
||||
{
|
||||
function __construct($message='Error', $code=500)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title for when a database error occurs.
|
||||
return _('Database error');
|
||||
}
|
||||
|
||||
function getLanguage()
|
||||
{
|
||||
// Don't try to figure out user's language; just show the page
|
||||
return common_config('site', 'language');
|
||||
}
|
||||
|
||||
function showPrimaryNav()
|
||||
{
|
||||
// don't show primary nav
|
||||
}
|
||||
}
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário