added google xoauth2 support + fixed a journaling issue

This commit is contained in:
SJ 2012-09-28 10:34:04 +02:00
parent f930aacc84
commit 55de53bb26
111 changed files with 38812 additions and 4 deletions

View File

@ -13,7 +13,7 @@
#define VERSION "0.1.21"
#define BUILD 706
#define BUILD 708
#define HOSTID "mailarchiver"

View File

@ -162,7 +162,7 @@ struct _state {
int bodylen;
int tolen;
char ms_journal;
char ms_journal, ms_journal_dropped;
};

View File

@ -84,6 +84,8 @@ struct _state parse_message(struct session_data *sdata, int take_into_pieces, st
}
if(take_into_pieces == 1 && state.writebufpos > 0){
if(state.ms_journal == 1) remove_trailing_journal_boundary(&writebuffer[0], &state);
len = write(state.mfd, writebuffer, state.writebufpos);
memset(writebuffer, 0, sizeof(writebuffer));
state.writebufpos = 0;
@ -212,6 +214,7 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, int
state->saved_size += len;
//n = write(state->mfd, buf, len); // WRITE
if(len + state->writebufpos > writebuffersize-1){
if(state->ms_journal == 1) remove_trailing_journal_boundary(writebuffer, state);
n = write(state->mfd, writebuffer, state->writebufpos); state->writebufpos = 0; memset(writebuffer, 0, writebuffersize);
}
memcpy(writebuffer+state->writebufpos, buf, len); state->writebufpos += len;
@ -327,6 +330,7 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, int
else if(strncasecmp(buf, "Subject:", strlen("Subject:")) == 0) state->message_state = MSG_SUBJECT;
else if(strncasecmp(buf, "Recipient:", strlen("Recipient:")) == 0) state->message_state = MSG_RECIPIENT;
else if(strncasecmp(buf, "Date:", strlen("Date:")) == 0 && sdata->sent == 0) sdata->sent = parse_date_header(buf);
else if(strncasecmp(buf, "Received:", strlen("Received:")) == 0) state->message_state = MSG_RECEIVED;
if(state->message_state == MSG_MESSAGE_ID && state->message_id[0] == 0){
p = strchr(buf+11, ' ');
@ -357,6 +361,14 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, int
if(p) *p = '\0';
}
if(state->message_state == MSG_RECEIVED && state->ms_journal == 1 && state->ms_journal_dropped == 0){
state->ms_journal_dropped = 1;
state->writebufpos = 0; memset(writebuffer, 0, writebuffersize);
memcpy(writebuffer+state->writebufpos, buf, len); state->writebufpos += strlen(buf);
memcpy(writebuffer+state->writebufpos, "\n", 1); state->writebufpos++;
}
if(state->is_1st_header == 1 && state->message_state == MSG_REFERENCES){
if(strncasecmp(buf, "References:", 11) == 0) parse_reference(state, buf+11);
else parse_reference(state, buf);

View File

@ -34,5 +34,6 @@ char *determine_attachment_type(char *filename, char *type);
char *get_attachment_extractor_by_filename(char *filename);
void parse_reference(struct _state *state, char *s);
int base64_decode_attachment_buffer(char *p, int plen, unsigned char *b, int blen);
void remove_trailing_journal_boundary(char *writebuffer, struct _state *state);
#endif /* _PARSER_H */

View File

@ -96,6 +96,7 @@ void init_state(struct _state *state){
state->bodylen = 0;
state->ms_journal = 0;
state->ms_journal_dropped = 0;
}
@ -811,3 +812,21 @@ int base64_decode_attachment_buffer(char *p, int plen, unsigned char *b, int ble
return b64len;
}
void remove_trailing_journal_boundary(char *writebuffer, struct _state *state){
char *p;
p = strstr(writebuffer, state->boundaries->s);
if(p){
state->writebufpos -= strlen(p);
*p = '\0';
p = strrchr(writebuffer, '\n');
if(p){
state->writebufpos -= strlen(p);
*p = '\0';
}
}
}

View File

@ -319,3 +319,23 @@ create index `audit_idx2` on `audit`(`action`);
create index `audit_idx3` on `audit`(`ipaddr`);
create index `audit_idx4` on `audit`(`ts`);
drop table if exists `google`;
create table if not exists `google` (
`id` bigint unsigned not null primary key,
`email` char(128) not null unique,
`access_token` char(255) default null,
`refresh_token` char(255) default null,
`created` int default 0
) ENGINE=InnoDB;
drop table if exists `google_imap`;
create table if not exists `google_imap` (
`id` bigint unsigned not null,
`email` char(128) not null,
`last_msg_id` bigint default 0,
key(`email`)
) ENGINE=InnoDB;

View File

@ -12,4 +12,5 @@ RewriteRule ^folders.php /index.php?route=folder/list& [QSA,L]
RewriteRule ^settings.php /index.php?route=user/settings [L]
RewriteRule ^login.php /index.php?route=login/login [L]
RewriteRule ^logout.php /index.php?route=login/logout [L]
RewriteRule ^google.php /index.php?route=login/google [QSA,L]

96
webui/Zend/Exception.php Normal file
View File

@ -0,0 +1,96 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Exception extends Exception
{
/**
* @var null|Exception
*/
private $_previous = null;
/**
* Construct the exception
*
* @param string $msg
* @param int $code
* @param Exception $previous
* @return void
*/
public function __construct($msg = '', $code = 0, Exception $previous = null)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
parent::__construct($msg, (int) $code);
$this->_previous = $previous;
} else {
parent::__construct($msg, (int) $code, $previous);
}
}
/**
* Overloading
*
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
* @param string $method
* @param array $args
* @return mixed
*/
public function __call($method, array $args)
{
if ('getprevious' == strtolower($method)) {
return $this->_getPrevious();
}
return null;
}
/**
* String representation of the exception
*
* @return string
*/
public function __toString()
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
if (null !== ($e = $this->getPrevious())) {
return $e->__toString()
. "\n\nNext "
. parent::__toString();
}
}
return parent::__toString();
}
/**
* Returns previous Exception
*
* @return Exception|null
*/
protected function _getPrevious()
{
return $this->_previous;
}
}

1276
webui/Zend/Mail.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Exception extends Zend_Exception
{}

112
webui/Zend/Mail/Message.php Normal file
View File

@ -0,0 +1,112 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Message.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mail_Part
*/
require_once 'Zend/Mail/Part.php';
/**
* Zend_Mail_Message_Interface
*/
require_once 'Zend/Mail/Message/Interface.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Message extends Zend_Mail_Part implements Zend_Mail_Message_Interface
{
/**
* flags for this message
* @var array
*/
protected $_flags = array();
/**
* Public constructor
*
* In addition to the parameters of Zend_Mail_Part::__construct() this constructor supports:
* - file filename or file handle of a file with raw message content
* - flags array with flags for message, keys are ignored, use constants defined in Zend_Mail_Storage
*
* @param string $rawMessage full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (isset($params['file'])) {
if (!is_resource($params['file'])) {
$params['raw'] = @file_get_contents($params['file']);
if ($params['raw'] === false) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('could not open file');
}
} else {
$params['raw'] = stream_get_contents($params['file']);
}
}
if (!empty($params['flags'])) {
// set key and value to the same value for easy lookup
$this->_flags = array_merge($this->_flags, array_combine($params['flags'],$params['flags']));
}
parent::__construct($params);
}
/**
* return toplines as found after headers
*
* @return string toplines
*/
public function getTopLines()
{
return $this->_topLines;
}
/**
* check if flag is set
*
* @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
* @return bool true if set, otherwise false
*/
public function hasFlag($flag)
{
return isset($this->_flags[$flag]);
}
/**
* get all set flags
*
* @return array array with flags, key and value are the same for easy lookup
*/
public function getFlags()
{
return $this->_flags;
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mail_Part
*/
require_once 'Zend/Mail/Part/File.php';
/**
* Zend_Mail_Message_Interface
*/
require_once 'Zend/Mail/Message/Interface.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Message_File extends Zend_Mail_Part_File implements Zend_Mail_Message_Interface
{
/**
* flags for this message
* @var array
*/
protected $_flags = array();
/**
* Public constructor
*
* In addition to the parameters of Zend_Mail_Part::__construct() this constructor supports:
* - flags array with flags for message, keys are ignored, use constants defined in Zend_Mail_Storage
*
* @param string $rawMessage full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (!empty($params['flags'])) {
// set key and value to the same value for easy lookup
$this->_flags = array_combine($params['flags'], $params['flags']);
}
parent::__construct($params);
}
/**
* return toplines as found after headers
*
* @return string toplines
*/
public function getTopLines()
{
return $this->_topLines;
}
/**
* check if flag is set
*
* @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
* @return bool true if set, otherwise false
*/
public function hasFlag($flag)
{
return isset($this->_flags[$flag]);
}
/**
* get all set flags
*
* @return array array with flags, key and value are the same for easy lookup
*/
public function getFlags()
{
return $this->_flags;
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Message_Interface
{
/**
* return toplines as found after headers
*
* @return string toplines
*/
public function getTopLines();
/**
* check if flag is set
*
* @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
* @return bool true if set, otherwise false
*/
public function hasFlag($flag);
/**
* get all set flags
*
* @return array array with flags, key and value are the same for easy lookup
*/
public function getFlags();
}

569
webui/Zend/Mail/Part.php Normal file
View File

@ -0,0 +1,569 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Part.php 24759 2012-05-05 02:58:55Z adamlundrigan $
*/
/**
* @see Zend_Mime_Decode
*/
require_once 'Zend/Mime/Decode.php';
/**
* @see Zend_Mail_Part_Interface
*/
require_once 'Zend/Mail/Part/Interface.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Part implements RecursiveIterator, Zend_Mail_Part_Interface
{
/**
* headers of part as array
* @var null|array
*/
protected $_headers;
/**
* raw part body
* @var null|string
*/
protected $_content;
/**
* toplines as fetched with headers
* @var string
*/
protected $_topLines = '';
/**
* parts of multipart message
* @var array
*/
protected $_parts = array();
/**
* count of parts of a multipart message
* @var null|int
*/
protected $_countParts;
/**
* current position of iterator
* @var int
*/
protected $_iterationPos = 1;
/**
* mail handler, if late fetch is active
* @var null|Zend_Mail_Storage_Abstract
*/
protected $_mail;
/**
* message number for mail handler
* @var int
*/
protected $_messageNum = 0;
/**
* Class to use when creating message parts
* @var string
*/
protected $_partClass;
/**
* Public constructor
*
* Zend_Mail_Part supports different sources for content. The possible params are:
* - handler a instance of Zend_Mail_Storage_Abstract for late fetch
* - id number of message for handler
* - raw raw content with header and body as string
* - headers headers as array (name => value) or string, if a content part is found it's used as toplines
* - noToplines ignore content found after headers in param 'headers'
* - content content as string
*
* @param array $params full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (isset($params['handler'])) {
if (!$params['handler'] instanceof Zend_Mail_Storage_Abstract) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('handler is not a valid mail handler');
}
if (!isset($params['id'])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('need a message id with a handler');
}
$this->_mail = $params['handler'];
$this->_messageNum = $params['id'];
}
if (isset($params['partclass'])) {
$this->setPartClass($params['partclass']);
}
if (isset($params['raw'])) {
Zend_Mime_Decode::splitMessage($params['raw'], $this->_headers, $this->_content);
} else if (isset($params['headers'])) {
if (is_array($params['headers'])) {
$this->_headers = $params['headers'];
} else {
if (!empty($params['noToplines'])) {
Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $null);
} else {
Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $this->_topLines);
}
}
if (isset($params['content'])) {
$this->_content = $params['content'];
}
}
}
/**
* Set name pf class used to encapsulate message parts
* @param string $class
* @return Zend_Mail_Part
*/
public function setPartClass($class)
{
if ( !class_exists($class) ) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception("Class '{$class}' does not exist");
}
if ( !is_subclass_of($class, 'Zend_Mail_Part_Interface') ) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception("Class '{$class}' must implement Zend_Mail_Part_Interface");
}
$this->_partClass = $class;
return $this;
}
/**
* Retrieve the class name used to encapsulate message parts
* @return string
*/
public function getPartClass()
{
if ( !$this->_partClass ) {
$this->_partClass = __CLASS__;
}
return $this->_partClass;
}
/**
* Check if part is a multipart message
*
* @return bool if part is multipart
*/
public function isMultipart()
{
try {
return stripos($this->contentType, 'multipart/') === 0;
} catch(Zend_Mail_Exception $e) {
return false;
}
}
/**
* Body of part
*
* If part is multipart the raw content of this part with all sub parts is returned
*
* @return string body
* @throws Zend_Mail_Exception
*/
public function getContent()
{
if ($this->_content !== null) {
return $this->_content;
}
if ($this->_mail) {
return $this->_mail->getRawContent($this->_messageNum);
} else {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no content');
}
}
/**
* Return size of part
*
* Quite simple implemented currently (not decoding). Handle with care.
*
* @return int size
*/
public function getSize() {
return strlen($this->getContent());
}
/**
* Cache content and split in parts if multipart
*
* @return null
* @throws Zend_Mail_Exception
*/
protected function _cacheContent()
{
// caching content if we can't fetch parts
if ($this->_content === null && $this->_mail) {
$this->_content = $this->_mail->getRawContent($this->_messageNum);
}
if (!$this->isMultipart()) {
return;
}
// split content in parts
$boundary = $this->getHeaderField('content-type', 'boundary');
if (!$boundary) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no boundary found in content type to split message');
}
$parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary);
if ($parts === null) {
return;
}
$partClass = $this->getPartClass();
$counter = 1;
foreach ($parts as $part) {
$this->_parts[$counter++] = new $partClass(array('headers' => $part['header'], 'content' => $part['body']));
}
}
/**
* Get part of multipart message
*
* @param int $num number of part starting with 1 for first part
* @return Zend_Mail_Part wanted part
* @throws Zend_Mail_Exception
*/
public function getPart($num)
{
if (isset($this->_parts[$num])) {
return $this->_parts[$num];
}
if (!$this->_mail && $this->_content === null) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('part not found');
}
if ($this->_mail && $this->_mail->hasFetchPart) {
// TODO: fetch part
// return
}
$this->_cacheContent();
if (!isset($this->_parts[$num])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('part not found');
}
return $this->_parts[$num];
}
/**
* Count parts of a multipart part
*
* @return int number of sub-parts
*/
public function countParts()
{
if ($this->_countParts) {
return $this->_countParts;
}
$this->_countParts = count($this->_parts);
if ($this->_countParts) {
return $this->_countParts;
}
if ($this->_mail && $this->_mail->hasFetchPart) {
// TODO: fetch part
// return
}
$this->_cacheContent();
$this->_countParts = count($this->_parts);
return $this->_countParts;
}
/**
* Get all headers
*
* The returned headers are as saved internally. All names are lowercased. The value is a string or an array
* if a header with the same name occurs more than once.
*
* @return array headers as array(name => value)
*/
public function getHeaders()
{
if ($this->_headers === null) {
if (!$this->_mail) {
$this->_headers = array();
} else {
$part = $this->_mail->getRawHeader($this->_messageNum);
Zend_Mime_Decode::splitMessage($part, $this->_headers, $null);
}
}
return $this->_headers;
}
/**
* Get a header in specificed format
*
* Internally headers that occur more than once are saved as array, all other as string. If $format
* is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
*
* @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes
* @param string $format change type of return value to 'string' or 'array'
* @return string|array value of header in wanted or internal format
* @throws Zend_Mail_Exception
*/
public function getHeader($name, $format = null)
{
if ($this->_headers === null) {
$this->getHeaders();
}
$lowerName = strtolower($name);
if ($this->headerExists($name) == false) {
$lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
if($this->headerExists($lowerName) == false) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception("no Header with Name $name or $lowerName found");
}
}
$name = $lowerName;
$header = $this->_headers[$name];
switch ($format) {
case 'string':
if (is_array($header)) {
$header = implode(Zend_Mime::LINEEND, $header);
}
break;
case 'array':
$header = (array)$header;
default:
// do nothing
}
return $header;
}
/**
* Check wheater the Mail part has a specific header.
*
* @param string $name
* @return boolean
*/
public function headerExists($name)
{
$name = strtolower($name);
if(isset($this->_headers[$name])) {
return true;
} else {
return false;
}
}
/**
* Get a specific field from a header like content type or all fields as array
*
* If the header occurs more than once, only the value from the first header
* is returned.
*
* Throws a Zend_Mail_Exception if the requested header does not exist. If
* the specific header field does not exist, returns null.
*
* @param string $name name of header, like in getHeader()
* @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned
* @param string $firstName key name for the first part
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
* @throws Zend_Exception, Zend_Mail_Exception
*/
public function getHeaderField($name, $wantedPart = 0, $firstName = 0) {
return Zend_Mime_Decode::splitHeaderField(current($this->getHeader($name, 'array')), $wantedPart, $firstName);
}
/**
* Getter for mail headers - name is matched in lowercase
*
* This getter is short for Zend_Mail_Part::getHeader($name, 'string')
*
* @see Zend_Mail_Part::getHeader()
*
* @param string $name header name
* @return string value of header
* @throws Zend_Mail_Exception
*/
public function __get($name)
{
return $this->getHeader($name, 'string');
}
/**
* Isset magic method proxy to hasHeader
*
* This method is short syntax for Zend_Mail_Part::hasHeader($name);
*
* @see Zend_Mail_Part::hasHeader
*
* @param string
* @return boolean
*/
public function __isset($name)
{
return $this->headerExists($name);
}
/**
* magic method to get content of part
*
* @return string content
*/
public function __toString()
{
return $this->getContent();
}
/**
* implements RecursiveIterator::hasChildren()
*
* @return bool current element has children/is multipart
*/
public function hasChildren()
{
$current = $this->current();
return $current && $current instanceof Zend_Mail_Part && $current->isMultipart();
}
/**
* implements RecursiveIterator::getChildren()
*
* @return Zend_Mail_Part same as self::current()
*/
public function getChildren()
{
return $this->current();
}
/**
* implements Iterator::valid()
*
* @return bool check if there's a current element
*/
public function valid()
{
if ($this->_countParts === null) {
$this->countParts();
}
return $this->_iterationPos && $this->_iterationPos <= $this->_countParts;
}
/**
* implements Iterator::next()
*
* @return null
*/
public function next()
{
++$this->_iterationPos;
}
/**
* implements Iterator::key()
*
* @return string key/number of current part
*/
public function key()
{
return $this->_iterationPos;
}
/**
* implements Iterator::current()
*
* @return Zend_Mail_Part current part
*/
public function current()
{
return $this->getPart($this->_iterationPos);
}
/**
* implements Iterator::rewind()
*
* @return null
*/
public function rewind()
{
$this->countParts();
$this->_iterationPos = 1;
}
}

View File

@ -0,0 +1,198 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime_Decode
*/
require_once 'Zend/Mime/Decode.php';
/**
* @see Zend_Mail_Part
*/
require_once 'Zend/Mail/Part.php';
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Part_File extends Zend_Mail_Part
{
protected $_contentPos = array();
protected $_partPos = array();
protected $_fh;
/**
* Public constructor
*
* This handler supports the following params:
* - file filename or open file handler with message content (required)
* - startPos start position of message or part in file (default: current position)
* - endPos end position of message or part in file (default: end of file)
*
* @param array $params full message with or without headers
* @throws Zend_Mail_Exception
*/
public function __construct(array $params)
{
if (empty($params['file'])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no file given in params');
}
if (!is_resource($params['file'])) {
$this->_fh = fopen($params['file'], 'r');
} else {
$this->_fh = $params['file'];
}
if (!$this->_fh) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('could not open file');
}
if (isset($params['startPos'])) {
fseek($this->_fh, $params['startPos']);
}
$header = '';
$endPos = isset($params['endPos']) ? $params['endPos'] : null;
while (($endPos === null || ftell($this->_fh) < $endPos) && trim($line = fgets($this->_fh))) {
$header .= $line;
}
Zend_Mime_Decode::splitMessage($header, $this->_headers, $null);
$this->_contentPos[0] = ftell($this->_fh);
if ($endPos !== null) {
$this->_contentPos[1] = $endPos;
} else {
fseek($this->_fh, 0, SEEK_END);
$this->_contentPos[1] = ftell($this->_fh);
}
if (!$this->isMultipart()) {
return;
}
$boundary = $this->getHeaderField('content-type', 'boundary');
if (!$boundary) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('no boundary found in content type to split message');
}
$part = array();
$pos = $this->_contentPos[0];
fseek($this->_fh, $pos);
while (!feof($this->_fh) && ($endPos === null || $pos < $endPos)) {
$line = fgets($this->_fh);
if ($line === false) {
if (feof($this->_fh)) {
break;
}
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('error reading file');
}
$lastPos = $pos;
$pos = ftell($this->_fh);
$line = trim($line);
if ($line == '--' . $boundary) {
if ($part) {
// not first part
$part[1] = $lastPos;
$this->_partPos[] = $part;
}
$part = array($pos);
} else if ($line == '--' . $boundary . '--') {
$part[1] = $lastPos;
$this->_partPos[] = $part;
break;
}
}
$this->_countParts = count($this->_partPos);
}
/**
* Body of part
*
* If part is multipart the raw content of this part with all sub parts is returned
*
* @return string body
* @throws Zend_Mail_Exception
*/
public function getContent($stream = null)
{
fseek($this->_fh, $this->_contentPos[0]);
if ($stream !== null) {
return stream_copy_to_stream($this->_fh, $stream, $this->_contentPos[1] - $this->_contentPos[0]);
}
$length = $this->_contentPos[1] - $this->_contentPos[0];
return $length < 1 ? '' : fread($this->_fh, $length);
}
/**
* Return size of part
*
* Quite simple implemented currently (not decoding). Handle with care.
*
* @return int size
*/
public function getSize() {
return $this->_contentPos[1] - $this->_contentPos[0];
}
/**
* Get part of multipart message
*
* @param int $num number of part starting with 1 for first part
* @return Zend_Mail_Part wanted part
* @throws Zend_Mail_Exception
*/
public function getPart($num)
{
--$num;
if (!isset($this->_partPos[$num])) {
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('part not found');
}
return new self(array('file' => $this->_fh, 'startPos' => $this->_partPos[$num][0],
'endPos' => $this->_partPos[$num][1]));
}
}

View File

@ -0,0 +1,136 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Part_Interface extends RecursiveIterator
{
/**
* Check if part is a multipart message
*
* @return bool if part is multipart
*/
public function isMultipart();
/**
* Body of part
*
* If part is multipart the raw content of this part with all sub parts is returned
*
* @return string body
* @throws Zend_Mail_Exception
*/
public function getContent();
/**
* Return size of part
*
* @return int size
*/
public function getSize();
/**
* Get part of multipart message
*
* @param int $num number of part starting with 1 for first part
* @return Zend_Mail_Part wanted part
* @throws Zend_Mail_Exception
*/
public function getPart($num);
/**
* Count parts of a multipart part
*
* @return int number of sub-parts
*/
public function countParts();
/**
* Get all headers
*
* The returned headers are as saved internally. All names are lowercased. The value is a string or an array
* if a header with the same name occurs more than once.
*
* @return array headers as array(name => value)
*/
public function getHeaders();
/**
* Get a header in specificed format
*
* Internally headers that occur more than once are saved as array, all other as string. If $format
* is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
*
* @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes
* @param string $format change type of return value to 'string' or 'array'
* @return string|array value of header in wanted or internal format
* @throws Zend_Mail_Exception
*/
public function getHeader($name, $format = null);
/**
* Get a specific field from a header like content type or all fields as array
*
* If the header occurs more than once, only the value from the first header
* is returned.
*
* Throws a Zend_Mail_Exception if the requested header does not exist. If
* the specific header field does not exist, returns null.
*
* @param string $name name of header, like in getHeader()
* @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned
* @param string $firstName key name for the first part
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
* @throws Zend_Exception, Zend_Mail_Exception
*/
public function getHeaderField($name, $wantedPart = 0, $firstName = 0);
/**
* Getter for mail headers - name is matched in lowercase
*
* This getter is short for Zend_Mail_Part::getHeader($name, 'string')
*
* @see Zend_Mail_Part::getHeader()
*
* @param string $name header name
* @return string value of header
* @throws Zend_Mail_Exception
*/
public function __get($name);
/**
* magic method to get content of part
*
* @return string content
*/
public function __toString();
}

View File

@ -0,0 +1,447 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Validate
*/
require_once 'Zend/Validate.php';
/**
* @see Zend_Validate_Hostname
*/
require_once 'Zend/Validate/Hostname.php';
/**
* Zend_Mail_Protocol_Abstract
*
* Provides low-level methods for concrete adapters to communicate with a remote mail server and track requests and responses.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
* @todo Implement proxy settings
*/
abstract class Zend_Mail_Protocol_Abstract
{
/**
* Mail default EOL string
*/
const EOL = "\r\n";
/**
* Default timeout in seconds for initiating session
*/
const TIMEOUT_CONNECTION = 30;
/**
* Maximum of the transaction log
* @var integer
*/
protected $_maximumLog = 64;
/**
* Hostname or IP address of remote server
* @var string
*/
protected $_host;
/**
* Port number of connection
* @var integer
*/
protected $_port;
/**
* Instance of Zend_Validate to check hostnames
* @var Zend_Validate
*/
protected $_validHost;
/**
* Socket connection resource
* @var resource
*/
protected $_socket;
/**
* Last request sent to server
* @var string
*/
protected $_request;
/**
* Array of server responses to last request
* @var array
*/
protected $_response;
/**
* String template for parsing server responses using sscanf (default: 3 digit code and response string)
* @var resource
* @deprecated Since 1.10.3
*/
protected $_template = '%d%s';
/**
* Log of mail requests and server responses for a session
* @var array
*/
private $_log = array();
/**
* Constructor.
*
* @param string $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
* @param integer $port OPTIONAL Port number (default: null)
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null)
{
$this->_validHost = new Zend_Validate();
$this->_validHost->addValidator(new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL));
if (!$this->_validHost->isValid($host)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
}
$this->_host = $host;
$this->_port = $port;
}
/**
* Class destructor to cleanup open resources
*
* @return void
*/
public function __destruct()
{
$this->_disconnect();
}
/**
* Set the maximum log size
*
* @param integer $maximumLog Maximum log size
* @return void
*/
public function setMaximumLog($maximumLog)
{
$this->_maximumLog = (int) $maximumLog;
}
/**
* Get the maximum log size
*
* @return int the maximum log size
*/
public function getMaximumLog()
{
return $this->_maximumLog;
}
/**
* Create a connection to the remote host
*
* Concrete adapters for this class will implement their own unique connect scripts, using the _connect() method to create the socket resource.
*/
abstract public function connect();
/**
* Retrieve the last client request
*
* @return string
*/
public function getRequest()
{
return $this->_request;
}
/**
* Retrieve the last server response
*
* @return array
*/
public function getResponse()
{
return $this->_response;
}
/**
* Retrieve the transaction log
*
* @return string
*/
public function getLog()
{
return implode('', $this->_log);
}
/**
* Reset the transaction log
*
* @return void
*/
public function resetLog()
{
$this->_log = array();
}
/**
* Add the transaction log
*
* @param string new transaction
* @return void
*/
protected function _addLog($value)
{
if ($this->_maximumLog >= 0 && count($this->_log) >= $this->_maximumLog) {
array_shift($this->_log);
}
$this->_log[] = $value;
}
/**
* Connect to the server using the supplied transport and target
*
* An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
*
* @param string $remote Remote
* @throws Zend_Mail_Protocol_Exception
* @return boolean
*/
protected function _connect($remote)
{
$errorNum = 0;
$errorStr = '';
// open connection
$this->_socket = @stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION);
if ($this->_socket === false) {
if ($errorNum == 0) {
$errorStr = 'Could not open socket';
}
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($errorStr);
}
if (($result = $this->_setStreamTimeout(self::TIMEOUT_CONNECTION)) === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Could not set stream timeout');
}
return $result;
}
/**
* Disconnect from remote host and free resource
*
* @return void
*/
protected function _disconnect()
{
if (is_resource($this->_socket)) {
fclose($this->_socket);
}
}
/**
* Send the given request followed by a LINEEND to the server.
*
* @param string $request
* @throws Zend_Mail_Protocol_Exception
* @return integer|boolean Number of bytes written to remote host
*/
protected function _send($request)
{
if (!is_resource($this->_socket)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
}
$this->_request = $request;
$result = fwrite($this->_socket, $request . self::EOL);
// Save request to internal log
$this->_addLog($request . self::EOL);
if ($result === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Could not send request to ' . $this->_host);
}
return $result;
}
/**
* Get a line from the stream.
*
* @var integer $timeout Per-request timeout value if applicable
* @throws Zend_Mail_Protocol_Exception
* @return string
*/
protected function _receive($timeout = null)
{
if (!is_resource($this->_socket)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
}
// Adapters may wish to supply per-commend timeouts according to appropriate RFC
if ($timeout !== null) {
$this->_setStreamTimeout($timeout);
}
// Retrieve response
$reponse = fgets($this->_socket, 1024);
// Save request to internal log
$this->_addLog($reponse);
// Check meta data to ensure connection is still valid
$info = stream_get_meta_data($this->_socket);
if (!empty($info['timed_out'])) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($this->_host . ' has timed out');
}
if ($reponse === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Could not read from ' . $this->_host);
}
return $reponse;
}
/**
* Parse server response for successful codes
*
* Read the response from the stream and check for expected return code.
* Throws a Zend_Mail_Protocol_Exception if an unexpected code is returned.
*
* @param string|array $code One or more codes that indicate a successful response
* @throws Zend_Mail_Protocol_Exception
* @return string Last line of response string
*/
protected function _expect($code, $timeout = null)
{
$this->_response = array();
$cmd = '';
$more = '';
$msg = '';
$errMsg = '';
if (!is_array($code)) {
$code = array($code);
}
do {
$this->_response[] = $result = $this->_receive($timeout);
list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
if ($errMsg !== '') {
$errMsg .= ' ' . $msg;
} elseif ($cmd === null || !in_array($cmd, $code)) {
$errMsg = $msg;
}
} while (strpos($more, '-') === 0); // The '-' message prefix indicates an information string instead of a response string.
if ($errMsg !== '') {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($errMsg, $cmd);
}
return $msg;
}
/**
* Set stream timeout
*
* @param integer $timeout
* @return boolean
*/
protected function _setStreamTimeout($timeout)
{
return stream_set_timeout($this->_socket, $timeout);
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Exception
*/
require_once 'Zend/Mail/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Exception extends Zend_Mail_Exception
{}

View File

@ -0,0 +1,854 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Imap.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Imap
{
/**
* Default timeout in seconds for initiating session
*/
const TIMEOUT_CONNECTION = 30;
/**
* socket to imap server
* @var resource|null
*/
protected $_socket;
/**
* counter for request tag
* @var int
*/
protected $_tagCount = 0;
/**
* Public constructor
*
* @param string $host hostname or IP address of IMAP server, if given connect() is called
* @param int|null $port port of IMAP server, null for default (143 or 993 for ssl)
* @param bool $ssl use ssl? 'SSL', 'TLS' or false
* @throws Zend_Mail_Protocol_Exception
*/
function __construct($host = '', $port = null, $ssl = false)
{
if ($host) {
$this->connect($host, $port, $ssl);
}
}
/**
* Public destructor
*/
public function __destruct()
{
$this->logout();
}
/**
* Open connection to IMAP server
*
* @param string $host hostname or IP address of IMAP server
* @param int|null $port of IMAP server, default is 143 (993 for ssl)
* @param string|bool $ssl use 'SSL', 'TLS' or false
* @return string welcome message
* @throws Zend_Mail_Protocol_Exception
*/
public function connect($host, $port = null, $ssl = false)
{
if ($ssl == 'SSL') {
$host = 'ssl://' . $host;
}
if ($port === null) {
$port = $ssl === 'SSL' ? 993 : 143;
}
$errno = 0;
$errstr = '';
$this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
if (!$this->_socket) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
' (errno = ' . $errno . ' )');
}
if (!$this->_assumedNextLine('* OK')) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection');
}
if ($ssl === 'TLS') {
$result = $this->requestAndResponse('STARTTLS');
$result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
}
}
}
/**
* get the next line from socket with error checking, but nothing else
*
* @return string next line
* @throws Zend_Mail_Protocol_Exception
*/
protected function _nextLine()
{
$line = @fgets($this->_socket);
if ($line === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?');
}
return $line;
}
/**
* get next line and assume it starts with $start. some requests give a simple
* feedback so we can quickly check if we can go on.
*
* @param string $start the first bytes we assume to be in the next line
* @return bool line starts with $start
* @throws Zend_Mail_Protocol_Exception
*/
protected function _assumedNextLine($start)
{
$line = $this->_nextLine();
return strpos($line, $start) === 0;
}
/**
* get next line and split the tag. that's the normal case for a response line
*
* @param string $tag tag of line is returned by reference
* @return string next line
* @throws Zend_Mail_Protocol_Exception
*/
protected function _nextTaggedLine(&$tag)
{
$line = $this->_nextLine();
// seperate tag from line
list($tag, $line) = explode(' ', $line, 2);
return $line;
}
/**
* split a given line in tokens. a token is literal of any form or a list
*
* @param string $line line to decode
* @return array tokens, literals are returned as string, lists as array
* @throws Zend_Mail_Protocol_Exception
*/
protected function _decodeLine($line)
{
$tokens = array();
$stack = array();
/*
We start to decode the response here. The unterstood tokens are:
literal
"literal" or also "lit\\er\"al"
{bytes}<NL>literal
(literals*)
All tokens are returned in an array. Literals in braces (the last unterstood
token in the list) are returned as an array of tokens. I.e. the following response:
"foo" baz {3}<NL>bar ("f\\\"oo" bar)
would be returned as:
array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));
// TODO: add handling of '[' and ']' to parser for easier handling of response text
*/
// replace any trailling <NL> including spaces with a single space
$line = rtrim($line) . ' ';
while (($pos = strpos($line, ' ')) !== false) {
$token = substr($line, 0, $pos);
while ($token[0] == '(') {
array_push($stack, $tokens);
$tokens = array();
$token = substr($token, 1);
}
if ($token[0] == '"') {
if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
$tokens[] = $matches[1];
$line = substr($line, strlen($matches[0]));
continue;
}
}
if ($token[0] == '{') {
$endPos = strpos($token, '}');
$chars = substr($token, 1, $endPos - 1);
if (is_numeric($chars)) {
$token = '';
while (strlen($token) < $chars) {
$token .= $this->_nextLine();
}
$line = '';
if (strlen($token) > $chars) {
$line = substr($token, $chars);
$token = substr($token, 0, $chars);
} else {
$line .= $this->_nextLine();
}
$tokens[] = $token;
$line = trim($line) . ' ';
continue;
}
}
if ($stack && $token[strlen($token) - 1] == ')') {
// closing braces are not seperated by spaces, so we need to count them
$braces = strlen($token);
$token = rtrim($token, ')');
// only count braces if more than one
$braces -= strlen($token) + 1;
// only add if token had more than just closing braces
if (rtrim($token) != '') {
$tokens[] = rtrim($token);
}
$token = $tokens;
$tokens = array_pop($stack);
// special handline if more than one closing brace
while ($braces-- > 0) {
$tokens[] = $token;
$token = $tokens;
$tokens = array_pop($stack);
}
}
$tokens[] = $token;
$line = substr($line, $pos + 1);
}
// maybe the server forgot to send some closing braces
while ($stack) {
$child = $tokens;
$tokens = array_pop($stack);
$tokens[] = $child;
}
return $tokens;
}
/**
* read a response "line" (could also be more than one real line if response has {..}<NL>)
* and do a simple decode
*
* @param array|string $tokens decoded tokens are returned by reference, if $dontParse
* is true the unparsed line is returned here
* @param string $wantedTag check for this tag for response code. Default '*' is
* continuation tag.
* @param bool $dontParse if true only the unparsed line is returned $tokens
* @return bool if returned tag matches wanted tag
* @throws Zend_Mail_Protocol_Exception
*/
public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false)
{
$line = $this->_nextTaggedLine($tag);
if (!$dontParse) {
$tokens = $this->_decodeLine($line);
} else {
$tokens = $line;
}
// if tag is wanted tag we might be at the end of a multiline response
return $tag == $wantedTag;
}
/**
* read all lines of response until given tag is found (last line of response)
*
* @param string $tag the tag of your request
* @param string|array $filter you can filter the response so you get only the
* given response lines
* @param bool $dontParse if true every line is returned unparsed instead of
* the decoded tokens
* @return null|bool|array tokens if success, false if error, null if bad request
* @throws Zend_Mail_Protocol_Exception
*/
public function readResponse($tag, $dontParse = false)
{
$lines = array();
while (!$this->readLine($tokens, $tag, $dontParse)) {
$lines[] = $tokens;
}
if ($dontParse) {
// last to chars are still needed for response code
$tokens = array(substr($tokens, 0, 2));
}
// last line has response code
if ($tokens[0] == 'OK') {
return $lines ? $lines : true;
} else if ($tokens[0] == 'NO'){
return false;
}
return null;
}
/**
* send a request
*
* @param string $command your request command
* @param array $tokens additional parameters to command, use escapeString() to prepare
* @param string $tag provide a tag otherwise an autogenerated is returned
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function sendRequest($command, $tokens = array(), &$tag = null)
{
if (!$tag) {
++$this->_tagCount;
$tag = 'TAG' . $this->_tagCount;
}
$line = $tag . ' ' . $command;
foreach ($tokens as $token) {
if (is_array($token)) {
if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
}
if (!$this->_assumedNextLine('+ ')) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot send literal string');
}
$line = $token[1];
} else {
$line .= ' ' . $token;
}
}
if (@fputs($this->_socket, $line . "\r\n") === false) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
}
}
/**
* send a request and get response at once
*
* @param string $command command as in sendRequest()
* @param array $tokens parameters as in sendRequest()
* @param bool $dontParse if true unparsed lines are returned instead of tokens
* @return mixed response as in readResponse()
* @throws Zend_Mail_Protocol_Exception
*/
public function requestAndResponse($command, $tokens = array(), $dontParse = false)
{
$this->sendRequest($command, $tokens, $tag);
$response = $this->readResponse($tag, $dontParse);
return $response;
}
public function pilerListFolders() {
$folders = array();
$a = $this->requestAndResponse("LIST", array('""', '"*"'));
while(list($k, $v) = each($a)) {
if($v[1][0] == '\HasNoChildren') {
array_push($folders, $v[3]);
}
}
return $folders;
}
/**
* escape one or more literals i.e. for sendRequest
*
* @param string|array $string the literal/-s
* @return string|array escape literals, literals with newline ar returned
* as array('{size}', 'string');
*/
public function escapeString($string)
{
if (func_num_args() < 2) {
if (strpos($string, "\n") !== false) {
return array('{' . strlen($string) . '}', $string);
} else {
return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"';
}
}
$result = array();
foreach (func_get_args() as $string) {
$result[] = $this->escapeString($string);
}
return $result;
}
/**
* escape a list with literals or lists
*
* @param array $list list with literals or lists as PHP array
* @return string escaped list for imap
*/
public function escapeList($list)
{
$result = array();
foreach ($list as $k => $v) {
if (!is_array($v)) {
// $result[] = $this->escapeString($v);
$result[] = $v;
continue;
}
$result[] = $this->escapeList($v);
}
return '(' . implode(' ', $result) . ')';
}
/**
* Login to IMAP server.
*
* @param string $user username
* @param string $password password
* @return bool success
* @throws Zend_Mail_Protocol_Exception
*/
public function login($user, $password)
{
return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true);
}
/**
* logout of imap server
*
* @return bool success
*/
public function logout()
{
$result = false;
if ($this->_socket) {
try {
$result = $this->requestAndResponse('LOGOUT', array(), true);
} catch (Zend_Mail_Protocol_Exception $e) {
// ignoring exception
}
fclose($this->_socket);
$this->_socket = null;
}
return $result;
}
/**
* Get capabilities from IMAP server
*
* @return array list of capabilities
* @throws Zend_Mail_Protocol_Exception
*/
public function capability()
{
$response = $this->requestAndResponse('CAPABILITY');
if (!$response) {
return $response;
}
$capabilities = array();
foreach ($response as $line) {
$capabilities = array_merge($capabilities, $line);
}
return $capabilities;
}
/**
* Examine and select have the same response. The common code for both
* is in this method
*
* @param string $command can be 'EXAMINE' or 'SELECT' and this is used as command
* @param string $box which folder to change to or examine
* @return bool|array false if error, array with returned information
* otherwise (flags, exists, recent, uidvalidity)
* @throws Zend_Mail_Protocol_Exception
*/
public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
{
$this->sendRequest($command, array($this->escapeString($box)), $tag);
$result = array();
while (!$this->readLine($tokens, $tag)) {
if ($tokens[0] == 'FLAGS') {
array_shift($tokens);
$result['flags'] = $tokens;
continue;
}
switch ($tokens[1]) {
case 'EXISTS':
case 'RECENT':
$result[strtolower($tokens[1])] = $tokens[0];
break;
case '[UIDVALIDITY':
$result['uidvalidity'] = (int)$tokens[2];
break;
default:
// ignore
}
}
if ($tokens[0] != 'OK') {
return false;
}
return $result;
}
/**
* change folder
*
* @param string $box change to this folder
* @return bool|array see examineOrselect()
* @throws Zend_Mail_Protocol_Exception
*/
public function select($box = 'INBOX')
{
return $this->examineOrSelect('SELECT', $box);
}
/**
* examine folder
*
* @param string $box examine this folder
* @return bool|array see examineOrselect()
* @throws Zend_Mail_Protocol_Exception
*/
public function examine($box = 'INBOX')
{
return $this->examineOrSelect('EXAMINE', $box);
}
/**
* fetch one or more items of one or more messages
*
* @param string|array $items items to fetch from message(s) as string (if only one item)
* or array of strings
* @param int $from message for items or start message if $to !== null
* @param int|null $to if null only one message ($from) is fetched, else it's the
* last message, INF means last message avaible
* @return string|array if only one item of one message is fetched it's returned as string
* if items of one message are fetched it's returned as (name => value)
* if one items of messages are fetched it's returned as (msgno => value)
* if items of messages are fetchted it's returned as (msgno => (name => value))
* @throws Zend_Mail_Protocol_Exception
*/
public function fetch($items, $from, $to = null)
{
if (is_array($from)) {
$set = implode(',', $from);
} else if ($to === null) {
$set = (int)$from;
} else if ($to === INF) {
$set = (int)$from . ':*';
} else {
$set = (int)$from . ':' . (int)$to;
}
$items = (array)$items;
$itemList = $this->escapeList($items);
$this->sendRequest('FETCH', array($set, $itemList), $tag);
$result = array();
while (!$this->readLine($tokens, $tag)) {
// ignore other responses
if ($tokens[1] != 'FETCH') {
continue;
}
// ignore other messages
if ($to === null && !is_array($from) && $tokens[0] != $from) {
continue;
}
// if we only want one item we return that one directly
if (count($items) == 1) {
if ($tokens[2][0] == $items[0]) {
$data = $tokens[2][1];
} else {
// maybe the server send an other field we didn't wanted
$count = count($tokens[2]);
// we start with 2, because 0 was already checked
for ($i = 2; $i < $count; $i += 2) {
if ($tokens[2][$i] != $items[0]) {
continue;
}
$data = $tokens[2][$i + 1];
break;
}
}
} else {
$data = array();
while (key($tokens[2]) !== null) {
$data[current($tokens[2])] = next($tokens[2]);
next($tokens[2]);
}
}
// if we want only one message we can ignore everything else and just return
if ($to === null && !is_array($from) && $tokens[0] == $from) {
// we still need to read all lines
while (!$this->readLine($tokens, $tag));
return $data;
}
$result[$tokens[0]] = $data;
}
if ($to === null && !is_array($from)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('the single id was not found in response');
}
return $result;
}
/**
* get mailbox list
*
* this method can't be named after the IMAP command 'LIST', as list is a reserved keyword
*
* @param string $reference mailbox reference for list
* @param string $mailbox mailbox name match with wildcards
* @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
* @throws Zend_Mail_Protocol_Exception
*/
public function listMailbox($reference = '', $mailbox = '*')
{
$result = array();
$list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
if (!$list || $list === true) {
return $result;
}
foreach ($list as $item) {
if (count($item) != 4 || $item[0] != 'LIST') {
continue;
}
$result[$item[3]] = array('delim' => $item[2], 'flags' => $item[1]);
}
return $result;
}
/**
* set flags
*
* @param array $flags flags to set, add or remove - see $mode
* @param int $from message for items or start message if $to !== null
* @param int|null $to if null only one message ($from) is fetched, else it's the
* last message, INF means last message avaible
* @param string|null $mode '+' to add flags, '-' to remove flags, everything else sets the flags as given
* @param bool $silent if false the return values are the new flags for the wanted messages
* @return bool|array new flags if $silent is false, else true or false depending on success
* @throws Zend_Mail_Protocol_Exception
*/
public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
{
$item = 'FLAGS';
if ($mode == '+' || $mode == '-') {
$item = $mode . $item;
}
if ($silent) {
$item .= '.SILENT';
}
$flags = $this->escapeList($flags);
$set = (int)$from;
if ($to != null) {
$set .= ':' . ($to == INF ? '*' : (int)$to);
}
$result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent);
if ($silent) {
return $result ? true : false;
}
$tokens = $result;
$result = array();
foreach ($tokens as $token) {
if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') {
continue;
}
$result[$token[0]] = $token[2][1];
}
return $result;
}
/**
* append a new message to given folder
*
* @param string $folder name of target folder
* @param string $message full message content
* @param array $flags flags for new message
* @param string $date date for new message
* @return bool success
* @throws Zend_Mail_Protocol_Exception
*/
public function append($folder, $message, $flags = null, $date = null)
{
$tokens = array();
$tokens[] = $this->escapeString($folder);
if ($flags !== null) {
$tokens[] = $this->escapeList($flags);
}
if ($date !== null) {
$tokens[] = $this->escapeString($date);
}
$tokens[] = $this->escapeString($message);
return $this->requestAndResponse('APPEND', $tokens, true);
}
/**
* copy message set from current folder to other folder
*
* @param string $folder destination folder
* @param int|null $to if null only one message ($from) is fetched, else it's the
* last message, INF means last message avaible
* @return bool success
* @throws Zend_Mail_Protocol_Exception
*/
public function copy($folder, $from, $to = null)
{
$set = (int)$from;
if ($to != null) {
$set .= ':' . ($to == INF ? '*' : (int)$to);
}
return $this->requestAndResponse('COPY', array($set, $this->escapeString($folder)), true);
}
/**
* create a new folder (and parent folders if needed)
*
* @param string $folder folder name
* @return bool success
*/
public function create($folder)
{
return $this->requestAndResponse('CREATE', array($this->escapeString($folder)), true);
}
/**
* rename an existing folder
*
* @param string $old old name
* @param string $new new name
* @return bool success
*/
public function rename($old, $new)
{
return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true);
}
/**
* remove a folder
*
* @param string $folder folder name
* @return bool success
*/
public function delete($folder)
{
return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true);
}
/**
* permanently remove messages
*
* @return bool success
*/
public function expunge()
{
// TODO: parse response?
return $this->requestAndResponse('EXPUNGE');
}
/**
* send noop
*
* @return bool success
*/
public function noop()
{
// TODO: parse response
return $this->requestAndResponse('NOOP');
}
/**
* do a search request
*
* This method is currently marked as internal as the API might change and is not
* safe if you don't take precautions.
*
* @internal
* @return array message ids
*/
public function search(array $params)
{
$response = $this->requestAndResponse('SEARCH', $params);
if (!$response) {
return $response;
}
foreach ($response as $ids) {
if ($ids[0] == 'SEARCH') {
array_shift($ids);
return $ids;
}
}
return array();
}
}

View File

@ -0,0 +1,472 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Pop3.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Pop3
{
/**
* Default timeout in seconds for initiating session
*/
const TIMEOUT_CONNECTION = 30;
/**
* saves if server supports top
* @var null|bool
*/
public $hasTop = null;
/**
* socket to pop3
* @var null|resource
*/
protected $_socket;
/**
* greeting timestamp for apop
* @var null|string
*/
protected $_timestamp;
/**
* Public constructor
*
* @param string $host hostname or IP address of POP3 server, if given connect() is called
* @param int|null $port port of POP3 server, null for default (110 or 995 for ssl)
* @param bool|string $ssl use ssl? 'SSL', 'TLS' or false
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($host = '', $port = null, $ssl = false)
{
if ($host) {
$this->connect($host, $port, $ssl);
}
}
/**
* Public destructor
*/
public function __destruct()
{
$this->logout();
}
/**
* Open connection to POP3 server
*
* @param string $host hostname or IP address of POP3 server
* @param int|null $port of POP3 server, default is 110 (995 for ssl)
* @param string|bool $ssl use 'SSL', 'TLS' or false
* @return string welcome message
* @throws Zend_Mail_Protocol_Exception
*/
public function connect($host, $port = null, $ssl = false)
{
if ($ssl == 'SSL') {
$host = 'ssl://' . $host;
}
if ($port === null) {
$port = $ssl == 'SSL' ? 995 : 110;
}
$errno = 0;
$errstr = '';
$this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
if (!$this->_socket) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
' (errno = ' . $errno . ' )');
}
$welcome = $this->readResponse();
strtok($welcome, '<');
$this->_timestamp = strtok('>');
if (!strpos($this->_timestamp, '@')) {
$this->_timestamp = null;
} else {
$this->_timestamp = '<' . $this->_timestamp . '>';
}
if ($ssl === 'TLS') {
$this->request('STLS');
$result = stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
}
}
return $welcome;
}
/**
* Send a request
*
* @param string $request your request without newline
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function sendRequest($request)
{
$result = @fputs($this->_socket, $request . "\r\n");
if (!$result) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('send failed - connection closed?');
}
}
/**
* read a response
*
* @param boolean $multiline response has multiple lines and should be read until "<nl>.<nl>"
* @return string response
* @throws Zend_Mail_Protocol_Exception
*/
public function readResponse($multiline = false)
{
$result = @fgets($this->_socket);
if (!is_string($result)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('read failed - connection closed?');
}
$result = trim($result);
if (strpos($result, ' ')) {
list($status, $message) = explode(' ', $result, 2);
} else {
$status = $result;
$message = '';
}
if ($status != '+OK') {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('last request failed');
}
if ($multiline) {
$message = '';
$line = fgets($this->_socket);
while ($line && rtrim($line, "\r\n") != '.') {
if ($line[0] == '.') {
$line = substr($line, 1);
}
$message .= $line;
$line = fgets($this->_socket);
};
}
return $message;
}
/**
* Send request and get resposne
*
* @see sendRequest(), readResponse()
*
* @param string $request request
* @param bool $multiline multiline response?
* @return string result from readResponse()
* @throws Zend_Mail_Protocol_Exception
*/
public function request($request, $multiline = false)
{
$this->sendRequest($request);
return $this->readResponse($multiline);
}
/**
* End communication with POP3 server (also closes socket)
*
* @return null
*/
public function logout()
{
if (!$this->_socket) {
return;
}
try {
$this->request('QUIT');
} catch (Zend_Mail_Protocol_Exception $e) {
// ignore error - we're closing the socket anyway
}
fclose($this->_socket);
$this->_socket = null;
}
/**
* Get capabilities from POP3 server
*
* @return array list of capabilities
* @throws Zend_Mail_Protocol_Exception
*/
public function capa()
{
$result = $this->request('CAPA', true);
return explode("\n", $result);
}
/**
* Login to POP3 server. Can use APOP
*
* @param string $user username
* @param string $password password
* @param bool $try_apop should APOP be tried?
* @return void
* @throws Zend_Mail_Protocol_Exception
*/
public function login($user, $password, $tryApop = true)
{
if ($tryApop && $this->_timestamp) {
try {
$this->request("APOP $user " . md5($this->_timestamp . $password));
return;
} catch (Zend_Mail_Protocol_Exception $e) {
// ignore
}
}
$result = $this->request("USER $user");
$result = $this->request("PASS $password");
}
/**
* Make STAT call for message count and size sum
*
* @param int $messages out parameter with count of messages
* @param int $octets out parameter with size in octects of messages
* @return void
* @throws Zend_Mail_Protocol_Exception
*/
public function status(&$messages, &$octets)
{
$messages = 0;
$octets = 0;
$result = $this->request('STAT');
list($messages, $octets) = explode(' ', $result);
}
/**
* Make LIST call for size of message(s)
*
* @param int|null $msgno number of message, null for all
* @return int|array size of given message or list with array(num => size)
* @throws Zend_Mail_Protocol_Exception
*/
public function getList($msgno = null)
{
if ($msgno !== null) {
$result = $this->request("LIST $msgno");
list(, $result) = explode(' ', $result);
return (int)$result;
}
$result = $this->request('LIST', true);
$messages = array();
$line = strtok($result, "\n");
while ($line) {
list($no, $size) = explode(' ', trim($line));
$messages[(int)$no] = (int)$size;
$line = strtok("\n");
}
return $messages;
}
/**
* Make UIDL call for getting a uniqueid
*
* @param int|null $msgno number of message, null for all
* @return string|array uniqueid of message or list with array(num => uniqueid)
* @throws Zend_Mail_Protocol_Exception
*/
public function uniqueid($msgno = null)
{
if ($msgno !== null) {
$result = $this->request("UIDL $msgno");
list(, $result) = explode(' ', $result);
return $result;
}
$result = $this->request('UIDL', true);
$result = explode("\n", $result);
$messages = array();
foreach ($result as $line) {
if (!$line) {
continue;
}
list($no, $id) = explode(' ', trim($line), 2);
$messages[(int)$no] = $id;
}
return $messages;
}
/**
* Make TOP call for getting headers and maybe some body lines
* This method also sets hasTop - before it it's not known if top is supported
*
* The fallback makes normale RETR call, which retrieves the whole message. Additional
* lines are not removed.
*
* @param int $msgno number of message
* @param int $lines number of wanted body lines (empty line is inserted after header lines)
* @param bool $fallback fallback with full retrieve if top is not supported
* @return string message headers with wanted body lines
* @throws Zend_Mail_Protocol_Exception
*/
public function top($msgno, $lines = 0, $fallback = false)
{
if ($this->hasTop === false) {
if ($fallback) {
return $this->retrieve($msgno);
} else {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('top not supported and no fallback wanted');
}
}
$this->hasTop = true;
$lines = (!$lines || $lines < 1) ? 0 : (int)$lines;
try {
$result = $this->request("TOP $msgno $lines", true);
} catch (Zend_Mail_Protocol_Exception $e) {
$this->hasTop = false;
if ($fallback) {
$result = $this->retrieve($msgno);
} else {
throw $e;
}
}
return $result;
}
/**
* Make a RETR call for retrieving a full message with headers and body
*
* @deprecated since 1.1.0; this method has a typo - please use retrieve()
* @param int $msgno message number
* @return string message
* @throws Zend_Mail_Protocol_Exception
*/
public function retrive($msgno)
{
return $this->retrieve($msgno);
}
/**
* Make a RETR call for retrieving a full message with headers and body
*
* @param int $msgno message number
* @return string message
* @throws Zend_Mail_Protocol_Exception
*/
public function retrieve($msgno)
{
$result = $this->request("RETR $msgno", true);
return $result;
}
/**
* Make a NOOP call, maybe needed for keeping the server happy
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function noop()
{
$this->request('NOOP');
}
/**
* Make a DELE count to remove a message
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function delete($msgno)
{
$this->request("DELE $msgno");
}
/**
* Make RSET call, which rollbacks delete requests
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function undelete()
{
$this->request('RSET');
}
}

View File

@ -0,0 +1,443 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Smtp.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* @see Zend_Mail_Protocol_Abstract
*/
require_once 'Zend/Mail/Protocol/Abstract.php';
/**
* Smtp implementation of Zend_Mail_Protocol_Abstract
*
* Minimum implementation according to RFC2821: EHLO, MAIL FROM, RCPT TO, DATA, RSET, NOOP, QUIT
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp extends Zend_Mail_Protocol_Abstract
{
/**
* The transport method for the socket
*
* @var string
*/
protected $_transport = 'tcp';
/**
* Indicates that a session is requested to be secure
*
* @var string
*/
protected $_secure;
/**
* Indicates an smtp session has been started by the HELO command
*
* @var boolean
*/
protected $_sess = false;
/**
* Indicates the HELO command has been issues
*
* @var unknown_type
*/
protected $_helo = false;
/**
* Indicates an smtp AUTH has been issued and authenticated
*
* @var unknown_type
*/
protected $_auth = false;
/**
* Indicates a MAIL command has been issued
*
* @var unknown_type
*/
protected $_mail = false;
/**
* Indicates one or more RCTP commands have been issued
*
* @var unknown_type
*/
protected $_rcpt = false;
/**
* Indicates that DATA has been issued and sent
*
* @var unknown_type
*/
protected $_data = null;
/**
* Constructor.
*
* @param string $host
* @param integer $port
* @param array $config
* @return void
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($host = '127.0.0.1', $port = null, array $config = array())
{
if (isset($config['ssl'])) {
switch (strtolower($config['ssl'])) {
case 'tls':
$this->_secure = 'tls';
break;
case 'ssl':
$this->_transport = 'ssl';
$this->_secure = 'ssl';
if ($port == null) {
$port = 465;
}
break;
default:
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception($config['ssl'] . ' is unsupported SSL type');
break;
}
}
// If no port has been specified then check the master PHP ini file. Defaults to 25 if the ini setting is null.
if ($port == null) {
if (($port = ini_get('smtp_port')) == '') {
$port = 25;
}
}
parent::__construct($host, $port);
}
/**
* Connect to the server with the parameters given in the constructor.
*
* @return boolean
*/
public function connect()
{
return $this->_connect($this->_transport . '://' . $this->_host . ':'. $this->_port);
}
/**
* Initiate HELO/EHLO sequence and set flag to indicate valid smtp session
*
* @param string $host The client hostname or IP address (default: 127.0.0.1)
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function helo($host = '127.0.0.1')
{
// Respect RFC 2821 and disallow HELO attempts if session is already initiated.
if ($this->_sess === true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Cannot issue HELO to existing session');
}
// Validate client hostname
if (!$this->_validHost->isValid($host)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
}
// Initiate helo sequence
$this->_expect(220, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
$this->_ehlo($host);
// If a TLS session is required, commence negotiation
if ($this->_secure == 'tls') {
$this->_send('STARTTLS');
$this->_expect(220, 180);
if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Unable to connect via TLS');
}
$this->_ehlo($host);
}
$this->_startSession();
$this->auth();
}
/**
* Send EHLO or HELO depending on capabilities of smtp host
*
* @param string $host The client hostname or IP address (default: 127.0.0.1)
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
protected function _ehlo($host)
{
// Support for older, less-compliant remote servers. Tries multiple attempts of EHLO or HELO.
try {
$this->_send('EHLO ' . $host);
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
} catch (Zend_Mail_Protocol_Exception $e) {
$this->_send('HELO ' . $host);
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
} catch (Zend_Mail_Protocol_Exception $e) {
throw $e;
}
}
/**
* Issues MAIL command
*
* @param string $from Sender mailbox
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function mail($from)
{
if ($this->_sess !== true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('A valid session has not been started');
}
$this->_send('MAIL FROM:<' . $from . '>');
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
// Set mail to true, clear recipients and any existing data flags as per 4.1.1.2 of RFC 2821
$this->_mail = true;
$this->_rcpt = false;
$this->_data = false;
}
/**
* Issues RCPT command
*
* @param string $to Receiver(s) mailbox
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function rcpt($to)
{
if ($this->_mail !== true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No sender reverse path has been supplied');
}
// Set rcpt to true, as per 4.1.1.3 of RFC 2821
$this->_send('RCPT TO:<' . $to . '>');
$this->_expect(array(250, 251), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
$this->_rcpt = true;
}
/**
* Issues DATA command
*
* @param string $data
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function data($data)
{
// Ensure recipients have been set
if ($this->_rcpt !== true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('No recipient forward path has been supplied');
}
$this->_send('DATA');
$this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2
foreach (explode(Zend_Mime::LINEEND, $data) as $line) {
if (strpos($line, '.') === 0) {
// Escape lines prefixed with a '.'
$line = '.' . $line;
}
$this->_send($line);
}
$this->_send('.');
$this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2
$this->_data = true;
}
/**
* Issues the RSET command and validates answer
*
* Can be used to restore a clean smtp communication state when a transaction has been cancelled or commencing a new transaction.
*
* @return void
*/
public function rset()
{
$this->_send('RSET');
// MS ESMTP doesn't follow RFC, see [ZF-1377]
$this->_expect(array(250, 220));
$this->_mail = false;
$this->_rcpt = false;
$this->_data = false;
}
/**
* Issues the NOOP command and validates answer
*
* Not used by Zend_Mail, could be used to keep a connection alive or check if it is still open.
*
* @return void
*/
public function noop()
{
$this->_send('NOOP');
$this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
}
/**
* Issues the VRFY command and validates answer
*
* Not used by Zend_Mail.
*
* @param string $user User Name or eMail to verify
* @return void
*/
public function vrfy($user)
{
$this->_send('VRFY ' . $user);
$this->_expect(array(250, 251, 252), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
}
/**
* Issues the QUIT command and clears the current session
*
* @return void
*/
public function quit()
{
if ($this->_sess) {
$this->_send('QUIT');
$this->_expect(221, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
$this->_stopSession();
}
}
/**
* Default authentication method
*
* This default method is implemented by AUTH adapters to properly authenticate to a remote host.
*
* @throws Zend_Mail_Protocol_Exception
* @return void
*/
public function auth()
{
if ($this->_auth === true) {
/**
* @see Zend_Mail_Protocol_Exception
*/
require_once 'Zend/Mail/Protocol/Exception.php';
throw new Zend_Mail_Protocol_Exception('Already authenticated for this session');
}
}
/**
* Closes connection
*
* @return void
*/
public function disconnect()
{
$this->_disconnect();
}
/**
* Start mail session
*
* @return void
*/
protected function _startSession()
{
$this->_sess = true;
}
/**
* Stop mail session
*
* @return void
*/
protected function _stopSession()
{
$this->_sess = false;
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Crammd5.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* Performs CRAM-MD5 authentication
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp_Auth_Crammd5 extends Zend_Mail_Protocol_Smtp
{
/**
* Constructor.
*
* @param string $host (Default: 127.0.0.1)
* @param int $port (Default: null)
* @param array $config Auth-specific parameters
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null, $config = null)
{
if (is_array($config)) {
if (isset($config['username'])) {
$this->_username = $config['username'];
}
if (isset($config['password'])) {
$this->_password = $config['password'];
}
}
parent::__construct($host, $port, $config);
}
/**
* @todo Perform CRAM-MD5 authentication with supplied credentials
*
* @return void
*/
public function auth()
{
// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH CRAM-MD5');
$challenge = $this->_expect(334);
$challenge = base64_decode($challenge);
$digest = $this->_hmacMd5($this->_password, $challenge);
$this->_send(base64_encode($this->_username . ' ' . $digest));
$this->_expect(235);
$this->_auth = true;
}
/**
* Prepare CRAM-MD5 response to server's ticket
*
* @param string $key Challenge key (usually password)
* @param string $data Challenge data
* @param string $block Length of blocks
* @return string
*/
protected function _hmacMd5($key, $data, $block = 64)
{
if (strlen($key) > 64) {
$key = pack('H32', md5($key));
} elseif (strlen($key) < 64) {
$key = str_pad($key, $block, "\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;
}
}

View File

@ -0,0 +1,98 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Login.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* Performs LOGIN authentication
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp_Auth_Login extends Zend_Mail_Protocol_Smtp
{
/**
* LOGIN username
*
* @var string
*/
protected $_username;
/**
* LOGIN password
*
* @var string
*/
protected $_password;
/**
* Constructor.
*
* @param string $host (Default: 127.0.0.1)
* @param int $port (Default: null)
* @param array $config Auth-specific parameters
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null, $config = null)
{
if (is_array($config)) {
if (isset($config['username'])) {
$this->_username = $config['username'];
}
if (isset($config['password'])) {
$this->_password = $config['password'];
}
}
parent::__construct($host, $port, $config);
}
/**
* Perform LOGIN authentication with supplied credentials
*
* @return void
*/
public function auth()
{
// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH LOGIN');
$this->_expect(334);
$this->_send(base64_encode($this->_username));
$this->_expect(334);
$this->_send(base64_encode($this->_password));
$this->_expect(235);
$this->_auth = true;
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Plain.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* Performs PLAIN authentication
*
* @category Zend
* @package Zend_Mail
* @subpackage Protocol
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Protocol_Smtp_Auth_Plain extends Zend_Mail_Protocol_Smtp
{
/**
* PLAIN username
*
* @var string
*/
protected $_username;
/**
* PLAIN password
*
* @var string
*/
protected $_password;
/**
* Constructor.
*
* @param string $host (Default: 127.0.0.1)
* @param int $port (Default: null)
* @param array $config Auth-specific parameters
* @return void
*/
public function __construct($host = '127.0.0.1', $port = null, $config = null)
{
if (is_array($config)) {
if (isset($config['username'])) {
$this->_username = $config['username'];
}
if (isset($config['password'])) {
$this->_password = $config['password'];
}
}
parent::__construct($host, $port, $config);
}
/**
* Perform PLAIN authentication with supplied credentials
*
* @return void
*/
public function auth()
{
// Ensure AUTH has not already been initiated.
parent::auth();
$this->_send('AUTH PLAIN');
$this->_expect(334);
$this->_send(base64_encode("\0" . $this->_username . "\0" . $this->_password));
$this->_expect(235);
$this->_auth = true;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Storage.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage
{
// maildir and IMAP flags, using IMAP names, where possible to be able to distinguish between IMAP
// system flags and other flags
const FLAG_PASSED = 'Passed';
const FLAG_SEEN = '\Seen';
const FLAG_ANSWERED = '\Answered';
const FLAG_FLAGGED = '\Flagged';
const FLAG_DELETED = '\Deleted';
const FLAG_DRAFT = '\Draft';
const FLAG_RECENT = '\Recent';
}

View File

@ -0,0 +1,368 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Mail_Storage_Abstract implements Countable, ArrayAccess, SeekableIterator
{
/**
* class capabilities with default values
* @var array
*/
protected $_has = array('uniqueid' => true,
'delete' => false,
'create' => false,
'top' => false,
'fetchPart' => true,
'flags' => false);
/**
* current iteration position
* @var int
*/
protected $_iterationPos = 0;
/**
* maximum iteration position (= message count)
* @var null|int
*/
protected $_iterationMax = null;
/**
* used message class, change it in an extened class to extend the returned message class
* @var string
*/
protected $_messageClass = 'Zend_Mail_Message';
/**
* Getter for has-properties. The standard has properties
* are: hasFolder, hasUniqueid, hasDelete, hasCreate, hasTop
*
* The valid values for the has-properties are:
* - true if a feature is supported
* - false if a feature is not supported
* - null is it's not yet known or it can't be know if a feature is supported
*
* @param string $var property name
* @return bool supported or not
* @throws Zend_Mail_Storage_Exception
*/
public function __get($var)
{
if (strpos($var, 'has') === 0) {
$var = strtolower(substr($var, 3));
return isset($this->_has[$var]) ? $this->_has[$var] : null;
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception($var . ' not found');
}
/**
* Get a full list of features supported by the specific mail lib and the server
*
* @return array list of features as array(featurename => true|false[|null])
*/
public function getCapabilities()
{
return $this->_has;
}
/**
* Count messages messages in current box/folder
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
*/
abstract public function countMessages();
/**
* Get a list of messages with number and size
*
* @param int $id number of message
* @return int|array size of given message of list with all messages as array(num => size)
*/
abstract public function getSize($id = 0);
/**
* Get a message with headers and body
*
* @param int $id number of message
* @return Zend_Mail_Message
*/
abstract public function getMessage($id);
abstract public function getFullMessage($id);
/**
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
*/
abstract public function getRawHeader($id, $part = null, $topLines = 0);
/**
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
*/
abstract public function getRawContent($id, $part = null);
/**
* Create instance with parameters
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
abstract public function __construct($params);
/**
* Destructor calls close() and therefore closes the resource.
*/
public function __destruct()
{
$this->close();
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return null
*/
abstract public function close();
/**
* Keep the resource alive.
*
* @return null
*/
abstract public function noop();
/**
* delete a message from current box/folder
*
* @return null
*/
abstract public function removeMessage($id);
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
abstract public function getUniqueId($id = null);
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
abstract public function getNumberByUniqueId($id);
// interface implementations follows
/**
* Countable::count()
*
* @return int
*/
public function count()
{
return $this->countMessages();
}
/**
* ArrayAccess::offsetExists()
*
* @param int $id
* @return boolean
*/
public function offsetExists($id)
{
try {
if ($this->getMessage($id)) {
return true;
}
} catch(Zend_Mail_Storage_Exception $e) {}
return false;
}
/**
* ArrayAccess::offsetGet()
*
* @param int $id
* @return Zend_Mail_Message message object
*/
public function offsetGet($id)
{
return $this->getMessage($id);
}
/**
* ArrayAccess::offsetSet()
*
* @param id $id
* @param mixed $value
* @throws Zend_Mail_Storage_Exception
* @return void
*/
public function offsetSet($id, $value)
{
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot write mail messages via array access');
}
/**
* ArrayAccess::offsetUnset()
*
* @param int $id
* @return boolean success
*/
public function offsetUnset($id)
{
return $this->removeMessage($id);
}
/**
* Iterator::rewind()
*
* Rewind always gets the new count from the storage. Thus if you use
* the interfaces and your scripts take long you should use reset()
* from time to time.
*
* @return void
*/
public function rewind()
{
$this->_iterationMax = $this->countMessages();
$this->_iterationPos = 1;
}
/**
* Iterator::current()
*
* @return Zend_Mail_Message current message
*/
public function current()
{
return $this->getMessage($this->_iterationPos);
}
/**
* Iterator::key()
*
* @return int id of current position
*/
public function key()
{
return $this->_iterationPos;
}
/**
* Iterator::next()
*
* @return void
*/
public function next()
{
++$this->_iterationPos;
}
/**
* Iterator::valid()
*
* @return boolean
*/
public function valid()
{
if ($this->_iterationMax === null) {
$this->_iterationMax = $this->countMessages();
}
return $this->_iterationPos && $this->_iterationPos <= $this->_iterationMax;
}
/**
* SeekableIterator::seek()
*
* @param int $pos
* @return void
* @throws OutOfBoundsException
*/
public function seek($pos)
{
if ($this->_iterationMax === null) {
$this->_iterationMax = $this->countMessages();
}
if ($pos > $this->_iterationMax) {
throw new OutOfBoundsException('this position does not exist');
}
$this->_iterationPos = $pos;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Exception extends Zend_Mail_Exception
{}

View File

@ -0,0 +1,236 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Folder.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Folder implements RecursiveIterator
{
/**
* subfolders of folder array(localName => Zend_Mail_Storage_Folder folder)
* @var array
*/
protected $_folders;
/**
* local name (name of folder in parent folder)
* @var string
*/
protected $_localName;
/**
* global name (absolute name of folder)
* @var string
*/
protected $_globalName;
/**
* folder is selectable if folder is able to hold messages, else it's just a parent folder
* @var bool
*/
protected $_selectable = true;
/**
* create a new mail folder instance
*
* @param string $localName name of folder in current subdirectory
* @param string $globalName absolute name of folder
* @param bool $selectable if true folder holds messages, if false it's just a parent for subfolders
* @param array $folders init with given instances of Zend_Mail_Storage_Folder as subfolders
*/
public function __construct($localName, $globalName = '', $selectable = true, array $folders = array())
{
$this->_localName = $localName;
$this->_globalName = $globalName ? $globalName : $localName;
$this->_selectable = $selectable;
$this->_folders = $folders;
}
/**
* implements RecursiveIterator::hasChildren()
*
* @return bool current element has children
*/
public function hasChildren()
{
$current = $this->current();
return $current && $current instanceof Zend_Mail_Storage_Folder && !$current->isLeaf();
}
/**
* implements RecursiveIterator::getChildren()
*
* @return Zend_Mail_Storage_Folder same as self::current()
*/
public function getChildren()
{
return $this->current();
}
/**
* implements Iterator::valid()
*
* @return bool check if there's a current element
*/
public function valid()
{
return key($this->_folders) !== null;
}
/**
* implements Iterator::next()
*
* @return null
*/
public function next()
{
next($this->_folders);
}
/**
* implements Iterator::key()
*
* @return string key/local name of current element
*/
public function key()
{
return key($this->_folders);
}
/**
* implements Iterator::current()
*
* @return Zend_Mail_Storage_Folder current folder
*/
public function current()
{
return current($this->_folders);
}
/**
* implements Iterator::rewind()
*
* @return null
*/
public function rewind()
{
reset($this->_folders);
}
/**
* get subfolder named $name
*
* @param string $name wanted subfolder
* @return Zend_Mail_Storage_Folder folder named $folder
* @throws Zend_Mail_Storage_Exception
*/
public function __get($name)
{
if (!isset($this->_folders[$name])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("no subfolder named $name");
}
return $this->_folders[$name];
}
/**
* add or replace subfolder named $name
*
* @param string $name local name of subfolder
* @param Zend_Mail_Storage_Folder $folder instance for new subfolder
* @return null
*/
public function __set($name, Zend_Mail_Storage_Folder $folder)
{
$this->_folders[$name] = $folder;
}
/**
* remove subfolder named $name
*
* @param string $name local name of subfolder
* @return null
*/
public function __unset($name)
{
unset($this->_folders[$name]);
}
/**
* magic method for easy output of global name
*
* @return string global name of folder
*/
public function __toString()
{
return (string)$this->getGlobalName();
}
/**
* get local name
*
* @return string local name
*/
public function getLocalName()
{
return $this->_localName;
}
/**
* get global name
*
* @return string global name
*/
public function getGlobalName()
{
return $this->_globalName;
}
/**
* is this folder selectable?
*
* @return bool selectable
*/
public function isSelectable()
{
return $this->_selectable;
}
/**
* check if folder has no subfolder
*
* @return bool true if no subfolders
*/
public function isLeaf()
{
return empty($this->_folders);
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Storage_Folder_Interface
{
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
*/
public function getFolders($rootFolder = null);
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function selectFolder($globalName);
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder();
}

View File

@ -0,0 +1,265 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Maildir.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Folder
*/
require_once 'Zend/Mail/Storage/Folder.php';
/**
* @see Zend_Mail_Storage_Folder_Interface
*/
require_once 'Zend/Mail/Storage/Folder/Interface.php';
/**
* @see Zend_Mail_Storage_Maildir
*/
require_once 'Zend/Mail/Storage/Maildir.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Folder_Maildir extends Zend_Mail_Storage_Maildir implements Zend_Mail_Storage_Folder_Interface
{
/**
* Zend_Mail_Storage_Folder root folder for folder structure
* @var Zend_Mail_Storage_Folder
*/
protected $_rootFolder;
/**
* rootdir of folder structure
* @var string
*/
protected $_rootdir;
/**
* name of current folder
* @var string
*/
protected $_currentFolder;
/**
* delim char for subfolders
* @var string
*/
protected $_delim;
/**
* Create instance with parameters
* Supported parameters are:
* - dirname rootdir of maildir structure
* - delim delim char for folder structur, default is '.'
* - folder intial selected folder, default is 'INBOX'
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (!isset($params->dirname) || !is_dir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
}
$this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$this->_delim = isset($params->delim) ? $params->delim : '.';
$this->_buildFolderTree();
$this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX');
$this->_has['top'] = true;
$this->_has['flags'] = true;
}
/**
* find all subfolders and mbox files for folder structure
*
* Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder.
* $parentFolder and $parentGlobalName are only used internally for recursion.
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _buildFolderTree()
{
$this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false);
$this->_rootFolder->INBOX = new Zend_Mail_Storage_Folder('INBOX', 'INBOX', true);
$dh = @opendir($this->_rootdir);
if (!$dh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("can't read folders in maildir");
}
$dirs = array();
while (($entry = readdir($dh)) !== false) {
// maildir++ defines folders must start with .
if ($entry[0] != '.' || $entry == '.' || $entry == '..') {
continue;
}
if ($this->_isMaildir($this->_rootdir . $entry)) {
$dirs[] = $entry;
}
}
closedir($dh);
sort($dirs);
$stack = array(null);
$folderStack = array(null);
$parentFolder = $this->_rootFolder;
$parent = '.';
foreach ($dirs as $dir) {
do {
if (strpos($dir, $parent) === 0) {
$local = substr($dir, strlen($parent));
if (strpos($local, $this->_delim) !== false) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while reading maildir');
}
array_push($stack, $parent);
$parent = $dir . $this->_delim;
$folder = new Zend_Mail_Storage_Folder($local, substr($dir, 1), true);
$parentFolder->$local = $folder;
array_push($folderStack, $parentFolder);
$parentFolder = $folder;
break;
} else if ($stack) {
$parent = array_pop($stack);
$parentFolder = array_pop($folderStack);
}
} while ($stack);
if (!$stack) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while reading maildir');
}
}
}
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
* @throws Zend_Mail_Storage_Exception
*/
public function getFolders($rootFolder = null)
{
if (!$rootFolder || $rootFolder == 'INBOX') {
return $this->_rootFolder;
}
// rootdir is same as INBOX in maildir
if (strpos($rootFolder, 'INBOX' . $this->_delim) === 0) {
$rootFolder = substr($rootFolder, 6);
}
$currentFolder = $this->_rootFolder;
$subname = trim($rootFolder, $this->_delim);
while ($currentFolder) {
@list($entry, $subname) = @explode($this->_delim, $subname, 2);
$currentFolder = $currentFolder->$entry;
if (!$subname) {
break;
}
}
if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->_delim)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("folder $rootFolder not found");
}
return $currentFolder;
}
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function selectFolder($globalName)
{
$this->_currentFolder = (string)$globalName;
// getting folder from folder tree for validation
$folder = $this->getFolders($this->_currentFolder);
try {
$this->_openMaildir($this->_rootdir . '.' . $folder->getGlobalName());
} catch(Zend_Mail_Storage_Exception $e) {
// check what went wrong
if (!$folder->isSelectable()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable", 0, $e);
}
// seems like file has vanished; rebuilding folder tree - but it's still an exception
$this->_buildFolderTree($this->_rootdir);
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('seems like the maildir has vanished, I\'ve rebuild the ' .
'folder tree, search for an other folder and try again', 0, $e);
}
}
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder()
{
return $this->_currentFolder;
}
}

View File

@ -0,0 +1,264 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mbox.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Folder
*/
require_once 'Zend/Mail/Storage/Folder.php';
/**
* @see Zend_Mail_Storage_Folder_Interface
*/
require_once 'Zend/Mail/Storage/Folder/Interface.php';
/**
* @see Zend_Mail_Storage_Mbox
*/
require_once 'Zend/Mail/Storage/Mbox.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Folder_Mbox extends Zend_Mail_Storage_Mbox implements Zend_Mail_Storage_Folder_Interface
{
/**
* Zend_Mail_Storage_Folder root folder for folder structure
* @var Zend_Mail_Storage_Folder
*/
protected $_rootFolder;
/**
* rootdir of folder structure
* @var string
*/
protected $_rootdir;
/**
* name of current folder
* @var string
*/
protected $_currentFolder;
/**
* Create instance with parameters
*
* Disallowed parameters are:
* - filename use Zend_Mail_Storage_Mbox for a single file
* Supported parameters are:
* - dirname rootdir of mbox structure
* - folder intial selected folder, default is 'INBOX'
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (isset($params->filename)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('use Zend_Mail_Storage_Mbox for a single file');
}
if (!isset($params->dirname) || !is_dir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
}
$this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$this->_buildFolderTree($this->_rootdir);
$this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX');
$this->_has['top'] = true;
$this->_has['uniqueid'] = false;
}
/**
* find all subfolders and mbox files for folder structure
*
* Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder.
* $parentFolder and $parentGlobalName are only used internally for recursion.
*
* @param string $currentDir call with root dir, also used for recursion.
* @param Zend_Mail_Storage_Folder|null $parentFolder used for recursion
* @param string $parentGlobalName used for rescursion
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _buildFolderTree($currentDir, $parentFolder = null, $parentGlobalName = '')
{
if (!$parentFolder) {
$this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false);
$parentFolder = $this->_rootFolder;
}
$dh = @opendir($currentDir);
if (!$dh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("can't read dir $currentDir");
}
while (($entry = readdir($dh)) !== false) {
// ignore hidden files for mbox
if ($entry[0] == '.') {
continue;
}
$absoluteEntry = $currentDir . $entry;
$globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
if (is_file($absoluteEntry) && $this->_isMboxFile($absoluteEntry)) {
$parentFolder->$entry = new Zend_Mail_Storage_Folder($entry, $globalName);
continue;
}
if (!is_dir($absoluteEntry) /* || $entry == '.' || $entry == '..' */) {
continue;
}
$folder = new Zend_Mail_Storage_Folder($entry, $globalName, false);
$parentFolder->$entry = $folder;
$this->_buildFolderTree($absoluteEntry . DIRECTORY_SEPARATOR, $folder, $globalName);
}
closedir($dh);
}
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
* @throws Zend_Mail_Storage_Exception
*/
public function getFolders($rootFolder = null)
{
if (!$rootFolder) {
return $this->_rootFolder;
}
$currentFolder = $this->_rootFolder;
$subname = trim($rootFolder, DIRECTORY_SEPARATOR);
while ($currentFolder) {
@list($entry, $subname) = @explode(DIRECTORY_SEPARATOR, $subname, 2);
$currentFolder = $currentFolder->$entry;
if (!$subname) {
break;
}
}
if ($currentFolder->getGlobalName() != DIRECTORY_SEPARATOR . trim($rootFolder, DIRECTORY_SEPARATOR)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("folder $rootFolder not found");
}
return $currentFolder;
}
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function selectFolder($globalName)
{
$this->_currentFolder = (string)$globalName;
// getting folder from folder tree for validation
$folder = $this->getFolders($this->_currentFolder);
try {
$this->_openMboxFile($this->_rootdir . $folder->getGlobalName());
} catch(Zend_Mail_Storage_Exception $e) {
// check what went wrong
if (!$folder->isSelectable()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable", 0, $e);
}
// seems like file has vanished; rebuilding folder tree - but it's still an exception
$this->_buildFolderTree($this->_rootdir);
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('seems like the mbox file has vanished, I\'ve rebuild the ' .
'folder tree, search for an other folder and try again', 0, $e);
}
}
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder()
{
return $this->_currentFolder;
}
/**
* magic method for serialize()
*
* with this method you can cache the mbox class
*
* @return array name of variables
*/
public function __sleep()
{
return array_merge(parent::__sleep(), array('_currentFolder', '_rootFolder', '_rootdir'));
}
/**
* magic method for unserialize()
*
* with this method you can cache the mbox class
*
* @return null
*/
public function __wakeup()
{
// if cache is stall selectFolder() rebuilds the tree on error
parent::__wakeup();
}
}

View File

@ -0,0 +1,657 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Imap.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Protocol_Imap
*/
require_once 'Zend/Mail/Protocol/Imap.php';
/**
* @see Zend_Mail_Storage_Writable_Interface
*/
require_once 'Zend/Mail/Storage/Writable/Interface.php';
/**
* @see Zend_Mail_Storage_Folder_Interface
*/
require_once 'Zend/Mail/Storage/Folder/Interface.php';
/**
* @see Zend_Mail_Storage_Folder
*/
require_once 'Zend/Mail/Storage/Folder.php';
/**
* @see Zend_Mail_Message
*/
require_once 'Zend/Mail/Message.php';
/**
* @see Zend_Mail_Storage
*/
require_once 'Zend/Mail/Storage.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Imap extends Zend_Mail_Storage_Abstract
implements Zend_Mail_Storage_Folder_Interface, Zend_Mail_Storage_Writable_Interface
{
// TODO: with an internal cache we could optimize this class, or create an extra class with
// such optimizations. Especially the various fetch calls could be combined to one cache call
/**
* protocol handler
* @var null|Zend_Mail_Protocol_Imap
*/
protected $_protocol;
/**
* name of current folder
* @var string
*/
protected $_currentFolder = '';
/**
* imap flags to constants translation
* @var array
*/
protected static $_knownFlags = array('\Passed' => Zend_Mail_Storage::FLAG_PASSED,
'\Answered' => Zend_Mail_Storage::FLAG_ANSWERED,
'\Seen' => Zend_Mail_Storage::FLAG_SEEN,
'\Deleted' => Zend_Mail_Storage::FLAG_DELETED,
'\Draft' => Zend_Mail_Storage::FLAG_DRAFT,
'\Flagged' => Zend_Mail_Storage::FLAG_FLAGGED);
/**
* map flags to search criterias
* @var array
*/
protected static $_searchFlags = array('\Recent' => 'RECENT',
'\Answered' => 'ANSWERED',
'\Seen' => 'SEEN',
'\Deleted' => 'DELETED',
'\Draft' => 'DRAFT',
'\Flagged' => 'FLAGGED');
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function countMessages($flags = null)
{
if (!$this->_currentFolder) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('No selected folder to count');
}
if ($flags === null) {
return count($this->_protocol->search(array('ALL')));
}
$params = array();
foreach ((array)$flags as $flag) {
if (isset(self::$_searchFlags[$flag])) {
$params[] = self::$_searchFlags[$flag];
} else {
$params[] = 'KEYWORD';
$params[] = $this->_protocol->escapeString($flag);
}
}
return count($this->_protocol->search($params));
}
/**
* get a list of messages with number and size
*
* @param int $id number of message
* @return int|array size of given message of list with all messages as array(num => size)
* @throws Zend_Mail_Protocol_Exception
*/
public function getSize($id = 0)
{
if ($id) {
return $this->_protocol->fetch('RFC822.SIZE', $id);
}
return $this->_protocol->fetch('RFC822.SIZE', 1, INF);
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message
* @throws Zend_Mail_Protocol_Exception
*/
public function getMessage($id)
{
$data = $this->_protocol->fetch(array('FLAGS', 'RFC822.HEADER'), $id);
$header = $data['RFC822.HEADER'];
$flags = array();
foreach ($data['FLAGS'] as $flag) {
$flags[] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
}
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
// TODO: toplines
return $this->_protocol->fetch('RFC822.HEADER', $id);
}
public function getFullMessage($id)
{
$data = $this->_protocol->fetch(array('RFC822.HEADER', 'RFC822.TEXT'), $id);
return $data['RFC822.HEADER'] . "\n\n" . $data['RFC822.TEXT'];
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
return $this->_protocol->fetch('RFC822.TEXT', $id);
}
public function piler_batch_fetch($from, $to) {
return $this->_protocol->fetch(array('RFC822.HEADER', 'RFC822.TEXT'), $from, $to);
}
/**
* create instance with parameters
* Supported paramters are
* - user username
* - host hostname or ip address of IMAP server [optional, default = 'localhost']
* - password password for user 'username' [optional, default = '']
* - port port for IMAP server [optional, default = 110]
* - ssl 'SSL' or 'TLS' for secure sockets
* - folder select this folder [optional, default = 'INBOX']
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
$this->_has['flags'] = true;
if ($params instanceof Zend_Mail_Protocol_Imap) {
$this->_protocol = $params;
try {
$this->selectFolder('INBOX');
} catch(Zend_Mail_Storage_Exception $e) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot select INBOX, is this a valid transport?', 0, $e);
}
return;
}
if (!isset($params->user)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('need at least user in params');
}
$host = isset($params->host) ? $params->host : 'localhost';
$password = isset($params->password) ? $params->password : '';
$port = isset($params->port) ? $params->port : null;
$ssl = isset($params->ssl) ? $params->ssl : false;
$this->_protocol = new Zend_Mail_Protocol_Imap();
$this->_protocol->connect($host, $port, $ssl);
if (!$this->_protocol->login($params->user, $password)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot login, user or password wrong');
}
$this->selectFolder(isset($params->folder) ? $params->folder : 'INBOX');
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return null
*/
public function close()
{
$this->_currentFolder = '';
$this->_protocol->logout();
}
/**
* Keep the server busy.
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function noop()
{
if (!$this->_protocol->noop()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('could not do nothing');
}
}
/**
* Remove a message from server. If you're doing that from a web enviroment
* you should be careful and use a uniqueid as parameter if possible to
* identify the message.
*
* @param int $id number of message
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeMessage($id)
{
if (!$this->_protocol->store(array(Zend_Mail_Storage::FLAG_DELETED), $id, null, '+')) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot set deleted flag');
}
// TODO: expunge here or at close? we can handle an error here better and are more fail safe
if (!$this->_protocol->expunge()) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('message marked as deleted, but could not expunge');
}
}
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if ($id) {
return $this->_protocol->fetch('UID', $id);
}
return $this->_protocol->fetch('UID', 1, INF);
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
// TODO: use search to find number directly
$ids = $this->getUniqueId();
foreach ($ids as $k => $v) {
if ($v == $id) {
return $k;
}
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unique id not found');
}
/**
* get root folder or given folder
*
* @param string $rootFolder get folder structure for given folder, else root
* @return Zend_Mail_Storage_Folder root or wanted folder
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function getFolders($rootFolder = null)
{
$folders = $this->_protocol->listMailbox((string)$rootFolder);
if (!$folders) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('folder not found');
}
ksort($folders, SORT_STRING);
$root = new Zend_Mail_Storage_Folder('/', '/', false);
$stack = array(null);
$folderStack = array(null);
$parentFolder = $root;
$parent = '';
foreach ($folders as $globalName => $data) {
do {
if (!$parent || strpos($globalName, $parent) === 0) {
$pos = strrpos($globalName, $data['delim']);
if ($pos === false) {
$localName = $globalName;
} else {
$localName = substr($globalName, $pos + 1);
}
$selectable = !$data['flags'] || !in_array('\\Noselect', $data['flags']);
array_push($stack, $parent);
$parent = $globalName . $data['delim'];
$folder = new Zend_Mail_Storage_Folder($localName, $globalName, $selectable);
$parentFolder->$localName = $folder;
array_push($folderStack, $parentFolder);
$parentFolder = $folder;
break;
} else if ($stack) {
$parent = array_pop($stack);
$parentFolder = array_pop($folderStack);
}
} while ($stack);
if (!$stack) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('error while constructing folder tree');
}
}
return $root;
}
/**
* select given folder
*
* folder must be selectable!
*
* @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
* @return null
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function selectFolder($globalName)
{
$this->_currentFolder = $globalName;
if (!$this->_protocol->select($this->_currentFolder)) {
$this->_currentFolder = '';
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot change folder, maybe it does not exist');
}
}
/**
* get Zend_Mail_Storage_Folder instance for current folder
*
* @return Zend_Mail_Storage_Folder instance of current folder
* @throws Zend_Mail_Storage_Exception
*/
public function getCurrentFolder()
{
return $this->_currentFolder;
}
/**
* create a new folder
*
* This method also creates parent folders if necessary. Some mail storages may restrict, which folder
* may be used as parent or which chars may be used in the folder name
*
* @param string $name global name of folder, local name if $parentFolder is set
* @param string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function createFolder($name, $parentFolder = null)
{
// TODO: we assume / as the hierarchy delim - need to get that from the folder class!
if ($parentFolder instanceof Zend_Mail_Storage_Folder) {
$folder = $parentFolder->getGlobalName() . '/' . $name;
} else if ($parentFolder != null) {
$folder = $parentFolder . '/' . $name;
} else {
$folder = $name;
}
if (!$this->_protocol->create($folder)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot create folder');
}
}
/**
* remove a folder
*
* @param string|Zend_Mail_Storage_Folder $name name or instance of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeFolder($name)
{
if ($name instanceof Zend_Mail_Storage_Folder) {
$name = $name->getGlobalName();
}
if (!$this->_protocol->delete($name)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot delete folder');
}
}
/**
* rename and/or move folder
*
* The new name has the same restrictions as in createFolder()
*
* @param string|Zend_Mail_Storage_Folder $oldName name or instance of folder
* @param string $newName new global name of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function renameFolder($oldName, $newName)
{
if ($oldName instanceof Zend_Mail_Storage_Folder) {
$oldName = $oldName->getGlobalName();
}
if (!$this->_protocol->rename($oldName, $newName)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot rename folder');
}
}
/**
* append a new message to mail storage
*
* @param string $message message as string or instance of message class
* @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken
* @param null|array $flags set flags for new message, else a default set is used
* @throws Zend_Mail_Storage_Exception
*/
// not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
public function appendMessage($message, $folder = null, $flags = null)
{
if ($folder === null) {
$folder = $this->_currentFolder;
}
if ($flags === null) {
$flags = array(Zend_Mail_Storage::FLAG_SEEN);
}
// TODO: handle class instances for $message
if (!$this->_protocol->append($folder, $message, $flags)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot create message, please check if the folder exists and your flags');
}
}
/**
* copy an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function copyMessage($id, $folder)
{
if (!$this->_protocol->copy($folder, $id)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot copy message, does the folder exist?');
}
}
/**
* move an existing message
*
* NOTE: imap has no native move command, thus it's emulated with copy and delete
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function moveMessage($id, $folder) {
$this->copyMessage($id, $folder);
$this->removeMessage($id);
}
/**
* set flags for message
*
* NOTE: this method can't set the recent flag.
*
* @param int $id number of message
* @param array $flags new flags for message
* @throws Zend_Mail_Storage_Exception
*/
public function setFlags($id, $flags)
{
if (!$this->_protocol->store($flags, $id)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot set flags, have you tried to set the recent flag or special chars?');
}
}
}

View File

@ -0,0 +1,475 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Maildir.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Message_File
*/
require_once 'Zend/Mail/Message/File.php';
/**
* @see Zend_Mail_Storage
*/
require_once 'Zend/Mail/Storage.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Maildir extends Zend_Mail_Storage_Abstract
{
/**
* used message class, change it in an extened class to extend the returned message class
* @var string
*/
protected $_messageClass = 'Zend_Mail_Message_File';
/**
* data of found message files in maildir dir
* @var array
*/
protected $_files = array();
/**
* known flag chars in filenames
*
* This list has to be in alphabetical order for setFlags()
*
* @var array
*/
protected static $_knownFlags = array('D' => Zend_Mail_Storage::FLAG_DRAFT,
'F' => Zend_Mail_Storage::FLAG_FLAGGED,
'P' => Zend_Mail_Storage::FLAG_PASSED,
'R' => Zend_Mail_Storage::FLAG_ANSWERED,
'S' => Zend_Mail_Storage::FLAG_SEEN,
'T' => Zend_Mail_Storage::FLAG_DELETED);
// TODO: getFlags($id) for fast access if headers are not needed (i.e. just setting flags)?
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
*/
public function countMessages($flags = null)
{
if ($flags === null) {
return count($this->_files);
}
$count = 0;
if (!is_array($flags)) {
foreach ($this->_files as $file) {
if (isset($file['flaglookup'][$flags])) {
++$count;
}
}
return $count;
}
$flags = array_flip($flags);
foreach ($this->_files as $file) {
foreach ($flags as $flag => $v) {
if (!isset($file['flaglookup'][$flag])) {
continue 2;
}
}
++$count;
}
return $count;
}
/**
* Get one or all fields from file structure. Also checks if message is valid
*
* @param int $id message number
* @param string|null $field wanted field
* @return string|array wanted field or all fields as array
* @throws Zend_Mail_Storage_Exception
*/
protected function _getFileData($id, $field = null)
{
if (!isset($this->_files[$id - 1])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('id does not exist');
}
if (!$field) {
return $this->_files[$id - 1];
}
if (!isset($this->_files[$id - 1][$field])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('field does not exist');
}
return $this->_files[$id - 1][$field];
}
/**
* Get a list of messages with number and size
*
* @param int|null $id number of message or null for all messages
* @return int|array size of given message of list with all messages as array(num => size)
* @throws Zend_Mail_Storage_Exception
*/
public function getSize($id = null)
{
if ($id !== null) {
$filedata = $this->_getFileData($id);
return isset($filedata['size']) ? $filedata['size'] : filesize($filedata['filename']);
}
$result = array();
foreach ($this->_files as $num => $data) {
$result[$num + 1] = isset($data['size']) ? $data['size'] : filesize($data['filename']);
}
return $result;
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message_File
* @throws Zend_Mail_Storage_Exception
*/
public function getMessage($id)
{
// TODO that's ugly, would be better to let the message class decide
if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
return new $this->_messageClass(array('file' => $this->_getFileData($id, 'filename'),
'flags' => $this->_getFileData($id, 'flags')));
}
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $this->getRawHeader($id),
'flags' => $this->_getFileData($id, 'flags')));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$fh = fopen($this->_getFileData($id, 'filename'), 'r');
$content = '';
while (!feof($fh)) {
$line = fgets($fh);
if (!trim($line)) {
break;
}
$content .= $line;
}
fclose($fh);
return $content;
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$fh = fopen($this->_getFileData($id, 'filename'), 'r');
while (!feof($fh)) {
$line = fgets($fh);
if (!trim($line)) {
break;
}
}
$content = stream_get_contents($fh);
fclose($fh);
return $content;
}
/**
* Create instance with parameters
* Supported parameters are:
* - dirname dirname of mbox file
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (!isset($params->dirname) || !is_dir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
}
if (!$this->_isMaildir($params->dirname)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('invalid maildir given');
}
$this->_has['top'] = true;
$this->_has['flags'] = true;
$this->_openMaildir($params->dirname);
}
/**
* check if a given dir is a valid maildir
*
* @param string $dirname name of dir
* @return bool dir is valid maildir
*/
protected function _isMaildir($dirname)
{
if (file_exists($dirname . '/new') && !is_dir($dirname . '/new')) {
return false;
}
if (file_exists($dirname . '/tmp') && !is_dir($dirname . '/tmp')) {
return false;
}
return is_dir($dirname . '/cur');
}
/**
* open given dir as current maildir
*
* @param string $dirname name of maildir
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _openMaildir($dirname)
{
if ($this->_files) {
$this->close();
}
$dh = @opendir($dirname . '/cur/');
if (!$dh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot open maildir');
}
$this->_getMaildirFiles($dh, $dirname . '/cur/');
closedir($dh);
$dh = @opendir($dirname . '/new/');
if ($dh) {
$this->_getMaildirFiles($dh, $dirname . '/new/', array(Zend_Mail_Storage::FLAG_RECENT));
closedir($dh);
} else if (file_exists($dirname . '/new/')) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot read recent mails in maildir');
}
}
/**
* find all files in opened dir handle and add to maildir files
*
* @param resource $dh dir handle used for search
* @param string $dirname dirname of dir in $dh
* @param array $default_flags default flags for given dir
* @return null
*/
protected function _getMaildirFiles($dh, $dirname, $default_flags = array())
{
while (($entry = readdir($dh)) !== false) {
if ($entry[0] == '.' || !is_file($dirname . $entry)) {
continue;
}
@list($uniq, $info) = explode(':', $entry, 2);
@list(,$size) = explode(',', $uniq, 2);
if ($size && $size[0] == 'S' && $size[1] == '=') {
$size = substr($size, 2);
}
if (!ctype_digit($size)) {
$size = null;
}
@list($version, $flags) = explode(',', $info, 2);
if ($version != 2) {
$flags = '';
}
$named_flags = $default_flags;
$length = strlen($flags);
for ($i = 0; $i < $length; ++$i) {
$flag = $flags[$i];
$named_flags[$flag] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
}
$data = array('uniq' => $uniq,
'flags' => $named_flags,
'flaglookup' => array_flip($named_flags),
'filename' => $dirname . $entry);
if ($size !== null) {
$data['size'] = (int)$size;
}
$this->_files[] = $data;
}
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return void
*/
public function close()
{
$this->_files = array();
}
/**
* Waste some CPU cycles doing nothing.
*
* @return void
*/
public function noop()
{
return true;
}
/**
* stub for not supported message deletion
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeMessage($id)
{
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('maildir is (currently) read-only');
}
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if ($id) {
return $this->_getFileData($id, 'uniq');
}
$ids = array();
foreach ($this->_files as $num => $file) {
$ids[$num + 1] = $file['uniq'];
}
return $ids;
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
foreach ($this->_files as $num => $file) {
if ($file['uniq'] == $id) {
return $num + 1;
}
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unique id not found');
}
}

View File

@ -0,0 +1,447 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mbox.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Loader
* May be used in constructor, but commented out for now
*/
// require_once 'Zend/Loader.php';
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Message_File
*/
require_once 'Zend/Mail/Message/File.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Mbox extends Zend_Mail_Storage_Abstract
{
/**
* file handle to mbox file
* @var null|resource
*/
protected $_fh;
/**
* filename of mbox file for __wakeup
* @var string
*/
protected $_filename;
/**
* modification date of mbox file for __wakeup
* @var int
*/
protected $_filemtime;
/**
* start and end position of messages as array('start' => start, 'seperator' => headersep, 'end' => end)
* @var array
*/
protected $_positions;
/**
* used message class, change it in an extened class to extend the returned message class
* @var string
*/
protected $_messageClass = 'Zend_Mail_Message_File';
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
*/
public function countMessages()
{
return count($this->_positions);
}
/**
* Get a list of messages with number and size
*
* @param int|null $id number of message or null for all messages
* @return int|array size of given message of list with all messages as array(num => size)
*/
public function getSize($id = 0)
{
if ($id) {
$pos = $this->_positions[$id - 1];
return $pos['end'] - $pos['start'];
}
$result = array();
foreach ($this->_positions as $num => $pos) {
$result[$num + 1] = $pos['end'] - $pos['start'];
}
return $result;
}
/**
* Get positions for mail message or throw exeption if id is invalid
*
* @param int $id number of message
* @return array positions as in _positions
* @throws Zend_Mail_Storage_Exception
*/
protected function _getPos($id)
{
if (!isset($this->_positions[$id - 1])) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('id does not exist');
}
return $this->_positions[$id - 1];
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message_File
* @throws Zend_Mail_Storage_Exception
*/
public function getMessage($id)
{
// TODO that's ugly, would be better to let the message class decide
if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
// TODO top/body lines
$messagePos = $this->_getPos($id);
return new $this->_messageClass(array('file' => $this->_fh, 'startPos' => $messagePos['start'],
'endPos' => $messagePos['end']));
}
$bodyLines = 0; // TODO: need a way to change that
$message = $this->getRawHeader($id);
// file pointer is after headers now
if ($bodyLines) {
$message .= "\n";
while ($bodyLines-- && ftell($this->_fh) < $this->_positions[$id - 1]['end']) {
$message .= fgets($this->_fh);
}
}
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $message));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$messagePos = $this->_getPos($id);
// TODO: toplines
return stream_get_contents($this->_fh, $messagePos['separator'] - $messagePos['start'], $messagePos['start']);
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$messagePos = $this->_getPos($id);
return stream_get_contents($this->_fh, $messagePos['end'] - $messagePos['separator'], $messagePos['separator']);
}
/**
* Create instance with parameters
* Supported parameters are:
* - filename filename of mbox file
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
if (!isset($params->filename) /* || Zend_Loader::isReadable($params['filename']) */) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('no valid filename given in params');
}
$this->_openMboxFile($params->filename);
$this->_has['top'] = true;
$this->_has['uniqueid'] = false;
}
/**
* check if given file is a mbox file
*
* if $file is a resource its file pointer is moved after the first line
*
* @param resource|string $file stream resource of name of file
* @param bool $fileIsString file is string or resource
* @return bool file is mbox file
*/
protected function _isMboxFile($file, $fileIsString = true)
{
if ($fileIsString) {
$file = @fopen($file, 'r');
if (!$file) {
return false;
}
} else {
fseek($file, 0);
}
$result = false;
$line = fgets($file);
if (strpos($line, 'From ') === 0) {
$result = true;
}
if ($fileIsString) {
@fclose($file);
}
return $result;
}
/**
* open given file as current mbox file
*
* @param string $filename filename of mbox file
* @return null
* @throws Zend_Mail_Storage_Exception
*/
protected function _openMboxFile($filename)
{
if ($this->_fh) {
$this->close();
}
$this->_fh = @fopen($filename, 'r');
if (!$this->_fh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot open mbox file');
}
$this->_filename = $filename;
$this->_filemtime = filemtime($this->_filename);
if (!$this->_isMboxFile($this->_fh, false)) {
@fclose($this->_fh);
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('file is not a valid mbox format');
}
$messagePos = array('start' => ftell($this->_fh), 'separator' => 0, 'end' => 0);
while (($line = fgets($this->_fh)) !== false) {
if (strpos($line, 'From ') === 0) {
$messagePos['end'] = ftell($this->_fh) - strlen($line) - 2; // + newline
if (!$messagePos['separator']) {
$messagePos['separator'] = $messagePos['end'];
}
$this->_positions[] = $messagePos;
$messagePos = array('start' => ftell($this->_fh), 'separator' => 0, 'end' => 0);
}
if (!$messagePos['separator'] && !trim($line)) {
$messagePos['separator'] = ftell($this->_fh);
}
}
$messagePos['end'] = ftell($this->_fh);
if (!$messagePos['separator']) {
$messagePos['separator'] = $messagePos['end'];
}
$this->_positions[] = $messagePos;
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return void
*/
public function close()
{
@fclose($this->_fh);
$this->_positions = array();
}
/**
* Waste some CPU cycles doing nothing.
*
* @return void
*/
public function noop()
{
return true;
}
/**
* stub for not supported message deletion
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeMessage($id)
{
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('mbox is read-only');
}
/**
* get unique id for one or all messages
*
* Mbox does not support unique ids (yet) - it's always the same as the message number.
* That shouldn't be a problem, because we can't change mbox files. Therefor the message
* number is save enough.
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if ($id) {
// check if id exists
$this->_getPos($id);
return $id;
}
$range = range(1, $this->countMessages());
return array_combine($range, $range);
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
// check if id exists
$this->_getPos($id);
return $id;
}
/**
* magic method for serialize()
*
* with this method you can cache the mbox class
*
* @return array name of variables
*/
public function __sleep()
{
return array('_filename', '_positions', '_filemtime');
}
/**
* magic method for unserialize()
*
* with this method you can cache the mbox class
* for cache validation the mtime of the mbox file is used
*
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function __wakeup()
{
if ($this->_filemtime != @filemtime($this->_filename)) {
$this->close();
$this->_openMboxFile($this->_filename);
} else {
$this->_fh = @fopen($this->_filename, 'r');
if (!$this->_fh) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('cannot open mbox file');
}
}
}
}

View File

@ -0,0 +1,328 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Pop3.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Storage_Abstract
*/
require_once 'Zend/Mail/Storage/Abstract.php';
/**
* @see Zend_Mail_Protocol_Pop3
*/
require_once 'Zend/Mail/Protocol/Pop3.php';
/**
* @see Zend_Mail_Message
*/
require_once 'Zend/Mail/Message.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Storage_Pop3 extends Zend_Mail_Storage_Abstract
{
/**
* protocol handler
* @var null|Zend_Mail_Protocol_Pop3
*/
protected $_protocol;
/**
* Count messages all messages in current box
*
* @return int number of messages
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function countMessages()
{
$this->_protocol->status($count, $null);
return (int)$count;
}
/**
* get a list of messages with number and size
*
* @param int $id number of message
* @return int|array size of given message of list with all messages as array(num => size)
* @throws Zend_Mail_Protocol_Exception
*/
public function getSize($id = 0)
{
$id = $id ? $id : null;
return $this->_protocol->getList($id);
}
/**
* Fetch a message
*
* @param int $id number of message
* @return Zend_Mail_Message
* @throws Zend_Mail_Protocol_Exception
*/
public function getMessage($id)
{
$bodyLines = 0;
$message = $this->_protocol->top($id, $bodyLines, true);
return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $message,
'noToplines' => $bodyLines < 1));
}
/*
* Get raw header of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage header
* @param int $topLines include this many lines with header (after an empty line)
* @return string raw header
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawHeader($id, $part = null, $topLines = 0)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
return $this->_protocol->top($id, 0, true);
}
/*
* Get raw content of message or part
*
* @param int $id number of message
* @param null|array|string $part path to part or null for messsage content
* @return string raw content
* @throws Zend_Mail_Protocol_Exception
* @throws Zend_Mail_Storage_Exception
*/
public function getRawContent($id, $part = null)
{
if ($part !== null) {
// TODO: implement
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('not implemented');
}
$content = $this->_protocol->retrieve($id);
// TODO: find a way to avoid decoding the headers
Zend_Mime_Decode::splitMessage($content, $null, $body);
return $body;
}
/**
* create instance with parameters
* Supported paramters are
* - host hostname or ip address of POP3 server
* - user username
* - password password for user 'username' [optional, default = '']
* - port port for POP3 server [optional, default = 110]
* - ssl 'SSL' or 'TLS' for secure sockets
*
* @param array $params mail reader specific parameters
* @throws Zend_Mail_Storage_Exception
* @throws Zend_Mail_Protocol_Exception
*/
public function __construct($params)
{
if (is_array($params)) {
$params = (object)$params;
}
$this->_has['fetchPart'] = false;
$this->_has['top'] = null;
$this->_has['uniqueid'] = null;
if ($params instanceof Zend_Mail_Protocol_Pop3) {
$this->_protocol = $params;
return;
}
if (!isset($params->user)) {
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('need at least user in params');
}
$host = isset($params->host) ? $params->host : 'localhost';
$password = isset($params->password) ? $params->password : '';
$port = isset($params->port) ? $params->port : null;
$ssl = isset($params->ssl) ? $params->ssl : false;
$this->_protocol = new Zend_Mail_Protocol_Pop3();
$this->_protocol->connect($host, $port, $ssl);
$this->_protocol->login($params->user, $password);
}
/**
* Close resource for mail lib. If you need to control, when the resource
* is closed. Otherwise the destructor would call this.
*
* @return null
*/
public function close()
{
$this->_protocol->logout();
}
/**
* Keep the server busy.
*
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function noop()
{
return $this->_protocol->noop();
}
/**
* Remove a message from server. If you're doing that from a web enviroment
* you should be careful and use a uniqueid as parameter if possible to
* identify the message.
*
* @param int $id number of message
* @return null
* @throws Zend_Mail_Protocol_Exception
*/
public function removeMessage($id)
{
$this->_protocol->delete($id);
}
/**
* get unique id for one or all messages
*
* if storage does not support unique ids it's the same as the message number
*
* @param int|null $id message number
* @return array|string message number for given message or all messages as array
* @throws Zend_Mail_Storage_Exception
*/
public function getUniqueId($id = null)
{
if (!$this->hasUniqueid) {
if ($id) {
return $id;
}
$count = $this->countMessages();
if ($count < 1) {
return array();
}
$range = range(1, $count);
return array_combine($range, $range);
}
return $this->_protocol->uniqueid($id);
}
/**
* get a message number from a unique id
*
* I.e. if you have a webmailer that supports deleting messages you should use unique ids
* as parameter and use this method to translate it to message number right before calling removeMessage()
*
* @param string $id unique id
* @return int message number
* @throws Zend_Mail_Storage_Exception
*/
public function getNumberByUniqueId($id)
{
if (!$this->hasUniqueid) {
return $id;
}
$ids = $this->getUniqueId();
foreach ($ids as $k => $v) {
if ($v == $id) {
return $k;
}
}
/**
* @see Zend_Mail_Storage_Exception
*/
require_once 'Zend/Mail/Storage/Exception.php';
throw new Zend_Mail_Storage_Exception('unique id not found');
}
/**
* Special handling for hasTop and hasUniqueid. The headers of the first message is
* retrieved if Top wasn't needed/tried yet.
*
* @see Zend_Mail_Storage_Abstract:__get()
* @param string $var
* @return string
* @throws Zend_Mail_Storage_Exception
*/
public function __get($var)
{
$result = parent::__get($var);
if ($result !== null) {
return $result;
}
if (strtolower($var) == 'hastop') {
if ($this->_protocol->hasTop === null) {
// need to make a real call, because not all server are honest in their capas
try {
$this->_protocol->top(1, 0, false);
} catch(Zend_Mail_Exception $e) {
// ignoring error
}
}
$this->_has['top'] = $this->_protocol->hasTop;
return $this->_protocol->hasTop;
}
if (strtolower($var) == 'hasuniqueid') {
$id = null;
try {
$id = $this->_protocol->uniqueid(1);
} catch(Zend_Mail_Exception $e) {
// ignoring error
}
$this->_has['uniqueid'] = $id ? true : false;
return $this->_has['uniqueid'];
}
return $result;
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @category Zend
* @package Zend_Mail
* @subpackage Storage
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Mail_Storage_Writable_Interface
{
/**
* create a new folder
*
* This method also creates parent folders if necessary. Some mail storages may restrict, which folder
* may be used as parent or which chars may be used in the folder name
*
* @param string $name global name of folder, local name if $parentFolder is set
* @param string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function createFolder($name, $parentFolder = null);
/**
* remove a folder
*
* @param string|Zend_Mail_Storage_Folder $name name or instance of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function removeFolder($name);
/**
* rename and/or move folder
*
* The new name has the same restrictions as in createFolder()
*
* @param string|Zend_Mail_Storage_Folder $oldName name or instance of folder
* @param string $newName new global name of folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function renameFolder($oldName, $newName);
/**
* append a new message to mail storage
*
* @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
* @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken
* @param null|array $flags set flags for new message, else a default set is used
* @throws Zend_Mail_Storage_Exception
*/
public function appendMessage($message, $folder = null, $flags = null);
/**
* copy an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function copyMessage($id, $folder);
/**
* move an existing message
*
* @param int $id number of message
* @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
* @return null
* @throws Zend_Mail_Storage_Exception
*/
public function moveMessage($id, $folder);
/**
* set flags for message
*
* NOTE: this method can't set the recent flag.
*
* @param int $id number of message
* @param array $flags new flags for message
* @throws Zend_Mail_Storage_Exception
*/
public function setFlags($id, $flags);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,350 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Abstract.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* Abstract for sending eMails through different
* ways of transport
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Mail_Transport_Abstract
{
/**
* Mail body
* @var string
* @access public
*/
public $body = '';
/**
* MIME boundary
* @var string
* @access public
*/
public $boundary = '';
/**
* Mail header string
* @var string
* @access public
*/
public $header = '';
/**
* Array of message headers
* @var array
* @access protected
*/
protected $_headers = array();
/**
* Message is a multipart message
* @var boolean
* @access protected
*/
protected $_isMultipart = false;
/**
* Zend_Mail object
* @var false|Zend_Mail
* @access protected
*/
protected $_mail = false;
/**
* Array of message parts
* @var array
* @access protected
*/
protected $_parts = array();
/**
* Recipients string
* @var string
* @access public
*/
public $recipients = '';
/**
* EOL character string used by transport
* @var string
* @access public
*/
public $EOL = "\r\n";
/**
* Send an email independent from the used transport
*
* The requisite information for the email will be found in the following
* properties:
*
* - {@link $recipients} - list of recipients (string)
* - {@link $header} - message header
* - {@link $body} - message body
*/
abstract protected function _sendMail();
/**
* Return all mail headers as an array
*
* If a boundary is given, a multipart header is generated with a
* Content-Type of either multipart/alternative or multipart/mixed depending
* on the mail parts present in the {@link $_mail Zend_Mail object} present.
*
* @param string $boundary
* @return array
*/
protected function _getHeaders($boundary)
{
if (null !== $boundary) {
// Build multipart mail
$type = $this->_mail->getType();
if (!$type) {
if ($this->_mail->hasAttachments) {
$type = Zend_Mime::MULTIPART_MIXED;
} elseif ($this->_mail->getBodyText() && $this->_mail->getBodyHtml()) {
$type = Zend_Mime::MULTIPART_ALTERNATIVE;
} else {
$type = Zend_Mime::MULTIPART_MIXED;
}
}
$this->_headers['Content-Type'] = array(
$type . ';'
. $this->EOL
. " " . 'boundary="' . $boundary . '"'
);
$this->boundary = $boundary;
}
$this->_headers['MIME-Version'] = array('1.0');
return $this->_headers;
}
/**
* Prepend header name to header value
*
* @param string $item
* @param string $key
* @param string $prefix
* @static
* @access protected
* @return void
*/
protected static function _formatHeader(&$item, $key, $prefix)
{
$item = $prefix . ': ' . $item;
}
/**
* Prepare header string for use in transport
*
* Prepares and generates {@link $header} based on the headers provided.
*
* @param mixed $headers
* @access protected
* @return void
* @throws Zend_Mail_Transport_Exception if any header lines exceed 998
* characters
*/
protected function _prepareHeaders($headers)
{
if (!$this->_mail) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Missing Zend_Mail object in _mail property');
}
$this->header = '';
foreach ($headers as $header => $content) {
if (isset($content['append'])) {
unset($content['append']);
$value = implode(',' . $this->EOL . ' ', $content);
$this->header .= $header . ': ' . $value . $this->EOL;
} else {
array_walk($content, array(get_class($this), '_formatHeader'), $header);
$this->header .= implode($this->EOL, $content) . $this->EOL;
}
}
// Sanity check on headers -- should not be > 998 characters
$sane = true;
foreach (explode($this->EOL, $this->header) as $line) {
if (strlen(trim($line)) > 998) {
$sane = false;
break;
}
}
if (!$sane) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Exception('At least one mail header line is too long');
}
}
/**
* Generate MIME compliant message from the current configuration
*
* If both a text and HTML body are present, generates a
* multipart/alternative Zend_Mime_Part containing the headers and contents
* of each. Otherwise, uses whichever of the text or HTML parts present.
*
* The content part is then prepended to the list of Zend_Mime_Parts for
* this message.
*
* @return void
*/
protected function _buildBody()
{
if (($text = $this->_mail->getBodyText())
&& ($html = $this->_mail->getBodyHtml()))
{
// Generate unique boundary for multipart/alternative
$mime = new Zend_Mime(null);
$boundaryLine = $mime->boundaryLine($this->EOL);
$boundaryEnd = $mime->mimeEnd($this->EOL);
$text->disposition = false;
$html->disposition = false;
$body = $boundaryLine
. $text->getHeaders($this->EOL)
. $this->EOL
. $text->getContent($this->EOL)
. $this->EOL
. $boundaryLine
. $html->getHeaders($this->EOL)
. $this->EOL
. $html->getContent($this->EOL)
. $this->EOL
. $boundaryEnd;
$mp = new Zend_Mime_Part($body);
$mp->type = Zend_Mime::MULTIPART_ALTERNATIVE;
$mp->boundary = $mime->boundary();
$this->_isMultipart = true;
// Ensure first part contains text alternatives
array_unshift($this->_parts, $mp);
// Get headers
$this->_headers = $this->_mail->getHeaders();
return;
}
// If not multipart, then get the body
if (false !== ($body = $this->_mail->getBodyHtml())) {
array_unshift($this->_parts, $body);
} elseif (false !== ($body = $this->_mail->getBodyText())) {
array_unshift($this->_parts, $body);
}
if (!$body) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('No body specified');
}
// Get headers
$this->_headers = $this->_mail->getHeaders();
$headers = $body->getHeadersArray($this->EOL);
foreach ($headers as $header) {
// Headers in Zend_Mime_Part are kept as arrays with two elements, a
// key and a value
$this->_headers[$header[0]] = array($header[1]);
}
}
/**
* Send a mail using this transport
*
* @param Zend_Mail $mail
* @access public
* @return void
* @throws Zend_Mail_Transport_Exception if mail is empty
*/
public function send(Zend_Mail $mail)
{
$this->_isMultipart = false;
$this->_mail = $mail;
$this->_parts = $mail->getParts();
$mime = $mail->getMime();
// Build body content
$this->_buildBody();
// Determine number of parts and boundary
$count = count($this->_parts);
$boundary = null;
if ($count < 1) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Empty mail cannot be sent');
}
if ($count > 1) {
// Multipart message; create new MIME object and boundary
$mime = new Zend_Mime($this->_mail->getMimeBoundary());
$boundary = $mime->boundary();
} elseif ($this->_isMultipart) {
// multipart/alternative -- grab boundary
$boundary = $this->_parts[0]->boundary;
}
// Determine recipients, and prepare headers
$this->recipients = implode(',', $mail->getRecipients());
$this->_prepareHeaders($this->_getHeaders($boundary));
// Create message body
// This is done so that the same Zend_Mail object can be used in
// multiple transports
$message = new Zend_Mime_Message();
$message->setParts($this->_parts);
$message->setMime($mime);
$this->body = $message->generateMessage($this->EOL);
// Send to transport!
$this->_sendMail();
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
/**
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_Exception extends Zend_Mail_Exception
{}

View File

@ -0,0 +1,134 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
/**
* @see Zend_Mail_Transport_Abstract
*/
require_once 'Zend/Mail/Transport/Abstract.php';
/**
* File transport
*
* Class for saving outgoing emails in filesystem
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_File extends Zend_Mail_Transport_Abstract
{
/**
* Target directory for saving sent email messages
*
* @var string
*/
protected $_path;
/**
* Callback function generating a file name
*
* @var string|array
*/
protected $_callback;
/**
* Constructor
*
* @param array|Zend_Config $options OPTIONAL (Default: null)
* @return void
*/
public function __construct($options = null)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} elseif (!is_array($options)) {
$options = array();
}
// Making sure we have some defaults to work with
if (!isset($options['path'])) {
$options['path'] = sys_get_temp_dir();
}
if (!isset($options['callback'])) {
$options['callback'] = array($this, 'defaultCallback');
}
$this->setOptions($options);
}
/**
* Sets options
*
* @param array $options
* @return void
*/
public function setOptions(array $options)
{
if (isset($options['path']) && is_dir($options['path'])) {
$this->_path = $options['path'];
}
if (isset($options['callback']) && is_callable($options['callback'])) {
$this->_callback = $options['callback'];
}
}
/**
* Saves e-mail message to a file
*
* @return void
* @throws Zend_Mail_Transport_Exception on not writable target directory
* @throws Zend_Mail_Transport_Exception on file_put_contents() failure
*/
protected function _sendMail()
{
$file = $this->_path . DIRECTORY_SEPARATOR . call_user_func($this->_callback, $this);
if (!is_writable(dirname($file))) {
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception(sprintf(
'Target directory "%s" does not exist or is not writable',
dirname($file)
));
}
$email = $this->header . $this->EOL . $this->body;
if (!file_put_contents($file, $email)) {
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Unable to send mail');
}
}
/**
* Default callback for generating filenames
*
* @param Zend_Mail_Transport_File File transport instance
* @return string
*/
public function defaultCallback($transport)
{
return 'ZendMail_' . $_SERVER['REQUEST_TIME'] . '_' . mt_rand() . '.tmp';
}
}

View File

@ -0,0 +1,220 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Sendmail.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mail_Transport_Abstract
*/
require_once 'Zend/Mail/Transport/Abstract.php';
/**
* Class for sending eMails via the PHP internal mail() function
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_Sendmail extends Zend_Mail_Transport_Abstract
{
/**
* Subject
* @var string
* @access public
*/
public $subject = null;
/**
* Config options for sendmail parameters
*
* @var string
*/
public $parameters;
/**
* EOL character string
* @var string
* @access public
*/
public $EOL = PHP_EOL;
/**
* error information
* @var string
*/
protected $_errstr;
/**
* Constructor.
*
* @param string|array|Zend_Config $parameters OPTIONAL (Default: null)
* @return void
*/
public function __construct($parameters = null)
{
if ($parameters instanceof Zend_Config) {
$parameters = $parameters->toArray();
}
if (is_array($parameters)) {
$parameters = implode(' ', $parameters);
}
$this->parameters = $parameters;
}
/**
* Send mail using PHP native mail()
*
* @access public
* @return void
* @throws Zend_Mail_Transport_Exception if parameters is set
* but not a string
* @throws Zend_Mail_Transport_Exception on mail() failure
*/
public function _sendMail()
{
if ($this->parameters === null) {
set_error_handler(array($this, '_handleMailErrors'));
$result = mail(
$this->recipients,
$this->_mail->getSubject(),
$this->body,
$this->header);
restore_error_handler();
} else {
if(!is_string($this->parameters)) {
/**
* @see Zend_Mail_Transport_Exception
*
* Exception is thrown here because
* $parameters is a public property
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception(
'Parameters were set but are not a string'
);
}
set_error_handler(array($this, '_handleMailErrors'));
$result = mail(
$this->recipients,
$this->_mail->getSubject(),
$this->body,
$this->header,
$this->parameters);
restore_error_handler();
}
if ($this->_errstr !== null || !$result) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Unable to send mail. ' . $this->_errstr);
}
}
/**
* Format and fix headers
*
* mail() uses its $to and $subject arguments to set the To: and Subject:
* headers, respectively. This method strips those out as a sanity check to
* prevent duplicate header entries.
*
* @access protected
* @param array $headers
* @return void
* @throws Zend_Mail_Transport_Exception
*/
protected function _prepareHeaders($headers)
{
if (!$this->_mail) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object');
}
// mail() uses its $to parameter to set the To: header, and the $subject
// parameter to set the Subject: header. We need to strip them out.
if (0 === strpos(PHP_OS, 'WIN')) {
// If the current recipients list is empty, throw an error
if (empty($this->recipients)) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Missing To addresses');
}
} else {
// All others, simply grab the recipients and unset the To: header
if (!isset($headers['To'])) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('Missing To header');
}
unset($headers['To']['append']);
$this->recipients = implode(',', $headers['To']);
}
// Remove recipient header
unset($headers['To']);
// Remove subject header, if present
if (isset($headers['Subject'])) {
unset($headers['Subject']);
}
// Prepare headers
parent::_prepareHeaders($headers);
// Fix issue with empty blank line ontop when using Sendmail Trnasport
$this->header = rtrim($this->header);
}
/**
* Temporary error handler for PHP native mail().
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param string $errline
* @param array $errcontext
* @return true
*/
public function _handleMailErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
{
$this->_errstr = $errstr;
return true;
}
}

View File

@ -0,0 +1,243 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Smtp.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* @see Zend_Mail_Protocol_Smtp
*/
require_once 'Zend/Mail/Protocol/Smtp.php';
/**
* @see Zend_Mail_Transport_Abstract
*/
require_once 'Zend/Mail/Transport/Abstract.php';
/**
* SMTP connection object
*
* Loads an instance of Zend_Mail_Protocol_Smtp and forwards smtp transactions
*
* @category Zend
* @package Zend_Mail
* @subpackage Transport
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mail_Transport_Smtp extends Zend_Mail_Transport_Abstract
{
/**
* EOL character string used by transport
* @var string
* @access public
*/
public $EOL = "\n";
/**
* Remote smtp hostname or i.p.
*
* @var string
*/
protected $_host;
/**
* Port number
*
* @var integer|null
*/
protected $_port;
/**
* Local client hostname or i.p.
*
* @var string
*/
protected $_name = 'localhost';
/**
* Authentication type OPTIONAL
*
* @var string
*/
protected $_auth;
/**
* Config options for authentication
*
* @var array
*/
protected $_config;
/**
* Instance of Zend_Mail_Protocol_Smtp
*
* @var Zend_Mail_Protocol_Smtp
*/
protected $_connection;
/**
* Constructor.
*
* @param string $host OPTIONAL (Default: 127.0.0.1)
* @param array|null $config OPTIONAL (Default: null)
* @return void
*
* @todo Someone please make this compatible
* with the SendMail transport class.
*/
public function __construct($host = '127.0.0.1', Array $config = array())
{
if (isset($config['name'])) {
$this->_name = $config['name'];
}
if (isset($config['port'])) {
$this->_port = $config['port'];
}
if (isset($config['auth'])) {
$this->_auth = $config['auth'];
}
$this->_host = $host;
$this->_config = $config;
}
/**
* Class destructor to ensure all open connections are closed
*
* @return void
*/
public function __destruct()
{
if ($this->_connection instanceof Zend_Mail_Protocol_Smtp) {
try {
$this->_connection->quit();
} catch (Zend_Mail_Protocol_Exception $e) {
// ignore
}
$this->_connection->disconnect();
}
}
/**
* Sets the connection protocol instance
*
* @param Zend_Mail_Protocol_Abstract $client
*
* @return void
*/
public function setConnection(Zend_Mail_Protocol_Abstract $connection)
{
$this->_connection = $connection;
}
/**
* Gets the connection protocol instance
*
* @return Zend_Mail_Protocol|null
*/
public function getConnection()
{
return $this->_connection;
}
/**
* Send an email via the SMTP connection protocol
*
* The connection via the protocol adapter is made just-in-time to allow a
* developer to add a custom adapter if required before mail is sent.
*
* @return void
* @todo Rename this to sendMail, it's a public method...
*/
public function _sendMail()
{
// If sending multiple messages per session use existing adapter
if (!($this->_connection instanceof Zend_Mail_Protocol_Smtp)) {
// Check if authentication is required and determine required class
$connectionClass = 'Zend_Mail_Protocol_Smtp';
if ($this->_auth) {
$connectionClass .= '_Auth_' . ucwords($this->_auth);
}
if (!class_exists($connectionClass)) {
require_once 'Zend/Loader.php';
Zend_Loader::loadClass($connectionClass);
}
$this->setConnection(new $connectionClass($this->_host, $this->_port, $this->_config));
$this->_connection->connect();
$this->_connection->helo($this->_name);
} else {
// Reset connection to ensure reliable transaction
$this->_connection->rset();
}
// Set sender email address
$this->_connection->mail($this->_mail->getReturnPath());
// Set recipient forward paths
foreach ($this->_mail->getRecipients() as $recipient) {
$this->_connection->rcpt($recipient);
}
// Issue DATA command to client
$this->_connection->data($this->header . Zend_Mime::LINEEND . $this->body);
}
/**
* Format and fix headers
*
* Some SMTP servers do not strip BCC headers. Most clients do it themselves as do we.
*
* @access protected
* @param array $headers
* @return void
* @throws Zend_Transport_Exception
*/
protected function _prepareHeaders($headers)
{
if (!$this->_mail) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object');
}
unset($headers['Bcc']);
// Prepare headers
parent::_prepareHeaders($headers);
}
}

365
webui/Zend/Mime.php Normal file
View File

@ -0,0 +1,365 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Mime.php 24953 2012-06-13 19:09:58Z rob $
*/
/**
* Support class for MultiPart Mime Messages
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime
{
const TYPE_OCTETSTREAM = 'application/octet-stream';
const TYPE_TEXT = 'text/plain';
const TYPE_HTML = 'text/html';
const ENCODING_7BIT = '7bit';
const ENCODING_8BIT = '8bit';
const ENCODING_QUOTEDPRINTABLE = 'quoted-printable';
const ENCODING_BASE64 = 'base64';
const DISPOSITION_ATTACHMENT = 'attachment';
const DISPOSITION_INLINE = 'inline';
const LINELENGTH = 72;
const LINEEND = "\n";
const MULTIPART_ALTERNATIVE = 'multipart/alternative';
const MULTIPART_MIXED = 'multipart/mixed';
const MULTIPART_RELATED = 'multipart/related';
protected $_boundary;
protected static $makeUnique = 0;
// lookup-Tables for QuotedPrintable
public static $qpKeys = array(
"\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07",
"\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F",
"\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17",
"\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F",
"\x7F","\x80","\x81","\x82","\x83","\x84","\x85","\x86",
"\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E",
"\x8F","\x90","\x91","\x92","\x93","\x94","\x95","\x96",
"\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E",
"\x9F","\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6",
"\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE",
"\xAF","\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6",
"\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE",
"\xBF","\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6",
"\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE",
"\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6",
"\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE",
"\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6",
"\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE",
"\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6",
"\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE",
"\xFF"
);
public static $qpReplaceValues = array(
"=00","=01","=02","=03","=04","=05","=06","=07",
"=08","=09","=0A","=0B","=0C","=0D","=0E","=0F",
"=10","=11","=12","=13","=14","=15","=16","=17",
"=18","=19","=1A","=1B","=1C","=1D","=1E","=1F",
"=7F","=80","=81","=82","=83","=84","=85","=86",
"=87","=88","=89","=8A","=8B","=8C","=8D","=8E",
"=8F","=90","=91","=92","=93","=94","=95","=96",
"=97","=98","=99","=9A","=9B","=9C","=9D","=9E",
"=9F","=A0","=A1","=A2","=A3","=A4","=A5","=A6",
"=A7","=A8","=A9","=AA","=AB","=AC","=AD","=AE",
"=AF","=B0","=B1","=B2","=B3","=B4","=B5","=B6",
"=B7","=B8","=B9","=BA","=BB","=BC","=BD","=BE",
"=BF","=C0","=C1","=C2","=C3","=C4","=C5","=C6",
"=C7","=C8","=C9","=CA","=CB","=CC","=CD","=CE",
"=CF","=D0","=D1","=D2","=D3","=D4","=D5","=D6",
"=D7","=D8","=D9","=DA","=DB","=DC","=DD","=DE",
"=DF","=E0","=E1","=E2","=E3","=E4","=E5","=E6",
"=E7","=E8","=E9","=EA","=EB","=EC","=ED","=EE",
"=EF","=F0","=F1","=F2","=F3","=F4","=F5","=F6",
"=F7","=F8","=F9","=FA","=FB","=FC","=FD","=FE",
"=FF"
);
public static $qpKeysString =
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
/**
* Check if the given string is "printable"
*
* Checks that a string contains no unprintable characters. If this returns
* false, encode the string for secure delivery.
*
* @param string $str
* @return boolean
*/
public static function isPrintable($str)
{
return (strcspn($str, self::$qpKeysString) == strlen($str));
}
/**
* Encode a given string with the QUOTED_PRINTABLE mechanism and wrap the lines.
*
* @param string $str
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeQuotedPrintable($str,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
$out = '';
$str = self::_encodeQuotedPrintable($str);
// Split encoded text into separate lines
while(strlen($str) > 0) {
$ptr = strlen($str);
if ($ptr > $lineLength) {
$ptr = $lineLength;
}
// Ensure we are not splitting across an encoded character
$pos = strrpos(substr($str, 0, $ptr), '=');
if ($pos !== false && $pos >= $ptr - 2) {
$ptr = $pos;
}
// Check if there is a space at the end of the line and rewind
if ($ptr > 0 && $str[$ptr - 1] == ' ') {
--$ptr;
}
// Add string and continue
$out .= substr($str, 0, $ptr) . '=' . $lineEnd;
$str = substr($str, $ptr);
}
$out = rtrim($out, $lineEnd);
$out = rtrim($out, '=');
return $out;
}
/**
* Converts a string into quoted printable format.
*
* @param string $str
* @return string
*/
private static function _encodeQuotedPrintable($str)
{
$str = str_replace('=', '=3D', $str);
$str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
$str = rtrim($str);
return $str;
}
/**
* Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers.
*
* Mail headers depend on an extended quoted printable algorithm otherwise
* a range of bugs can occur.
*
* @param string $str
* @param string $charset
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeQuotedPrintableHeader($str, $charset,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
// Reduce line-length by the length of the required delimiter, charsets and encoding
$prefix = sprintf('=?%s?Q?', $charset);
$lineLength = $lineLength-strlen($prefix)-3;
$str = self::_encodeQuotedPrintable($str);
// Mail-Header required chars have to be encoded also:
$str = str_replace(array('?', ' ', '_', ','), array('=3F', '=20', '=5F', '=2C'), $str);
// initialize first line, we need it anyways
$lines = array(0 => "");
// Split encoded text into separate lines
$tmp = "";
while(strlen($str) > 0) {
$currentLine = max(count($lines)-1, 0);
$token = self::getNextQuotedPrintableToken($str);
$str = substr($str, strlen($token));
$tmp .= $token;
if($token == '=20') {
// only if we have a single char token or space, we can append the
// tempstring it to the current line or start a new line if necessary.
if(strlen($lines[$currentLine].$tmp) > $lineLength) {
$lines[$currentLine+1] = $tmp;
} else {
$lines[$currentLine] .= $tmp;
}
$tmp = "";
}
// don't forget to append the rest to the last line
if(strlen($str) == 0) {
$lines[$currentLine] .= $tmp;
}
}
// assemble the lines together by pre- and appending delimiters, charset, encoding.
for($i = 0; $i < count($lines); $i++) {
$lines[$i] = " ".$prefix.$lines[$i]."?=";
}
$str = trim(implode($lineEnd, $lines));
return $str;
}
/**
* Retrieves the first token from a quoted printable string.
*
* @param string $str
* @return string
*/
private static function getNextQuotedPrintableToken($str)
{
if(substr($str, 0, 1) == "=") {
$token = substr($str, 0, 3);
} else {
$token = substr($str, 0, 1);
}
return $token;
}
/**
* Encode a given string in mail header compatible base64 encoding.
*
* @param string $str
* @param string $charset
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeBase64Header($str,
$charset,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
$prefix = '=?' . $charset . '?B?';
$suffix = '?=';
$remainingLength = $lineLength - strlen($prefix) - strlen($suffix);
$encodedValue = self::encodeBase64($str, $remainingLength, $lineEnd);
$encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue);
$encodedValue = $prefix . $encodedValue . $suffix;
return $encodedValue;
}
/**
* Encode a given string in base64 encoding and break lines
* according to the maximum linelength.
*
* @param string $str
* @param int $lineLength Defaults to {@link LINELENGTH}
* @param int $lineEnd Defaults to {@link LINEEND}
* @return string
*/
public static function encodeBase64($str,
$lineLength = self::LINELENGTH,
$lineEnd = self::LINEEND)
{
return rtrim(chunk_split(base64_encode($str), $lineLength, $lineEnd));
}
/**
* Constructor
*
* @param null|string $boundary
* @access public
* @return void
*/
public function __construct($boundary = null)
{
// This string needs to be somewhat unique
if ($boundary === null) {
$this->_boundary = '=_' . md5(microtime(1) . self::$makeUnique++);
} else {
$this->_boundary = $boundary;
}
}
/**
* Encode the given string with the given encoding.
*
* @param string $str
* @param string $encoding
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return string
*/
public static function encode($str, $encoding, $EOL = self::LINEEND)
{
switch ($encoding) {
case self::ENCODING_BASE64:
return self::encodeBase64($str, self::LINELENGTH, $EOL);
case self::ENCODING_QUOTEDPRINTABLE:
return self::encodeQuotedPrintable($str, self::LINELENGTH, $EOL);
default:
/**
* @todo 7Bit and 8Bit is currently handled the same way.
*/
return $str;
}
}
/**
* Return a MIME boundary
*
* @access public
* @return string
*/
public function boundary()
{
return $this->_boundary;
}
/**
* Return a MIME boundary line
*
* @param mixed $EOL Defaults to {@link LINEEND}
* @access public
* @return string
*/
public function boundaryLine($EOL = self::LINEEND)
{
return $EOL . '--' . $this->_boundary . $EOL;
}
/**
* Return MIME ending
*
* @access public
* @return string
*/
public function mimeEnd($EOL = self::LINEEND)
{
return $EOL . '--' . $this->_boundary . '--' . $EOL;
}
}

244
webui/Zend/Mime/Decode.php Normal file
View File

@ -0,0 +1,244 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Decode.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* @see Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Decode
{
/**
* Explode MIME multipart string into seperate parts
*
* Parts consist of the header and the body of each MIME part.
*
* @param string $body raw body of message
* @param string $boundary boundary as found in content-type
* @return array parts with content of each part, empty if no parts found
* @throws Zend_Exception
*/
public static function splitMime($body, $boundary)
{
// TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
$body = str_replace("\r", '', $body);
$start = 0;
$res = array();
// find every mime part limiter and cut out the
// string before it.
// the part before the first boundary string is discarded:
$p = strpos($body, '--' . $boundary . "\n", $start);
if ($p === false) {
// no parts found!
return array();
}
// position after first boundary line
$start = $p + 3 + strlen($boundary);
while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
$res[] = substr($body, $start, $p-$start);
$start = $p + 3 + strlen($boundary);
}
// no more parts, find end boundary
$p = strpos($body, '--' . $boundary . '--', $start);
if ($p===false) {
throw new Zend_Exception('Not a valid Mime Message: End Missing');
}
// the remaining part also needs to be parsed:
$res[] = substr($body, $start, $p-$start);
return $res;
}
/**
* decodes a mime encoded String and returns a
* struct of parts with header and body
*
* @param string $message raw message content
* @param string $boundary boundary as found in content-type
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found
* @throws Zend_Exception
*/
public static function splitMessageStruct($message, $boundary, $EOL = Zend_Mime::LINEEND)
{
$parts = self::splitMime($message, $boundary);
if (count($parts) <= 0) {
return null;
}
$result = array();
foreach ($parts as $part) {
self::splitMessage($part, $headers, $body, $EOL);
$result[] = array('header' => $headers,
'body' => $body );
}
return $result;
}
/**
* split a message in header and body part, if no header or an
* invalid header is found $headers is empty
*
* The charset of the returned headers depend on your iconv settings.
*
* @param string $message raw message with header and optional content
* @param array $headers output param, array with headers as array(name => value)
* @param string $body output param, content of message
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return null
*/
public static function splitMessage($message, &$headers, &$body, $EOL = Zend_Mime::LINEEND)
{
// check for valid header at first line
$firstline = strtok($message, "\n");
if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) {
$headers = array();
// TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
$body = str_replace(array("\r", "\n"), array('', $EOL), $message);
return;
}
// find an empty line between headers and body
// default is set new line
if (strpos($message, $EOL . $EOL)) {
list($headers, $body) = explode($EOL . $EOL, $message, 2);
// next is the standard new line
} else if ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) {
list($headers, $body) = explode("\r\n\r\n", $message, 2);
// next is the other "standard" new line
} else if ($EOL != "\n" && strpos($message, "\n\n")) {
list($headers, $body) = explode("\n\n", $message, 2);
// at last resort find anything that looks like a new line
} else {
@list($headers, $body) = @preg_split("%([\r\n]+)\\1%U", $message, 2);
}
$headers = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
if ($headers === false ) {
// an error occurs during the decoding
return;
}
// normalize header names
foreach ($headers as $name => $header) {
$lower = strtolower($name);
if ($lower == $name) {
continue;
}
unset($headers[$name]);
if (!isset($headers[$lower])) {
$headers[$lower] = $header;
continue;
}
if (is_array($headers[$lower])) {
$headers[$lower][] = $header;
continue;
}
$headers[$lower] = array($headers[$lower], $header);
}
}
/**
* split a content type in its different parts
*
* @param string $type content-type
* @param string $wantedPart the wanted part, else an array with all parts is returned
* @return string|array wanted part or all parts as array('type' => content-type, partname => value)
*/
public static function splitContentType($type, $wantedPart = null)
{
return self::splitHeaderField($type, $wantedPart, 'type');
}
/**
* split a header field like content type in its different parts
*
* @param string $type header field
* @param string $wantedPart the wanted part, else an array with all parts is returned
* @param string $firstName key name for the first part
* @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
* @throws Zend_Exception
*/
public static function splitHeaderField($field, $wantedPart = null, $firstName = 0)
{
$wantedPart = strtolower($wantedPart);
$firstName = strtolower($firstName);
// special case - a bit optimized
if ($firstName === $wantedPart) {
$field = strtok($field, ';');
return $field[0] == '"' ? substr($field, 1, -1) : $field;
}
$field = $firstName . '=' . $field;
if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) {
throw new Zend_Exception('not a valid header field');
}
if ($wantedPart) {
foreach ($matches[1] as $key => $name) {
if (strcasecmp($name, $wantedPart)) {
continue;
}
if ($matches[2][$key][0] != '"') {
return $matches[2][$key];
}
return substr($matches[2][$key], 1, -1);
}
return null;
}
$split = array();
foreach ($matches[1] as $key => $name) {
$name = strtolower($name);
if ($matches[2][$key][0] == '"') {
$split[$name] = substr($matches[2][$key], 1, -1);
} else {
$split[$name] = $matches[2][$key];
}
}
return $split;
}
/**
* decode a quoted printable encoded string
*
* The charset of the returned string depends on your iconv settings.
*
* @param string encoded string
* @return string decoded string
*/
public static function decodeQuotedPrintable($string)
{
return quoted_printable_decode($string);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Exception extends Zend_Exception
{}

286
webui/Zend/Mime/Message.php Normal file
View File

@ -0,0 +1,286 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Message.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* Zend_Mime_Part
*/
require_once 'Zend/Mime/Part.php';
/**
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Message
{
protected $_parts = array();
protected $_mime = null;
/**
* Returns the list of all Zend_Mime_Parts in the message
*
* @return array of Zend_Mime_Part
*/
public function getParts()
{
return $this->_parts;
}
/**
* Sets the given array of Zend_Mime_Parts as the array for the message
*
* @param array $parts
*/
public function setParts($parts)
{
$this->_parts = $parts;
}
/**
* Append a new Zend_Mime_Part to the current message
*
* @param Zend_Mime_Part $part
*/
public function addPart(Zend_Mime_Part $part)
{
/**
* @todo check for duplicate object handle
*/
$this->_parts[] = $part;
}
/**
* Check if message needs to be sent as multipart
* MIME message or if it has only one part.
*
* @return boolean
*/
public function isMultiPart()
{
return (count($this->_parts) > 1);
}
/**
* Set Zend_Mime object for the message
*
* This can be used to set the boundary specifically or to use a subclass of
* Zend_Mime for generating the boundary.
*
* @param Zend_Mime $mime
*/
public function setMime(Zend_Mime $mime)
{
$this->_mime = $mime;
}
/**
* Returns the Zend_Mime object in use by the message
*
* If the object was not present, it is created and returned. Can be used to
* determine the boundary used in this message.
*
* @return Zend_Mime
*/
public function getMime()
{
if ($this->_mime === null) {
$this->_mime = new Zend_Mime();
}
return $this->_mime;
}
/**
* Generate MIME-compliant message from the current configuration
*
* This can be a multipart message if more than one MIME part was added. If
* only one part is present, the content of this part is returned. If no
* part had been added, an empty string is returned.
*
* Parts are seperated by the mime boundary as defined in Zend_Mime. If
* {@link setMime()} has been called before this method, the Zend_Mime
* object set by this call will be used. Otherwise, a new Zend_Mime object
* is generated and used.
*
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return string
*/
public function generateMessage($EOL = Zend_Mime::LINEEND)
{
if (! $this->isMultiPart()) {
$body = array_shift($this->_parts);
$body = $body->getContent($EOL);
} else {
$mime = $this->getMime();
$boundaryLine = $mime->boundaryLine($EOL);
$body = 'This is a message in Mime Format. If you see this, '
. "your mail reader does not support this format." . $EOL;
foreach (array_keys($this->_parts) as $p) {
$body .= $boundaryLine
. $this->getPartHeaders($p, $EOL)
. $EOL
. $this->getPartContent($p, $EOL);
}
$body .= $mime->mimeEnd($EOL);
}
return trim($body);
}
/**
* Get the headers of a given part as an array
*
* @param int $partnum
* @return array
*/
public function getPartHeadersArray($partnum)
{
return $this->_parts[$partnum]->getHeadersArray();
}
/**
* Get the headers of a given part as a string
*
* @param int $partnum
* @return string
*/
public function getPartHeaders($partnum, $EOL = Zend_Mime::LINEEND)
{
return $this->_parts[$partnum]->getHeaders($EOL);
}
/**
* Get the (encoded) content of a given part as a string
*
* @param int $partnum
* @return string
*/
public function getPartContent($partnum, $EOL = Zend_Mime::LINEEND)
{
return $this->_parts[$partnum]->getContent($EOL);
}
/**
* Explode MIME multipart string into seperate parts
*
* Parts consist of the header and the body of each MIME part.
*
* @param string $body
* @param string $boundary
* @return array
*/
protected static function _disassembleMime($body, $boundary)
{
$start = 0;
$res = array();
// find every mime part limiter and cut out the
// string before it.
// the part before the first boundary string is discarded:
$p = strpos($body, '--'.$boundary."\n", $start);
if ($p === false) {
// no parts found!
return array();
}
// position after first boundary line
$start = $p + 3 + strlen($boundary);
while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
$res[] = substr($body, $start, $p-$start);
$start = $p + 3 + strlen($boundary);
}
// no more parts, find end boundary
$p = strpos($body, '--' . $boundary . '--', $start);
if ($p===false) {
throw new Zend_Exception('Not a valid Mime Message: End Missing');
}
// the remaining part also needs to be parsed:
$res[] = substr($body, $start, $p-$start);
return $res;
}
/**
* Decodes a MIME encoded string and returns a Zend_Mime_Message object with
* all the MIME parts set according to the given string
*
* @param string $message
* @param string $boundary
* @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
* @return Zend_Mime_Message
*/
public static function createFromMessage($message, $boundary, $EOL = Zend_Mime::LINEEND)
{
require_once 'Zend/Mime/Decode.php';
$parts = Zend_Mime_Decode::splitMessageStruct($message, $boundary, $EOL);
$res = new self();
foreach ($parts as $part) {
// now we build a new MimePart for the current Message Part:
$newPart = new Zend_Mime_Part($part['body']);
foreach ($part['header'] as $key => $value) {
/**
* @todo check for characterset and filename
*/
switch(strtolower($key)) {
case 'content-type':
$newPart->type = $value;
break;
case 'content-transfer-encoding':
$newPart->encoding = $value;
break;
case 'content-id':
$newPart->id = trim($value,'<>');
break;
case 'content-disposition':
$newPart->disposition = $value;
break;
case 'content-description':
$newPart->description = $value;
break;
case 'content-location':
$newPart->location = $value;
break;
case 'content-language':
$newPart->language = $value;
break;
default:
throw new Zend_Exception('Unknown header ignored for MimePart:' . $key);
}
}
$res->addPart($newPart);
}
return $res;
}
}

230
webui/Zend/Mime/Part.php Normal file
View File

@ -0,0 +1,230 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Part.php 24593 2012-01-05 20:35:02Z matthew $
*/
/**
* Zend_Mime
*/
require_once 'Zend/Mime.php';
/**
* Class representing a MIME part.
*
* @category Zend
* @package Zend_Mime
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Mime_Part {
public $type = Zend_Mime::TYPE_OCTETSTREAM;
public $encoding = Zend_Mime::ENCODING_8BIT;
public $id;
public $disposition;
public $filename;
public $description;
public $charset;
public $boundary;
public $location;
public $language;
protected $_content;
protected $_isStream = false;
/**
* create a new Mime Part.
* The (unencoded) content of the Part as passed
* as a string or stream
*
* @param mixed $content String or Stream containing the content
*/
public function __construct($content)
{
$this->_content = $content;
if (is_resource($content)) {
$this->_isStream = true;
}
}
/**
* @todo setters/getters
* @todo error checking for setting $type
* @todo error checking for setting $encoding
*/
/**
* check if this part can be read as a stream.
* if true, getEncodedStream can be called, otherwise
* only getContent can be used to fetch the encoded
* content of the part
*
* @return bool
*/
public function isStream()
{
return $this->_isStream;
}
/**
* if this was created with a stream, return a filtered stream for
* reading the content. very useful for large file attachments.
*
* @return stream
* @throws Zend_Mime_Exception if not a stream or unable to append filter
*/
public function getEncodedStream()
{
if (!$this->_isStream) {
require_once 'Zend/Mime/Exception.php';
throw new Zend_Mime_Exception('Attempt to get a stream from a string part');
}
//stream_filter_remove(); // ??? is that right?
switch ($this->encoding) {
case Zend_Mime::ENCODING_QUOTEDPRINTABLE:
$filter = stream_filter_append(
$this->_content,
'convert.quoted-printable-encode',
STREAM_FILTER_READ,
array(
'line-length' => 76,
'line-break-chars' => Zend_Mime::LINEEND
)
);
if (!is_resource($filter)) {
require_once 'Zend/Mime/Exception.php';
throw new Zend_Mime_Exception('Failed to append quoted-printable filter');
}
break;
case Zend_Mime::ENCODING_BASE64:
$filter = stream_filter_append(
$this->_content,
'convert.base64-encode',
STREAM_FILTER_READ,
array(
'line-length' => 76,
'line-break-chars' => Zend_Mime::LINEEND
)
);
if (!is_resource($filter)) {
require_once 'Zend/Mime/Exception.php';
throw new Zend_Mime_Exception('Failed to append base64 filter');
}
break;
default:
}
return $this->_content;
}
/**
* Get the Content of the current Mime Part in the given encoding.
*
* @return String
*/
public function getContent($EOL = Zend_Mime::LINEEND)
{
if ($this->_isStream) {
return stream_get_contents($this->getEncodedStream());
} else {
return Zend_Mime::encode($this->_content, $this->encoding, $EOL);
}
}
/**
* Get the RAW unencoded content from this part
* @return string
*/
public function getRawContent()
{
if ($this->_isStream) {
return stream_get_contents($this->_content);
} else {
return $this->_content;
}
}
/**
* Create and return the array of headers for this MIME part
*
* @access public
* @return array
*/
public function getHeadersArray($EOL = Zend_Mime::LINEEND)
{
$headers = array();
$contentType = $this->type;
if ($this->charset) {
$contentType .= '; charset=' . $this->charset;
}
if ($this->boundary) {
$contentType .= ';' . $EOL
. " boundary=\"" . $this->boundary . '"';
}
$headers[] = array('Content-Type', $contentType);
if ($this->encoding) {
$headers[] = array('Content-Transfer-Encoding', $this->encoding);
}
if ($this->id) {
$headers[] = array('Content-ID', '<' . $this->id . '>');
}
if ($this->disposition) {
$disposition = $this->disposition;
if ($this->filename) {
$disposition .= '; filename="' . $this->filename . '"';
}
$headers[] = array('Content-Disposition', $disposition);
}
if ($this->description) {
$headers[] = array('Content-Description', $this->description);
}
if ($this->location) {
$headers[] = array('Content-Location', $this->location);
}
if ($this->language){
$headers[] = array('Content-Language', $this->language);
}
return $headers;
}
/**
* Return the headers for this part as a string
*
* @return String
*/
public function getHeaders($EOL = Zend_Mime::LINEEND)
{
$res = '';
foreach ($this->getHeadersArray($EOL) as $header) {
$res .= $header[0] . ': ' . $header[1] . $EOL;
}
return $res;
}
}

View File

@ -15,6 +15,12 @@ define('ENABLE_REMOTE_IMAGES', '0');
define('ENABLE_ON_THE_FLY_VERIFICATION', 1);
define('ENABLE_LDAP_IMPORT_FEATURE', 0);
define('ENABLE_FOLDER_RESTRICTIONS', 0);
define('ENABLE_GOOGLE_LOGIN', 0);
define('GOOGLE_CLIENT_ID', 'xxxxxxxxxxx');
define('GOOGLE_CLIENT_SECRET', 'xxxxxxxxxxxxx');
define('GOOGLE_DEVELOPER_KEY', 'xxxxxxxxxxxx');
define('GOOGLE_APPLICATION_NAME', 'piler enterprise email archiver');
define('REMOTE_IMAGE_REPLACEMENT', '/view/theme/default/images/remote.gif');
define('ICON_ARROW_UP', '/view/theme/default/images/arrowup.gif');
@ -107,6 +113,8 @@ define('TABLE_AUDIT', 'audit');
define('TABLE_ARCHIVING_RULE', 'archiving_rule');
define('TABLE_RETENTION_RULE', 'retention_rule');
define('TABLE_OPTION', 'option');
define('TABLE_GOOGLE', 'google');
define('TABLE_GOOGLE_IMAP', 'google_imap');
define('VIEW_MESSAGES', 'v_messages');
define('SPHINX_DRIVER', 'sphinx');
@ -150,6 +158,8 @@ define('LOAD_SAVED_SEARCH_URL', SITE_URL . 'index.php?route=search/load');
define('SEARCH_TAG_URL', SITE_URL . 'index.php?route=search/tag');
define('MESSAGE_NOTE_URL', SITE_URL . 'index.php?route=message/note');
define('GOOGLE_REDIRECT_URL', SITE_URL . 'google.php');
define('HEALTH_URL', SITE_URL . 'index.php?route=health/health');
define('HEALTH_WORKER_URL', SITE_URL . 'index.php?route=health/worker');
define('HEALTH_REFRESH', 60);

View File

@ -0,0 +1,96 @@
<?php
class ControllerLoginGoogle extends Controller {
private $error = array();
public function index(){
$this->id = "content";
$this->template = "login/login.tpl";
$this->layout = "common/layout";
$request = Registry::get('request');
$db = Registry::get('db');
$this->load->model('user/auth');
$this->load->model('user/user');
$this->load->model('user/prefs');
$this->load->model('user/google');
$this->load->model('folder/folder');
$this->document->title = $this->data['text_login'];
$client = new apiClient();
$client->setApplicationName(GOOGLE_APPLICATION_NAME);
$client->setScopes(array(
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://mail.google.com/',
));
$client->setClientId(GOOGLE_CLIENT_ID);
$client->setClientSecret(GOOGLE_CLIENT_SECRET);
$client->setRedirectUri(GOOGLE_REDIRECT_URL);
$client->setDeveloperKey(GOOGLE_DEVELOPER_KEY);
$oauth2 = new apiOauth2Service($client);
if(isset($_GET['code'])) {
$client->authenticate();
$_SESSION['access_token'] = $client->getAccessToken();
header('Location: ' . GOOGLE_REDIRECT_URL);
}
if(isset($_SESSION['access_token'])) {
$client->setAccessToken($_SESSION['access_token']);
}
if($client->getAccessToken()) {
$_SESSION['access_token'] = $client->getAccessToken();
$token = json_decode($_SESSION['access_token']);
if(isset($token->{'access_token'}) && isset($token->{'refresh_token'})) {
$account = $oauth2->userinfo->get();
$this->model_user_google->check_for_account($account);
$this->model_user_google->update_tokens($account['email'], $account['id'], $token);
header("Location: " . SITE_URL . "search.php");
exit;
}
}
$this->render();
}
private function validate() {
if(strlen($this->request->post['username']) < 2){
$this->error['username'] = $this->data['text_invalid_username'];
}
if (!$this->error) {
return true;
} else {
return false;
}
}
}
?>

View File

@ -51,6 +51,25 @@ class ControllerLoginLogin extends Controller {
}
if(ENABLE_GOOGLE_LOGIN == 1) {
$client = new apiClient();
$client->setApplicationName(GOOGLE_APPLICATION_NAME);
$client->setScopes(array(
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://mail.google.com/',
));
$client->setClientId(GOOGLE_CLIENT_ID);
$client->setClientSecret(GOOGLE_CLIENT_SECRET);
$client->setRedirectUri(GOOGLE_REDIRECT_URL);
$client->setDeveloperKey(GOOGLE_DEVELOPER_KEY);
$this->data['auth_url'] = $client->createAuthUrl();
}
$this->render();
}

View File

@ -0,0 +1,371 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
// Check for the required json and curl extensions, the Google API PHP Client won't function without them.
if (! function_exists('curl_init')) {
throw new Exception('Google PHP API Client requires the CURL PHP extension');
}
if (! function_exists('json_decode')) {
throw new Exception('Google PHP API Client requires the JSON PHP extension');
}
if (! function_exists('http_build_query')) {
throw new Exception('Google PHP API Client requires http_build_query()');
}
if (! ini_get('date.timezone') && function_exists('date_default_timezone_set')) {
date_default_timezone_set('UTC');
}
// hack around with the include paths a bit so the library 'just works'
$cwd = dirname(__FILE__);
set_include_path("$cwd" . PATH_SEPARATOR . get_include_path());
require_once "config.php";
// If a local configuration file is found, merge it's values with the default configuration
if (file_exists($cwd . '/local_config.php')) {
$defaultConfig = $apiConfig;
require_once ($cwd . '/local_config.php');
$apiConfig = array_merge($defaultConfig, $apiConfig);
}
// Include the top level classes, they each include their own dependencies
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
require_once 'auth/apiAuth.php';
require_once 'cache/apiCache.php';
require_once 'io/apiIO.php';
require_once('service/apiMediaFileUpload.php');
/**
* The Google API Client
* http://code.google.com/p/google-api-php-client/
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*/
class apiClient {
// the version of the discovery mechanism this class is meant to work with
const discoveryVersion = 'v0.3';
/**
* @static
* @var apiAuth $auth
*/
static $auth;
/** @var apiIo $io */
static $io;
/** @var apiCache $cache */
static $cache;
/** @var array $scopes */
protected $scopes = array();
/** @var bool $useObjects */
protected $useObjects = false;
// definitions of services that are discovered.
protected $services = array();
// Used to track authenticated state, can't discover services after doing authenticate()
private $authenticated = false;
private $defaultService = array(
'authorization_token_url' => 'https://www.google.com/accounts/OAuthAuthorizeToken',
'request_token_url' => 'https://www.google.com/accounts/OAuthGetRequestToken',
'access_token_url' => 'https://www.google.com/accounts/OAuthGetAccessToken');
public function __construct($config = array()) {
global $apiConfig;
$apiConfig = array_merge($apiConfig, $config);
self::$cache = new $apiConfig['cacheClass']();
self::$auth = new $apiConfig['authClass']();
self::$io = new $apiConfig['ioClass']();
}
public function discover($service, $version = 'v1') {
$this->addService($service, $version);
$this->$service = $this->discoverService($service, $this->services[$service]['discoveryURI']);
return $this->$service;
}
/**
* Add a service
*/
public function addService($service, $version) {
global $apiConfig;
if ($this->authenticated) {
// Adding services after being authenticated, since the oauth scope is already set (so you wouldn't have access to that data)
throw new apiException('Cant add services after having authenticated');
}
$this->services[$service] = $this->defaultService;
if (isset($apiConfig['services'][$service])) {
// Merge the service descriptor with the default values
$this->services[$service] = array_merge($this->services[$service], $apiConfig['services'][$service]);
}
$this->services[$service]['discoveryURI'] = $apiConfig['basePath'] . '/discovery/' . self::discoveryVersion . '/describe/' . urlencode($service) . '/' . urlencode($version);
}
/**
* Set the type of Auth class the client should use.
* @param string $authClassName
*/
public function setAuthClass($authClassName) {
self::$auth = new $authClassName();
}
public function authenticate() {
$service = $this->prepareService();
$this->authenticated = true;
return self::$auth->authenticate($service);
}
/**
* Construct the OAuth 2.0 authorization request URI.
* @return string
*/
public function createAuthUrl() {
$service = $this->prepareService();
return self::$auth->createAuthUrl($service['scope']);
}
private function prepareService() {
$service = $this->defaultService;
$scopes = array();
if ($this->scopes) {
$scopes = $this->scopes;
} else {
foreach ($this->services as $key => $val) {
if (isset($val['scope'])) {
if (is_array($val['scope'])) {
$scopes = array_merge($val['scope'], $scopes);
} else {
$scopes[] = $val['scope'];
}
} else {
$scopes[] = 'https://www.googleapis.com/auth/' . $key;
}
unset($val['discoveryURI']);
unset($val['scope']);
$service = array_merge($service, $val);
}
}
$service['scope'] = implode(' ', $scopes);
return $service;
}
/**
* Set the OAuth 2.0 access token using the string that resulted from calling authenticate()
* or apiClient#getAccessToken().
* @param string $accessToken JSON encoded string containing in the following format:
* {"access_token":"TOKEN", "refresh_token":"TOKEN", "token_type":"Bearer",
* "expires_in":3600, "id_token":"TOKEN", "created":1320790426}
*/
public function setAccessToken($accessToken) {
if ($accessToken == null || 'null' == $accessToken) {
$accessToken = null;
}
self::$auth->setAccessToken($accessToken);
}
/**
* Get the OAuth 2.0 access token.
* @return string $accessToken JSON encoded string in the following format:
* {"access_token":"TOKEN", "refresh_token":"TOKEN", "token_type":"Bearer",
* "expires_in":3600,"id_token":"TOKEN", "created":1320790426}
*/
public function getAccessToken() {
$token = self::$auth->getAccessToken();
return (null == $token || 'null' == $token) ? null : $token;
}
/**
* Set the developer key to use, these are obtained through the API Console.
* @see http://code.google.com/apis/console-help/#generatingdevkeys
* @param string $developerKey
*/
public function setDeveloperKey($developerKey) {
self::$auth->setDeveloperKey($developerKey);
}
/**
* Set OAuth 2.0 "state" parameter to achieve per-request customization.
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
* @param string $state
*/
public function setState($state) {
self::$auth->setState($state);
}
/**
* @param string $accessType Possible values for access_type include:
* {@code "offline"} to request offline access from the user. (This is the default value)
* {@code "online"} to request online access from the user.
*/
public function setAccessType($accessType) {
self::$auth->setAccessType($accessType);
}
/**
* @param string $approvalPrompt Possible values for approval_prompt include:
* {@code "force"} to force the approval UI to appear. (This is the default value)
* {@code "auto"} to request auto-approval when possible.
*/
public function setApprovalPrompt($approvalPrompt) {
self::$auth->setApprovalPrompt($approvalPrompt);
}
/**
* Set the application name, this is included in the User-Agent HTTP header.
* @param string $applicationName
*/
public function setApplicationName($applicationName) {
global $apiConfig;
$apiConfig['application_name'] = $applicationName;
}
/**
* Set the OAuth 2.0 Client ID.
* @param string $clientId
*/
public function setClientId($clientId) {
global $apiConfig;
$apiConfig['oauth2_client_id'] = $clientId;
self::$auth->clientId = $clientId;
}
/**
* Set the OAuth 2.0 Client Secret.
* @param string $clientSecret
*/
public function setClientSecret($clientSecret) {
global $apiConfig;
$apiConfig['oauth2_client_secret'] = $clientSecret;
self::$auth->clientSecret = $clientSecret;
}
/**
* Set the OAuth 2.0 Redirect URI.
* @param string $redirectUri
*/
public function setRedirectUri($redirectUri) {
global $apiConfig;
$apiConfig['oauth2_redirect_uri'] = $redirectUri;
self::$auth->redirectUri = $redirectUri;
}
/**
* Fetches a fresh OAuth 2.0 access token with the given refresh token.
* @param string $refreshToken
* @return void
*/
public function refreshToken($refreshToken) {
self::$auth->refreshToken($refreshToken);
}
/**
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
* token, if a token isn't provided.
* @throws apiAuthException
* @param string|null $token The token (access token or a refresh token) that should be revoked.
* @return boolean Returns True if the revocation was successful, otherwise False.
*/
public function revokeToken($token = null) {
self::$auth->revokeToken($token);
}
/**
* Verify an id_token. This method will verify the current id_token, if one
* isn't provided.
* @throws apiAuthException
* @param string|null $token The token (id_token) that should be verified.
* @return apiLoginTicket Returns an apiLoginTicket if the verification was
* successful.
*/
public function verifyIdToken($token = null) {
return self::$auth->verifyIdToken($token);
}
/**
* This function allows you to overrule the automatically generated scopes,
* so that you can ask for more or less permission in the auth flow
* Set this before you call authenticate() though!
* @param array $scopes, ie: array('https://www.googleapis.com/auth/plus', 'https://www.googleapis.com/auth/moderator')
*/
public function setScopes($scopes) {
$this->scopes = is_string($scopes) ? explode(" ", $scopes) : $scopes;
}
/**
* Declare if objects should be returned by the api service classes.
*
* @param boolean $useObjects True if objects should be returned by the service classes.
* False if associative arrays should be returned (default behavior).
*/
public function setUseObjects($useObjects) {
global $apiConfig;
$apiConfig['use_objects'] = $useObjects;
}
private function discoverService($serviceName, $serviceURI) {
$request = self::$io->makeRequest(new apiHttpRequest($serviceURI));
if ($request->getResponseHttpCode() != 200) {
throw new apiException("Could not fetch discovery document for $serviceName, code: "
. $request->getResponseHttpCode() . ", response: " . $request->getResponseBody());
}
$discoveryResponse = $request->getResponseBody();
$discoveryDocument = json_decode($discoveryResponse, true);
if ($discoveryDocument == NULL) {
throw new apiException("Invalid json returned for $serviceName");
}
return new apiService($serviceName, $discoveryDocument, apiClient::getIo());
}
/**
* @static
* @return apiAuth the implementation of apiAuth.
*/
public static function getAuth() {
return apiClient::$auth;
}
/**
* @static
* @return apiIo the implementation of apiIo.
*/
public static function getIo() {
return apiClient::$io;
}
/**
* @return apiCache the implementation of apiCache.
*/
public function getCache() {
return apiClient::$cache;
}
}
// Exceptions that the Google PHP API Library can throw
class apiException extends Exception {}
class apiAuthException extends apiException {}
class apiCacheException extends apiException {}
class apiIOException extends apiException {}
class apiServiceException extends apiException {}

View File

@ -0,0 +1,37 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
require_once "apiAuthNone.php";
require_once "apiOAuth.php";
require_once "apiOAuth2.php";
/**
* Abstract class for the Authentication in the API client
* @author Chris Chabot <chabotc@google.com>
*
*/
abstract class apiAuth {
abstract public function authenticate($service);
abstract public function sign(apiHttpRequest $request);
abstract public function createAuthUrl($scope);
abstract public function getAccessToken();
abstract public function setAccessToken($accessToken);
abstract public function setDeveloperKey($developerKey);
abstract public function refreshToken($refreshToken);
abstract public function revokeToken();
}

View File

@ -0,0 +1,48 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
/**
* Do-nothing authentication implementation, use this if you want to make un-authenticated calls
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*/
class apiAuthNone extends apiAuth {
public $key = null;
public function __construct() {
global $apiConfig;
if (!empty($apiConfig['developer_key'])) {
$this->setDeveloperKey($apiConfig['developer_key']);
}
}
public function setDeveloperKey($key) {$this->key = $key;}
public function authenticate($service) {/*noop*/}
public function setAccessToken($accessToken) {/* noop*/}
public function getAccessToken() {return null;}
public function createAuthUrl($scope) {return null;}
public function refreshToken($refreshToken) {/* noop*/}
public function revokeToken() {/* noop*/}
public function sign(apiHttpRequest $request) {
if ($this->key) {
$request->setUrl($request->getUrl() . ((strpos($request->getUrl(), '?') === false) ? '?' : '&')
. 'key='.urlencode($this->key));
}
return $request;
}
}

View File

@ -0,0 +1,60 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
/**
* Class to hold information about an authenticated login.
*
* @author Brian Eaton <beaton@google.com>
*/
class apiLoginTicket {
const USER_ATTR = "id";
// Information from id token envelope.
private $envelope;
// Information from id token payload.
private $payload;
/**
* Creates a user based on the supplied token.
*
* envelope: header from a verified authentication token.
* payload: information from a verified authentication token.
*/
public function __construct($envelope, $payload) {
$this->envelope = $envelope;
$this->payload = $payload;
}
/**
* Returns the numeric identifier for the user.
*/
public function getUserId() {
if (array_key_exists(self::USER_ATTR, $this->payload)) {
return $this->payload[self::USER_ATTR];
}
throw new apiAuthException("No user_id in token");
}
/**
* Returns attributes from the login ticket. This can contain
* various information about the user session.
*/
public function getAttributes() {
return array("envelope" => $this->envelope, "payload" => $this->payload);
}
}

View File

@ -0,0 +1,250 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* 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.
*/
require_once "external/OAuth.php";
/**
* Authentication class that deals with 3-Legged OAuth 1.0a authentication
*
* This class uses the OAuth 1.0a spec which has a slightly different work flow in
* how callback urls, request & access tokens are dealt with to prevent a possible
* man in the middle attack.
*
* @author Chris Chabot <chabotc@google.com>
*
*/
class apiOAuth extends apiAuth {
public $cacheKey;
protected $consumerToken;
protected $accessToken;
protected $privateKeyFile;
protected $developerKey;
public $service;
/**
* Instantiates the class, but does not initiate the login flow, leaving it
* to the discretion of the caller.
*/
public function __construct() {
global $apiConfig;
if (!empty($apiConfig['developer_key'])) {
$this->setDeveloperKey($apiConfig['developer_key']);
}
$this->consumerToken = new apiClientOAuthConsumer($apiConfig['oauth_consumer_key'], $apiConfig['oauth_consumer_secret'], NULL);
$this->signatureMethod = new apiClientOAuthSignatureMethod_HMAC_SHA1();
$this->cacheKey = 'OAuth:' . $apiConfig['oauth_consumer_key']; // Scope data to the local user as well, or else multiple local users will share the same OAuth credentials.
}
/**
* The 3 legged oauth class needs a way to store the access key and token
* it uses the apiCache class to do so.
*
* Constructing this class will initiate the 3 legged oauth work flow, including redirecting
* to the OAuth provider's site if required(!)
*
* @param string $consumerKey
* @param string $consumerSecret
* @return apiOAuth3Legged the logged-in provider instance
*/
public function authenticate($service) {
global $apiConfig;
$this->service = $service;
$this->service['authorization_token_url'] .= '?scope=' . apiClientOAuthUtil::urlencodeRFC3986($service['scope']) . '&domain=' . apiClientOAuthUtil::urlencodeRFC3986($apiConfig['site_name']) . '&oauth_token=';
if (isset($_GET['oauth_verifier']) && isset($_GET['oauth_token']) && isset($_GET['uid'])) {
$uid = $_GET['uid'];
$secret = apiClient::$cache->get($this->cacheKey.":nonce:" . $uid);
apiClient::$cache->delete($this->cacheKey.":nonce:" . $uid);
$token = $this->upgradeRequestToken($_GET['oauth_token'], $secret, $_GET['oauth_verifier']);
return json_encode($token);
} else {
// Initialize the OAuth dance, first request a request token, then kick the client to the authorize URL
// First we store the current URL in our cache, so that when the oauth dance is completed we can return there
$callbackUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$uid = uniqid();
$token = $this->obtainRequestToken($callbackUrl, $uid);
apiClient::$cache->set($this->cacheKey.":nonce:" . $uid, $token->secret);
$this->redirectToAuthorization($token);
}
}
/**
* Sets the internal oauth access token (which is returned by the authenticate function), a user should only
* go through the authenticate() flow once (which involces a bunch of browser redirections and authentication screens, not fun)
* and every time the user comes back the access token from the authentication() flow should be re-used (it essentially never expires)
* @param object $accessToken
*/
public function setAccessToken($accessToken) {
$accessToken = json_decode($accessToken, true);
if ($accessToken == null) {
throw new apiAuthException("Could not json decode the access token");
}
if (! isset($accessToken['key']) || ! isset($accessToken['secret'])) {
throw new apiAuthException("Invalid OAuth token, missing key and/or secret");
}
$this->accessToken = new apiClientOAuthConsumer($accessToken['key'], $accessToken['secret']);
}
/**
* Returns the current access token
*/
public function getAccessToken() {
return $this->accessToken;
}
/**
* Set the developer key to use, these are obtained through the API Console
*/
public function setDeveloperKey($developerKey) {
$this->developerKey = $developerKey;
}
/**
* Upgrades an existing request token to an access token.
*
* @param apiCache $cache cache class to use (file,apc,memcache,mysql)
* @param oauthVerifier
*/
public function upgradeRequestToken($requestToken, $requestTokenSecret, $oauthVerifier) {
$ret = $this->requestAccessToken($requestToken, $requestTokenSecret, $oauthVerifier);
$matches = array();
@parse_str($ret, $matches);
if (!isset($matches['oauth_token']) || !isset($matches['oauth_token_secret'])) {
throw new apiAuthException("Error authorizing access key (result was: {$ret})");
}
// The token was upgraded to an access token, we can now continue to use it.
$this->accessToken = new apiClientOAuthConsumer(apiClientOAuthUtil::urldecodeRFC3986($matches['oauth_token']), apiClientOAuthUtil::urldecodeRFC3986($matches['oauth_token_secret']));
return $this->accessToken;
}
/**
* Sends the actual request to exchange an existing request token for an access token.
*
* @param string $requestToken the existing request token
* @param string $requestTokenSecret the request token secret
* @return array('http_code' => HTTP response code (200, 404, 401, etc), 'data' => the html document)
*/
protected function requestAccessToken($requestToken, $requestTokenSecret, $oauthVerifier) {
$accessToken = new apiClientOAuthConsumer($requestToken, $requestTokenSecret);
$accessRequest = apiClientOAuthRequest::from_consumer_and_token($this->consumerToken, $accessToken, "GET", $this->service['access_token_url'], array('oauth_verifier' => $oauthVerifier));
$accessRequest->sign_request($this->signatureMethod, $this->consumerToken, $accessToken);
$request = apiClient::$io->makeRequest(new apiHttpRequest($accessRequest));
if ($request->getResponseHttpCode() != 200) {
throw new apiAuthException("Could not fetch access token, http code: " . $request->getResponseHttpCode() . ', response body: '. $request->getResponseBody());
}
return $request->getResponseBody();
}
/**
* Obtains a request token from the specified provider.
*/
public function obtainRequestToken($callbackUrl, $uid) {
$callbackParams = (strpos($_SERVER['REQUEST_URI'], '?') !== false ? '&' : '?') . 'uid=' . urlencode($uid);
$ret = $this->requestRequestToken($callbackUrl . $callbackParams);
$matches = array();
preg_match('/oauth_token=(.*)&oauth_token_secret=(.*)&oauth_callback_confirmed=(.*)/', $ret, $matches);
if (!is_array($matches) || count($matches) != 4) {
throw new apiAuthException("Error retrieving request key ({$ret})");
}
return new apiClientOAuthToken(apiClientOAuthUtil::urldecodeRFC3986($matches[1]), apiClientOAuthUtil::urldecodeRFC3986($matches[2]));
}
/**
* Sends the actual request to obtain a request token.
*
* @return array('http_code' => HTTP response code (200, 404, 401, etc), 'data' => the html document)
*/
protected function requestRequestToken($callbackUrl) {
$requestTokenRequest = apiClientOAuthRequest::from_consumer_and_token($this->consumerToken, NULL, "GET", $this->service['request_token_url'], array());
$requestTokenRequest->set_parameter('scope', $this->service['scope']);
$requestTokenRequest->set_parameter('oauth_callback', $callbackUrl);
$requestTokenRequest->sign_request($this->signatureMethod, $this->consumerToken, NULL);
$request = apiClient::$io->makeRequest(new apiHttpRequest($requestTokenRequest));
if ($request->getResponseHttpCode() != 200) {
throw new apiAuthException("Couldn't fetch request token, http code: " . $request->getResponseHttpCode() . ', response body: '. $request->getResponseBody());
}
return $request->getResponseBody();
}
/**
* Redirect the uset to the (provider's) authorize page, if approved it should kick the user back to the call back URL
* which hopefully means we'll end up in the constructor of this class again, but with oauth_continue=1 set
*
* @param OAuthToken $token the request token
* @param string $callbackUrl the URL to return to post-authorization (passed to login site)
*/
public function redirectToAuthorization($token) {
$authorizeRedirect = $this->service['authorization_token_url']. $token->key;
header("Location: $authorizeRedirect");
}
/**
* Sign the request using OAuth. This uses the consumer token and key
*
* @param string $method the method (get/put/delete/post)
* @param string $url the url to sign (http://site/social/rest/people/1/@me)
* @param array $params the params that should be appended to the url (count=20 fields=foo, etc)
* @param string $postBody for POST/PUT requests, the postBody is included in the signature
* @return string the signed url
*/
public function sign(apiHttpRequest $request) {
// add the developer key to the request before signing it
if ($this->developerKey) {
$request->setUrl($request->getUrl() . ((strpos($request->getUrl(), '?') === false) ? '?' : '&') . 'key='.urlencode($this->developerKey));
}
// and sign the request
$oauthRequest = apiClientOAuthRequest::from_request($request->getMethod(), $request->getBaseUrl(), $request->getQueryParams());
$params = $this->mergeParameters($request->getQueryParams());
foreach ($params as $key => $val) {
if (is_array($val)) {
$val = implode(',', $val);
}
$oauthRequest->set_parameter($key, $val);
}
$oauthRequest->sign_request($this->signatureMethod, $this->consumerToken, $this->accessToken);
$authHeaders = $oauthRequest->to_header();
$headers = $request->getHeaders();
$headers[] = $authHeaders;
$request->setHeaders($headers);
// and add the access token key to it (since it doesn't include the secret, it's still secure to store this in cache)
$request->accessKey = $this->accessToken->key;
return $request;
}
/**
* Merges the supplied parameters with reasonable defaults for 2 legged oauth. User-supplied parameters
* will have precedent over the defaults.
*
* @param array $params the user-supplied params that will be appended to the url
* @return array the combined parameters
*/
protected function mergeParameters($params) {
$defaults = array(
'oauth_nonce' => md5(microtime() . mt_rand()),
'oauth_version' => apiClientOAuthRequest::$version, 'oauth_timestamp' => time(),
'oauth_consumer_key' => $this->consumerToken->key
);
if ($this->accessToken != null) {
$params['oauth_token'] = $this->accessToken->key;
}
return array_merge($defaults, $params);
}
public function createAuthUrl($scope) {return null;}
public function refreshToken($refreshToken) {/* noop*/}
public function revokeToken() {/* noop*/}
}

View File

@ -0,0 +1,394 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* 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.
*/
require_once "apiVerifier.php";
require_once "apiLoginTicket.php";
require_once "service/apiUtils.php";
/**
* Authentication class that deals with the OAuth 2 web-server authentication flow
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*
*/
class apiOAuth2 extends apiAuth {
public $clientId;
public $clientSecret;
public $developerKey;
public $accessToken;
public $redirectUri;
public $state;
public $accessType = 'offline';
public $approvalPrompt = 'force';
const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token';
const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
const OAUTH2_FEDERATED_SIGNON_CERTS_URL = 'https://www.googleapis.com/oauth2/v1/certs';
const CLOCK_SKEW_SECS = 300; // five minutes in seconds
const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds
const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds
/**
* Instantiates the class, but does not initiate the login flow, leaving it
* to the discretion of the caller (which is done by calling authenticate()).
*/
public function __construct() {
global $apiConfig;
if (! empty($apiConfig['developer_key'])) {
$this->developerKey = $apiConfig['developer_key'];
}
if (! empty($apiConfig['oauth2_client_id'])) {
$this->clientId = $apiConfig['oauth2_client_id'];
}
if (! empty($apiConfig['oauth2_client_secret'])) {
$this->clientSecret = $apiConfig['oauth2_client_secret'];
}
if (! empty($apiConfig['oauth2_redirect_uri'])) {
$this->redirectUri = $apiConfig['oauth2_redirect_uri'];
}
if (! empty($apiConfig['oauth2_access_type'])) {
$this->accessType = $apiConfig['oauth2_access_type'];
}
if (! empty($apiConfig['oauth2_approval_prompt'])) {
$this->approvalPrompt = $apiConfig['oauth2_approval_prompt'];
}
}
/**
* @param $service
* @return string
* @throws apiAuthException
*/
public function authenticate($service) {
if (isset($_GET['code'])) {
// We got here from the redirect from a successful authorization grant, fetch the access token
$request = apiClient::$io->makeRequest(new apiHttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), array(
'code' => $_GET['code'],
'grant_type' => 'authorization_code',
'redirect_uri' => $this->redirectUri,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
)));
if ($request->getResponseHttpCode() == 200) {
$this->setAccessToken($request->getResponseBody());
$this->accessToken['created'] = time();
return $this->getAccessToken();
} else {
$response = $request->getResponseBody();
$decodedResponse = json_decode($response, true);
if ($decodedResponse != $response && $decodedResponse != null && $decodedResponse['error']) {
$response = $decodedResponse['error'];
}
throw new apiAuthException("Error fetching OAuth2 access token, message: '$response'", $request->getResponseHttpCode());
}
}
$authUrl = $this->createAuthUrl($service['scope']);
header('Location: ' . $authUrl);
}
/**
* Create a URL to obtain user authorization.
* The authorization endpoint allows the user to first
* authenticate, and then grant/deny the access request.
* @param string $scope The scope is expressed as a list of space-delimited strings.
* @return string
*/
public function createAuthUrl($scope) {
$params = array(
'response_type=code',
'redirect_uri=' . urlencode($this->redirectUri),
'client_id=' . urlencode($this->clientId),
'scope=' . urlencode($scope),
'access_type=' . urlencode($this->accessType),
'approval_prompt=' . urlencode($this->approvalPrompt)
);
if (isset($this->state)) {
$params[] = 'state=' . urlencode($this->state);
}
$params = implode('&', $params);
return self::OAUTH2_AUTH_URL . "?$params";
}
/**
* @param $accessToken
* @throws apiAuthException Thrown when $accessToken is invalid.
*/
public function setAccessToken($accessToken) {
$accessToken = json_decode($accessToken, true);
if ($accessToken == null) {
throw new apiAuthException('Could not json decode the access token');
}
if (! isset($accessToken['access_token'])) {
throw new apiAuthException("Invalid token format");
}
$this->accessToken = $accessToken;
}
public function getAccessToken() {
return json_encode($this->accessToken);
}
public function setDeveloperKey($developerKey) {
$this->developerKey = $developerKey;
}
public function setState($state) {
$this->state = $state;
}
public function setAccessType($accessType) {
$this->accessType = $accessType;
}
public function setApprovalPrompt($approvalPrompt) {
$this->approvalPrompt = $approvalPrompt;
}
/**
* Include an accessToken in a given apiHttpRequest.
* @param apiHttpRequest $request
* @return apiHttpRequest
* @throws apiAuthException
*/
public function sign(apiHttpRequest $request) {
// add the developer key to the request before signing it
if ($this->developerKey) {
$requestUrl = $request->getUrl();
$requestUrl .= (strpos($request->getUrl(), '?') === false) ? '?' : '&';
$requestUrl .= 'key=' . urlencode($this->developerKey);
$request->setUrl($requestUrl);
}
// Cannot sign the request without an OAuth access token.
if (null == $this->accessToken) {
return $request;
}
// If the token is set to expire in the next 30 seconds (or has already
// expired), refresh it and set the new token.
$expired = ($this->accessToken['created'] + ($this->accessToken['expires_in'] - 30)) < time();
if ($expired) {
if (! array_key_exists('refresh_token', $this->accessToken)) {
throw new apiAuthException("The OAuth 2.0 access token has expired, "
. "and a refresh token is not available. Refresh tokens are not "
. "returned for responses that were auto-approved.");
}
$this->refreshToken($this->accessToken['refresh_token']);
}
// Add the OAuth2 header to the request
$request->setRequestHeaders(
array('Authorization' => 'Bearer ' . $this->accessToken['access_token'])
);
return $request;
}
/**
* Fetches a fresh access token with the given refresh token.
* @param string $refreshToken
* @return void
*/
public function refreshToken($refreshToken) {
$params = array(
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'refresh_token' => $refreshToken,
'grant_type' => 'refresh_token'
);
$request = apiClient::$io->makeRequest(
new apiHttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), $params));
$code = $request->getResponseHttpCode();
$body = $request->getResponseBody();
if ($code == 200) {
$token = json_decode($body, true);
if ($token == null) {
throw new apiAuthException("Could not json decode the access token");
}
if (! isset($token['access_token']) || ! isset($token['expires_in'])) {
throw new apiAuthException("Invalid token format");
}
$this->accessToken['access_token'] = $token['access_token'];
$this->accessToken['expires_in'] = $token['expires_in'];
$this->accessToken['created'] = time();
} else {
throw new apiAuthException("Error refreshing the OAuth2 token, message: '$body'", $code);
}
}
/**
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
* token, if a token isn't provided.
* @throws apiAuthException
* @param string|null $token The token (access token or a refresh token) that should be revoked.
* @return boolean Returns True if the revocation was successful, otherwise False.
*/
public function revokeToken($token = null) {
if (!$token) {
$token = $this->accessToken['access_token'];
}
$request = new apiHttpRequest(self::OAUTH2_REVOKE_URI, 'POST', array(), "token=$token");
$response = apiClient::$io->makeRequest($request);
$code = $response->getResponseHttpCode();
if ($code == 200) {
$this->accessToken = null;
return true;
}
return false;
}
// Gets federated sign-on certificates to use for verifying identity tokens.
// Returns certs as array structure, where keys are key ids, and values
// are PEM encoded certificates.
private function getFederatedSignOnCerts() {
// This relies on makeRequest caching certificate responses.
$request = apiClient::$io->makeRequest(new apiHttpRequest(
self::OAUTH2_FEDERATED_SIGNON_CERTS_URL));
if ($request->getResponseHttpCode() == 200) {
$certs = json_decode($request->getResponseBody(), true);
if ($certs) {
return $certs;
}
}
throw new apiAuthException(
"Failed to retrieve verification certificates: '" .
$request->getResponseBody() . "'.",
$request->getResponseHttpCode());
}
/**
* Verifies an id token and returns the authenticated apiLoginTicket.
* Throws an exception if the id token is not valid.
* The audience parameter can be used to control which id tokens are
* accepted. By default, the id token must have been issued to this OAuth2 client.
*
* @param $id_token
* @param $audience
* @return apiLoginTicket
*/
public function verifyIdToken($id_token = null, $audience = null) {
if (!$id_token) {
$id_token = $this->accessToken['id_token'];
}
$certs = $this->getFederatedSignonCerts();
if (!$audience) {
$audience = $this->clientId;
}
return $this->verifySignedJwtWithCerts($id_token, $certs, $audience);
}
// Verifies the id token, returns the verified token contents.
// Visible for testing.
function verifySignedJwtWithCerts($jwt, $certs, $required_audience) {
$segments = explode(".", $jwt);
if (count($segments) != 3) {
throw new apiAuthException("Wrong number of segments in token: $jwt");
}
$signed = $segments[0] . "." . $segments[1];
$signature = apiUtils::urlSafeB64Decode($segments[2]);
// Parse envelope.
$envelope = json_decode(apiUtils::urlSafeB64Decode($segments[0]), true);
if (!$envelope) {
throw new apiAuthException("Can't parse token envelope: " . $segments[0]);
}
// Parse token
$json_body = apiUtils::urlSafeB64Decode($segments[1]);
$payload = json_decode($json_body, true);
if (!$payload) {
throw new apiAuthException("Can't parse token payload: " . $segments[1]);
}
// Check signature
$verified = false;
foreach ($certs as $keyName => $pem) {
$public_key = new apiPemVerifier($pem);
if ($public_key->verify($signed, $signature)) {
$verified = true;
break;
}
}
if (!$verified) {
throw new apiAuthException("Invalid token signature: $jwt");
}
// Check issued-at timestamp
$iat = 0;
if (array_key_exists("iat", $payload)) {
$iat = $payload["iat"];
}
if (!$iat) {
throw new apiAuthException("No issue time in token: $json_body");
}
$earliest = $iat - self::CLOCK_SKEW_SECS;
// Check expiration timestamp
$now = time();
$exp = 0;
if (array_key_exists("exp", $payload)) {
$exp = $payload["exp"];
}
if (!$exp) {
throw new apiAuthException("No expiration time in token: $json_body");
}
if ($exp >= $now + self::MAX_TOKEN_LIFETIME_SECS) {
throw new apiAuthException(
"Expiration time too far in future: $json_body");
}
$latest = $exp + self::CLOCK_SKEW_SECS;
if ($now < $earliest) {
throw new apiAuthException(
"Token used too early, $now < $earliest: $json_body");
}
if ($now > $latest) {
throw new apiAuthException(
"Token used too late, $now > $latest: $json_body");
}
// TODO(beaton): check issuer field?
// Check audience
$aud = $payload["aud"];
if ($aud != $required_audience) {
throw new apiAuthException("Wrong recipient, $aud != $required_audience: $json_body");
}
// All good.
return new apiLoginTicket($envelope, $payload);
}
}

View File

@ -0,0 +1,66 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
/**
* Signs data.
*
* Only used for testing.
*
* @author Brian Eaton <beaton@google.com>
*/
class apiP12Signer extends apiSigner {
// OpenSSL private key resource
private $privateKey;
// Creates a new signer from a .p12 file.
function __construct($p12file, $password) {
if (!function_exists('openssl_x509_read')) {
throw new Exception(
'The Google PHP API library needs the openssl PHP extension');
}
// This throws on error
$p12 = file_get_contents($p12file);
$certs = array();
if (!openssl_pkcs12_read($p12, $certs, $password)) {
throw new apiAuthException("Unable to parse $p12file. " .
"Is this a .p12 file? Is the password correct? OpenSSL error: " .
openssl_error_string());
}
// TODO(beaton): is this part of the contract for the openssl_pkcs12_read
// method? What happens if there are multiple private keys? Do we care?
if (!array_key_exists("pkey", $certs) || !$certs["pkey"]) {
throw new apiAuthException("No private key found in p12 file $p12file");
}
$this->privateKey = openssl_pkey_get_private($certs["pkey"]);
if (!$this->privateKey) {
throw new apiAuthException("Unable to load private key in $p12file");
}
}
function __destruct() {
if ($this->privateKey) {
openssl_pkey_free($this->privateKey);
}
}
function sign($data) {
if (!openssl_sign($data, $signature, $this->privateKey, "sha256")) {
throw new apiAuthException("Unable to sign data");
}
return $signature;
}
}

View File

@ -0,0 +1,61 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
/**
* Verifies signatures using PEM encoded certificates.
*
* @author Brian Eaton <beaton@google.com>
*/
class apiPemVerifier extends apiVerifier {
private $publicKey;
/**
* Constructs a verifier from the supplied PEM-encoded certificate.
*
* $pem: a PEM encoded certificate (not a file).
*/
function __construct($pem) {
if (!function_exists('openssl_x509_read')) {
throw new Exception(
'The Google PHP API library needs the openssl PHP extension');
}
$this->publicKey = openssl_x509_read($pem);
if (!$this->publicKey) {
throw new apiAuthException("Unable to parse PEM: $pem");
}
}
function __destruct() {
if ($this->publicKey) {
openssl_x509_free($this->publicKey);
}
}
/**
* Verifies the signature on data.
*
* Returns true if the signature is valid, false otherwise.
*/
function verify($data, $signature) {
$status = openssl_verify($data, $signature, $this->publicKey, "sha256");
if ($status === -1) {
throw new apiAuthException("Signature verification error: " .
openssl_error_string());
}
return $status === 1;
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
require_once "apiP12Signer.php";
/**
* Signs data.
*
* @author Brian Eaton <beaton@google.com>
*/
abstract class apiSigner {
/**
* Signs data, returns the signature as binary data.
*/
abstract public function sign($data);
}

View File

@ -0,0 +1,31 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
require_once "apiPemVerifier.php";
/**
* Verifies signatures.
*
* @author Brian Eaton <beaton@google.com>
*/
abstract class apiVerifier {
/**
* Checks a signature, returns true if the signature is correct,
* false otherwise.
*/
abstract public function verify($data, $signature);
}

97
webui/google-api/cache/apiApcCache.php vendored Normal file
View File

@ -0,0 +1,97 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
/**
* A persistent storage class based on the APC cache, which is not
* really very persistent, as soon as you restart your web server
* the storage will be wiped, however for debugging and/or speed
* it can be useful, kinda, and cache is a lot cheaper then storage.
*
* @author Chris Chabot <chabotc@google.com>
*/
class apiApcCache extends apiCache {
public function __construct() {
if (! function_exists('apc_add')) {
throw new apiCacheException("Apc functions not available");
}
}
private function isLocked($key) {
if ((@apc_fetch($key . '.lock')) === false) {
return false;
}
return true;
}
private function createLock($key) {
// the interesting thing is that this could fail if the lock was created in the meantime..
// but we'll ignore that out of convenience
@apc_add($key . '.lock', '', 5);
}
private function removeLock($key) {
// suppress all warnings, if some other process removed it that's ok too
@apc_delete($key . '.lock');
}
private function waitForLock($key) {
// 20 x 250 = 5 seconds
$tries = 20;
$cnt = 0;
do {
// 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
usleep(250);
$cnt ++;
} while ($cnt <= $tries && $this->isLocked($key));
if ($this->isLocked($key)) {
// 5 seconds passed, assume the owning process died off and remove it
$this->removeLock($key);
}
}
/**
* @inheritDoc
*/
public function get($key, $expiration = false) {
if (($ret = @apc_fetch($key)) === false) {
return false;
}
if (!$expiration || (time() - $ret['time'] > $expiration)) {
$this->delete($key);
return false;
}
return unserialize($ret['data']);
}
/**
* @inheritDoc
*/
public function set($key, $value) {
if (@apc_store($key, array('time' => time(), 'data' => serialize($value))) == false) {
throw new apiCacheException("Couldn't store data");
}
}
/**
* @inheritDoc
*/
public function delete($key) {
@apc_delete($key);
}
}

56
webui/google-api/cache/apiCache.php vendored Normal file
View File

@ -0,0 +1,56 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* 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.
*/
require_once "apiFileCache.php";
require_once "apiApcCache.php";
require_once "apiMemcacheCache.php";
/**
* Abstract storage class
*
* @author Chris Chabot <chabotc@google.com>
*/
abstract class apiCache {
/**
* Retrieves the data for the given key, or false if they
* key is unknown or expired
*
* @param String $key The key who's data to retrieve
* @param boolean|int $expiration Expiration time in seconds
*
*/
abstract function get($key, $expiration = false);
/**
* Store the key => $value set. The $value is serialized
* by this function so can be of any type
*
* @param String $key Key of the data
* @param $value the data
*/
abstract function set($key, $value);
/**
* Removes the key/data pair for the given $key
*
* @param String $key
*/
abstract function delete($key);
}

135
webui/google-api/cache/apiFileCache.php vendored Normal file
View File

@ -0,0 +1,135 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* 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.
*/
/*
* This class implements a basic on disk storage. While that does
* work quite well it's not the most elegant and scalable solution.
* It will also get you into a heap of trouble when you try to run
* this in a clustered environment. In those cases please use the
* MySql back-end
*
* @author Chris Chabot <chabotc@google.com>
*/
class apiFileCache extends apiCache {
private $path;
public function __construct() {
global $apiConfig;
$this->path = $apiConfig['ioFileCache_directory'];
}
private function isLocked($storageFile) {
// our lock file convention is simple: /the/file/path.lock
return file_exists($storageFile . '.lock');
}
private function createLock($storageFile) {
$storageDir = dirname($storageFile);
if (! is_dir($storageDir)) {
if (! @mkdir($storageDir, 0755, true)) {
// make sure the failure isn't because of a concurrency issue
if (! is_dir($storageDir)) {
throw new apiCacheException("Could not create storage directory: $storageDir");
}
}
}
@touch($storageFile . '.lock');
}
private function removeLock($storageFile) {
// suppress all warnings, if some other process removed it that's ok too
@unlink($storageFile . '.lock');
}
private function waitForLock($storageFile) {
// 20 x 250 = 5 seconds
$tries = 20;
$cnt = 0;
do {
// make sure PHP picks up on file changes. This is an expensive action but really can't be avoided
clearstatcache();
// 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
usleep(250);
$cnt ++;
} while ($cnt <= $tries && $this->isLocked($storageFile));
if ($this->isLocked($storageFile)) {
// 5 seconds passed, assume the owning process died off and remove it
$this->removeLock($storageFile);
}
}
private function getCacheDir($hash) {
// use the first 2 characters of the hash as a directory prefix
// this should prevent slowdowns due to huge directory listings
// and thus give some basic amount of scalability
return $this->path . '/' . substr($hash, 0, 2);
}
private function getCacheFile($hash) {
return $this->getCacheDir($hash) . '/' . $hash;
}
public function get($key, $expiration = false) {
$storageFile = $this->getCacheFile(md5($key));
// See if this storage file is locked, if so we wait upto 5 seconds for the lock owning process to
// complete it's work. If the lock is not released within that time frame, it's cleaned up.
// This should give us a fair amount of 'Cache Stampeding' protection
if ($this->isLocked($storageFile)) {
$this->waitForLock($storageFile);
}
if (file_exists($storageFile) && is_readable($storageFile)) {
$now = time();
if (! $expiration || (($mtime = @filemtime($storageFile)) !== false && ($now - $mtime) < $expiration)) {
if (($data = @file_get_contents($storageFile)) !== false) {
$data = unserialize($data);
return $data;
}
}
}
return false;
}
public function set($key, $value) {
$storageDir = $this->getCacheDir(md5($key));
$storageFile = $this->getCacheFile(md5($key));
if ($this->isLocked($storageFile)) {
// some other process is writing to this file too, wait until it's done to prevent hickups
$this->waitForLock($storageFile);
}
if (! is_dir($storageDir)) {
if (! @mkdir($storageDir, 0755, true)) {
throw new apiCacheException("Could not create storage directory: $storageDir");
}
}
// we serialize the whole request object, since we don't only want the
// responseContent but also the postBody used, headers, size, etc
$data = serialize($value);
$this->createLock($storageFile);
if (! @file_put_contents($storageFile, $data)) {
$this->removeLock($storageFile);
throw new apiCacheException("Could not store data in the file");
}
$this->removeLock($storageFile);
}
public function delete($key) {
$file = $this->getCacheFile(md5($key));
if (! @unlink($file)) {
throw new apiCacheException("Cache file could not be deleted");
}
}
}

View File

@ -0,0 +1,126 @@
<?php
/*
* Copyright 2008 Google Inc.
*
* 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.
*/
/**
* A persistent storage class based on the memcache, which is not
* really very persistent, as soon as you restart your memcache daemon
* the storage will be wiped, however for debugging and/or speed
* it can be useful, kinda, and cache is a lot cheaper then storage.
*
* @author Chris Chabot <chabotc@google.com>
*/
class apiMemcacheCache extends apiCache {
private $connection = false;
public function __construct() {
global $apiConfig;
if (! function_exists('memcache_connect')) {
throw new apiCacheException("Memcache functions not available");
}
$this->host = $apiConfig['ioMemCacheCache_host'];
$this->port = $apiConfig['ioMemCacheCache_port'];
if (empty($this->host) || empty($this->port)) {
throw new apiCacheException("You need to supply a valid memcache host and port");
}
}
private function isLocked($key) {
$this->check();
if ((@memcache_get($this->connection, $key . '.lock')) === false) {
return false;
}
return true;
}
private function createLock($key) {
$this->check();
// the interesting thing is that this could fail if the lock was created in the meantime..
// but we'll ignore that out of convenience
@memcache_add($this->connection, $key . '.lock', '', 0, 5);
}
private function removeLock($key) {
$this->check();
// suppress all warnings, if some other process removed it that's ok too
@memcache_delete($this->connection, $key . '.lock');
}
private function waitForLock($key) {
$this->check();
// 20 x 250 = 5 seconds
$tries = 20;
$cnt = 0;
do {
// 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
usleep(250);
$cnt ++;
} while ($cnt <= $tries && $this->isLocked($key));
if ($this->isLocked($key)) {
// 5 seconds passed, assume the owning process died off and remove it
$this->removeLock($key);
}
}
// I prefer lazy initialization since the cache isn't used every request
// so this potentially saves a lot of overhead
private function connect() {
if (! $this->connection = @memcache_pconnect($this->host, $this->port)) {
throw new apiCacheException("Couldn't connect to memcache server");
}
}
private function check() {
if (! $this->connection) {
$this->connect();
}
}
/**
* @inheritDoc
*/
public function get($key, $expiration = false) {
$this->check();
if (($ret = @memcache_get($this->connection, $key)) === false) {
return false;
}
if (! $expiration || (time() - $ret['time'] > $expiration)) {
$this->delete($key);
return false;
}
return $ret['data'];
}
/**
* @inheritDoc
*/
public function set($key, $value) {
$this->check();
// we store it with the cache_time default expiration so objects will at least get cleaned eventually.
if (@memcache_set($this->connection, $key, array('time' => time(),
'data' => $value), false) == false) {
throw new apiCacheException("Couldn't store data in cache");
}
}
/**
* @inheritDoc
*/
public function delete($key) {
$this->check();
@memcache_delete($this->connection, $key);
}
}

View File

@ -0,0 +1,92 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
global $apiConfig;
$apiConfig = array(
// True if objects should be returned by the service classes.
// False if associative arrays should be returned (default behavior).
'use_objects' => false,
// The application_name is included in the User-Agent HTTP header.
'application_name' => '',
// OAuth2 Settings, you can get these keys at https://code.google.com/apis/console
'oauth2_client_id' => '',
'oauth2_client_secret' => '',
'oauth2_redirect_uri' => '',
// The developer key, you get this at https://code.google.com/apis/console
'developer_key' => '',
// OAuth1 Settings.
// If you're using the apiOAuth auth class, it will use these values for the oauth consumer key and secret.
// See http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html for info on how to obtain those
'oauth_consumer_key' => 'anonymous',
'oauth_consumer_secret' => 'anonymous',
// Site name to show in the Google's OAuth 1 authentication screen.
'site_name' => 'www.example.org',
// Which Authentication, Storage and HTTP IO classes to use.
'authClass' => 'apiOAuth2',
'ioClass' => 'apiCurlIO',
'cacheClass' => 'apiFileCache',
// If you want to run the test suite (by running # phpunit AllTests.php in the tests/ directory), fill in the settings below
'oauth_test_token' => '', // the oauth access token to use (which you can get by runing authenticate() as the test user and copying the token value), ie '{"key":"foo","secret":"bar","callback_url":null}'
'oauth_test_user' => '', // and the user ID to use, this can either be a vanity name 'testuser' or a numberic ID '123456'
// Don't change these unless you're working against a special development or testing environment.
'basePath' => 'https://www.googleapis.com',
// IO Class dependent configuration, you only have to configure the values for the class that was configured as the ioClass above
'ioFileCache_directory' =>
(function_exists('sys_get_temp_dir') ?
sys_get_temp_dir() . '/apiClient' :
'/tmp/apiClient'),
'ioMemCacheStorage_host' => '127.0.0.1',
'ioMemcacheStorage_port' => '11211',
// Definition of service specific values like scopes, oauth token URLs, etc
'services' => array(
'analytics' => array('scope' => 'https://www.googleapis.com/auth/analytics.readonly'),
'calendar' => array(
'scope' => array(
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/calendar.readonly",
)
),
'books' => array('scope' => 'https://www.googleapis.com/auth/books'),
'latitude' => array(
'scope' => array(
'https://www.googleapis.com/auth/latitude.all.best',
'https://www.googleapis.com/auth/latitude.all.city',
)
),
'moderator' => array('scope' => 'https://www.googleapis.com/auth/moderator'),
'oauth2' => array(
'scope' => array(
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
)
),
'plus' => array('scope' => 'https://www.googleapis.com/auth/plus.me'),
'siteVerification' => array('scope' => 'https://www.googleapis.com/auth/siteverification'),
'tasks' => array('scope' => 'https://www.googleapis.com/auth/tasks'),
'urlshortener' => array('scope' => 'https://www.googleapis.com/auth/urlshortener')
)
);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,488 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "cse" collection of methods.
* Typical usage is:
* <code>
* $customsearchService = new apiCustomsearchService(...);
* $cse = $customsearchService->cse;
* </code>
*/
class CseServiceResource extends apiServiceResource {
/**
* Returns metadata about the search performed, metadata about the custom search engine used for the
* search, and the search results. (cse.list)
*
* @param string $q Query
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string sort The sort expression to apply to the results
* @opt_param string num Number of search results to return
* @opt_param string googlehost The local Google domain to use to perform the search.
* @opt_param string safe Search safety level
* @opt_param string filter Controls turning on or off the duplicate content filter.
* @opt_param string start The index of the first result to return
* @opt_param string cx The custom search engine ID to scope this search query
* @opt_param string lr The language restriction for the search results
* @opt_param string cr Country restrict(s).
* @opt_param string gl Geolocation of end user.
* @opt_param string cref The URL of a linked custom search engine
* @return Search
*/
public function listCse($q, $optParams = array()) {
$params = array('q' => $q);
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new Search($data);
} else {
return $data;
}
}
}
/**
* Service definition for Customsearch (v1).
*
* <p>
* Lets you search over a website or collection of websites
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/customsearch/v1/using_rest.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiCustomsearchService extends apiService {
public $cse;
/**
* Constructs the internal representation of the Customsearch service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/customsearch/';
$this->version = 'v1';
$this->serviceName = 'customsearch';
$apiClient->addService($this->serviceName, $this->version);
$this->cse = new CseServiceResource($this, $this->serviceName, 'cse', json_decode('{"methods": {"list": {"parameters": {"sort": {"type": "string", "location": "query"}, "filter": {"enum": ["0", "1"], "type": "string", "location": "query"}, "cx": {"type": "string", "location": "query"}, "googlehost": {"type": "string", "location": "query"}, "safe": {"default": "off", "enum": ["high", "medium", "off"], "location": "query", "type": "string"}, "q": {"required": true, "type": "string", "location": "query"}, "start": {"type": "string", "location": "query"}, "num": {"default": "10", "type": "string", "location": "query"}, "lr": {"enum": ["lang_ar", "lang_bg", "lang_ca", "lang_cs", "lang_da", "lang_de", "lang_el", "lang_en", "lang_es", "lang_et", "lang_fi", "lang_fr", "lang_hr", "lang_hu", "lang_id", "lang_is", "lang_it", "lang_iw", "lang_ja", "lang_ko", "lang_lt", "lang_lv", "lang_nl", "lang_no", "lang_pl", "lang_pt", "lang_ro", "lang_ru", "lang_sk", "lang_sl", "lang_sr", "lang_sv", "lang_tr", "lang_zh-CN", "lang_zh-TW"], "type": "string", "location": "query"}, "cr": {"type": "string", "location": "query"}, "gl": {"type": "string", "location": "query"}, "cref": {"type": "string", "location": "query"}}, "id": "search.cse.list", "httpMethod": "GET", "path": "v1", "response": {"$ref": "Search"}}}}', true));
}
}
class Context extends apiModel {
protected $__facetsType = 'ContextFacets';
protected $__facetsDataType = 'array';
public $facets;
public $title;
public function setFacets(/* array(ContextFacets) */ $facets) {
$this->assertIsArray($facets, 'ContextFacets', __METHOD__);
$this->facets = $facets;
}
public function getFacets() {
return $this->facets;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
}
class ContextFacets extends apiModel {
public $anchor;
public $label;
public function setAnchor($anchor) {
$this->anchor = $anchor;
}
public function getAnchor() {
return $this->anchor;
}
public function setLabel($label) {
$this->label = $label;
}
public function getLabel() {
return $this->label;
}
}
class Promotion extends apiModel {
public $link;
public $displayLink;
protected $__imageType = 'PromotionImage';
protected $__imageDataType = '';
public $image;
protected $__bodyLinesType = 'PromotionBodyLines';
protected $__bodyLinesDataType = 'array';
public $bodyLines;
public $title;
public function setLink($link) {
$this->link = $link;
}
public function getLink() {
return $this->link;
}
public function setDisplayLink($displayLink) {
$this->displayLink = $displayLink;
}
public function getDisplayLink() {
return $this->displayLink;
}
public function setImage(PromotionImage $image) {
$this->image = $image;
}
public function getImage() {
return $this->image;
}
public function setBodyLines(/* array(PromotionBodyLines) */ $bodyLines) {
$this->assertIsArray($bodyLines, 'PromotionBodyLines', __METHOD__);
$this->bodyLines = $bodyLines;
}
public function getBodyLines() {
return $this->bodyLines;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
}
class PromotionBodyLines extends apiModel {
public $url;
public $link;
public $title;
public function setUrl($url) {
$this->url = $url;
}
public function getUrl() {
return $this->url;
}
public function setLink($link) {
$this->link = $link;
}
public function getLink() {
return $this->link;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
}
class PromotionImage extends apiModel {
public $source;
public $width;
public $height;
public function setSource($source) {
$this->source = $source;
}
public function getSource() {
return $this->source;
}
public function setWidth($width) {
$this->width = $width;
}
public function getWidth() {
return $this->width;
}
public function setHeight($height) {
$this->height = $height;
}
public function getHeight() {
return $this->height;
}
}
class Query extends apiModel {
public $count;
public $sort;
public $outputEncoding;
public $language;
public $title;
public $googleHost;
public $safe;
public $searchTerms;
public $filter;
public $startIndex;
public $cx;
public $startPage;
public $inputEncoding;
public $cr;
public $gl;
public $totalResults;
public $cref;
public function setCount($count) {
$this->count = $count;
}
public function getCount() {
return $this->count;
}
public function setSort($sort) {
$this->sort = $sort;
}
public function getSort() {
return $this->sort;
}
public function setOutputEncoding($outputEncoding) {
$this->outputEncoding = $outputEncoding;
}
public function getOutputEncoding() {
return $this->outputEncoding;
}
public function setLanguage($language) {
$this->language = $language;
}
public function getLanguage() {
return $this->language;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
public function setGoogleHost($googleHost) {
$this->googleHost = $googleHost;
}
public function getGoogleHost() {
return $this->googleHost;
}
public function setSafe($safe) {
$this->safe = $safe;
}
public function getSafe() {
return $this->safe;
}
public function setSearchTerms($searchTerms) {
$this->searchTerms = $searchTerms;
}
public function getSearchTerms() {
return $this->searchTerms;
}
public function setFilter($filter) {
$this->filter = $filter;
}
public function getFilter() {
return $this->filter;
}
public function setStartIndex($startIndex) {
$this->startIndex = $startIndex;
}
public function getStartIndex() {
return $this->startIndex;
}
public function setCx($cx) {
$this->cx = $cx;
}
public function getCx() {
return $this->cx;
}
public function setStartPage($startPage) {
$this->startPage = $startPage;
}
public function getStartPage() {
return $this->startPage;
}
public function setInputEncoding($inputEncoding) {
$this->inputEncoding = $inputEncoding;
}
public function getInputEncoding() {
return $this->inputEncoding;
}
public function setCr($cr) {
$this->cr = $cr;
}
public function getCr() {
return $this->cr;
}
public function setGl($gl) {
$this->gl = $gl;
}
public function getGl() {
return $this->gl;
}
public function setTotalResults($totalResults) {
$this->totalResults = $totalResults;
}
public function getTotalResults() {
return $this->totalResults;
}
public function setCref($cref) {
$this->cref = $cref;
}
public function getCref() {
return $this->cref;
}
}
class Result extends apiModel {
public $kind;
public $title;
public $displayLink;
public $cacheId;
public $pagemap;
public $snippet;
public $htmlSnippet;
public $link;
public $htmlTitle;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
public function setDisplayLink($displayLink) {
$this->displayLink = $displayLink;
}
public function getDisplayLink() {
return $this->displayLink;
}
public function setCacheId($cacheId) {
$this->cacheId = $cacheId;
}
public function getCacheId() {
return $this->cacheId;
}
public function setPagemap($pagemap) {
$this->pagemap = $pagemap;
}
public function getPagemap() {
return $this->pagemap;
}
public function setSnippet($snippet) {
$this->snippet = $snippet;
}
public function getSnippet() {
return $this->snippet;
}
public function setHtmlSnippet($htmlSnippet) {
$this->htmlSnippet = $htmlSnippet;
}
public function getHtmlSnippet() {
return $this->htmlSnippet;
}
public function setLink($link) {
$this->link = $link;
}
public function getLink() {
return $this->link;
}
public function setHtmlTitle($htmlTitle) {
$this->htmlTitle = $htmlTitle;
}
public function getHtmlTitle() {
return $this->htmlTitle;
}
}
class Search extends apiModel {
protected $__promotionsType = 'Promotion';
protected $__promotionsDataType = 'array';
public $promotions;
public $kind;
protected $__urlType = 'SearchUrl';
protected $__urlDataType = '';
public $url;
protected $__itemsType = 'Result';
protected $__itemsDataType = 'array';
public $items;
protected $__contextType = 'Context';
protected $__contextDataType = '';
public $context;
protected $__queriesType = 'Query';
protected $__queriesDataType = 'map';
public $queries;
public function setPromotions(/* array(Promotion) */ $promotions) {
$this->assertIsArray($promotions, 'Promotion', __METHOD__);
$this->promotions = $promotions;
}
public function getPromotions() {
return $this->promotions;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setUrl(SearchUrl $url) {
$this->url = $url;
}
public function getUrl() {
return $this->url;
}
public function setItems(/* array(Result) */ $items) {
$this->assertIsArray($items, 'Result', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
public function setContext(Context $context) {
$this->context = $context;
}
public function getContext() {
return $this->context;
}
public function setQueries(Query $queries) {
$this->queries = $queries;
}
public function getQueries() {
return $this->queries;
}
}
class SearchUrl extends apiModel {
public $type;
public $template;
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
public function setTemplate($template) {
$this->template = $template;
}
public function getTemplate() {
return $this->template;
}
}

View File

@ -0,0 +1,166 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "text" collection of methods.
* Typical usage is:
* <code>
* $freebaseService = new apiFreebaseService(...);
* $text = $freebaseService->text;
* </code>
*/
class TextServiceResource extends apiServiceResource {
/**
* Returns blob attached to node at specified id as HTML (text.get)
*
* @param string $id The id of the item that you want data about
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string maxlength The max number of characters to return. Valid only for 'plain' format.
* @opt_param string format Sanitizing transformation.
* @return ContentserviceGet
*/
public function get($id, $optParams = array()) {
$params = array('id' => $id);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new ContentserviceGet($data);
} else {
return $data;
}
}
}
/**
* The "mqlread" collection of methods.
* Typical usage is:
* <code>
* $freebaseService = new apiFreebaseService(...);
* $mqlread = $freebaseService->mqlread;
* </code>
*/
class MqlreadServiceResource extends apiServiceResource {
/**
* Performs MQL Queries. (mqlread.mqlread)
*
* @param string $query An envelope containing a single MQL query.
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string lang The language of the results - an id of a /type/lang object.
* @opt_param bool html_escape Whether or not to escape entities.
* @opt_param string indent How many spaces to indent the json.
* @opt_param string uniqueness_failure How MQL responds to uniqueness failures.
* @opt_param string dateline The dateline that you get in a mqlwrite response to ensure consistent results.
* @opt_param string cursor The mql cursor.
* @opt_param string callback JS method name for JSONP callbacks.
* @opt_param bool cost Show the costs or not.
* @opt_param string as_of_time Run the query as it would've been run at the specified point in time.
*/
public function mqlread($query, $optParams = array()) {
$params = array('query' => $query);
$params = array_merge($params, $optParams);
$data = $this->__call('mqlread', array($params));
return $data;
}
}
/**
* The "image" collection of methods.
* Typical usage is:
* <code>
* $freebaseService = new apiFreebaseService(...);
* $image = $freebaseService->image;
* </code>
*/
class ImageServiceResource extends apiServiceResource {
/**
* Returns the scaled/cropped image attached to a freebase node. (image.image)
*
* @param string $id Freebase entity or content id, mid, or guid.
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string maxwidth Maximum width in pixels for resulting image.
* @opt_param string maxheight Maximum height in pixels for resulting image.
* @opt_param string fallbackid Use the image associated with this secondary id if no image is associated with the primary id.
* @opt_param bool pad A boolean specifying whether the resulting image should be padded up to the requested dimensions.
* @opt_param string mode Method used to scale or crop image.
*/
public function image($id, $optParams = array()) {
$params = array('id' => $id);
$params = array_merge($params, $optParams);
$data = $this->__call('image', array($params));
return $data;
}
}
/**
* Service definition for Freebase (v1).
*
* <p>
* Lets you access the Freebase repository of open data.
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://wiki.freebase.com/wiki/New_Freebase_API" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiFreebaseService extends apiService {
public $mqlread;
public $image;
public $text;
/**
* Constructs the internal representation of the Freebase service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/freebase/v1/';
$this->version = 'v1';
$this->serviceName = 'freebase';
$apiClient->addService($this->serviceName, $this->version);
$this->text = new TextServiceResource($this, $this->serviceName, 'text', json_decode('{"methods": {"get": {"parameters": {"format": {"default": "plain", "enum": ["html", "plain", "raw"], "location": "query", "type": "string"}, "id": {"repeated": true, "required": true, "type": "string", "location": "path"}, "maxlength": {"format": "uint32", "type": "integer", "location": "query"}}, "id": "freebase.text.get", "httpMethod": "GET", "path": "text{/id*}", "response": {"$ref": "ContentserviceGet"}}}}', true));
$this->mqlread = new MqlreadServiceResource($this, $this->serviceName, 'mqlread', json_decode('{"httpMethod": "GET", "parameters": {"lang": {"default": "/lang/en", "type": "string", "location": "query"}, "cursor": {"type": "string", "location": "query"}, "indent": {"format": "uint32", "default": "0", "maximum": "10", "location": "query", "type": "integer"}, "uniqueness_failure": {"default": "hard", "enum": ["hard", "soft"], "location": "query", "type": "string"}, "dateline": {"type": "string", "location": "query"}, "html_escape": {"default": "true", "type": "boolean", "location": "query"}, "callback": {"type": "string", "location": "query"}, "cost": {"default": "false", "type": "boolean", "location": "query"}, "query": {"required": true, "type": "string", "location": "query"}, "as_of_time": {"type": "string", "location": "query"}}, "path": "mqlread", "id": "freebase.mqlread"}', true));
$this->image = new ImageServiceResource($this, $this->serviceName, 'image', json_decode('{"httpMethod": "GET", "parameters": {"maxwidth": {"format": "uint32", "type": "integer", "location": "query", "maximum": "4096"}, "maxheight": {"format": "uint32", "type": "integer", "location": "query", "maximum": "4096"}, "fallbackid": {"default": "/freebase/no_image_png", "type": "string", "location": "query"}, "pad": {"default": "false", "type": "boolean", "location": "query"}, "mode": {"default": "fit", "enum": ["fill", "fillcrop", "fillcropmid", "fit"], "location": "query", "type": "string"}, "id": {"repeated": true, "required": true, "type": "string", "location": "path"}}, "path": "image{/id*}", "id": "freebase.image"}', true));
}
}
class ContentserviceGet extends apiModel {
public $result;
public function setResult($result) {
$this->result = $result;
}
public function getResult() {
return $this->result;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,287 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "currentLocation" collection of methods.
* Typical usage is:
* <code>
* $latitudeService = new apiLatitudeService(...);
* $currentLocation = $latitudeService->currentLocation;
* </code>
*/
class CurrentLocationServiceResource extends apiServiceResource {
/**
* Updates or creates the user's current location. (currentLocation.insert)
*
* @param Location $postBody
* @return Location
*/
public function insert(Location $postBody, $optParams = array()) {
$params = array('postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new Location($data);
} else {
return $data;
}
}
/**
* Returns the authenticated user's current location. (currentLocation.get)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string granularity Granularity of the requested location.
* @return Location
*/
public function get($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Location($data);
} else {
return $data;
}
}
/**
* Deletes the authenticated user's current location. (currentLocation.delete)
*
*/
public function delete($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('delete', array($params));
return $data;
}
}
/**
* The "location" collection of methods.
* Typical usage is:
* <code>
* $latitudeService = new apiLatitudeService(...);
* $location = $latitudeService->location;
* </code>
*/
class LocationServiceResource extends apiServiceResource {
/**
* Inserts or updates a location in the user's location history. (location.insert)
*
* @param Location $postBody
* @return Location
*/
public function insert(Location $postBody, $optParams = array()) {
$params = array('postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new Location($data);
} else {
return $data;
}
}
/**
* Reads a location from the user's location history. (location.get)
*
* @param string $locationId Timestamp of the location to read (ms since epoch).
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string granularity Granularity of the location to return.
* @return Location
*/
public function get($locationId, $optParams = array()) {
$params = array('locationId' => $locationId);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Location($data);
} else {
return $data;
}
}
/**
* Lists the user's location history. (location.list)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string max-results Maximum number of locations to return.
* @opt_param string max-time Maximum timestamp of locations to return (ms since epoch).
* @opt_param string min-time Minimum timestamp of locations to return (ms since epoch).
* @opt_param string granularity Granularity of the requested locations.
* @return LocationFeed
*/
public function listLocation($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new LocationFeed($data);
} else {
return $data;
}
}
/**
* Deletes a location from the user's location history. (location.delete)
*
* @param string $locationId Timestamp of the location to delete (ms since epoch).
*/
public function delete($locationId, $optParams = array()) {
$params = array('locationId' => $locationId);
$params = array_merge($params, $optParams);
$data = $this->__call('delete', array($params));
return $data;
}
}
/**
* Service definition for Latitude (v1).
*
* <p>
* Lets you read and update your current location and work with your location history
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/latitude/v1/using_rest.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiLatitudeService extends apiService {
public $currentLocation;
public $location;
/**
* Constructs the internal representation of the Latitude service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/latitude/v1/';
$this->version = 'v1';
$this->serviceName = 'latitude';
$apiClient->addService($this->serviceName, $this->version);
$this->currentLocation = new CurrentLocationServiceResource($this, $this->serviceName, 'currentLocation', json_decode('{"methods": {"insert": {"scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city", "https://www.googleapis.com/auth/latitude.current.best", "https://www.googleapis.com/auth/latitude.current.city"], "request": {"$ref": "LatitudeCurrentlocationResourceJson"}, "response": {"$ref": "LatitudeCurrentlocationResourceJson"}, "httpMethod": "POST", "path": "currentLocation", "id": "latitude.currentLocation.insert"}, "delete": {"id": "latitude.currentLocation.delete", "path": "currentLocation", "httpMethod": "DELETE", "scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city", "https://www.googleapis.com/auth/latitude.current.best", "https://www.googleapis.com/auth/latitude.current.city"]}, "get": {"scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city", "https://www.googleapis.com/auth/latitude.current.best", "https://www.googleapis.com/auth/latitude.current.city"], "parameters": {"granularity": {"type": "string", "location": "query"}}, "response": {"$ref": "LatitudeCurrentlocationResourceJson"}, "httpMethod": "GET", "path": "currentLocation", "id": "latitude.currentLocation.get"}}}', true));
$this->location = new LocationServiceResource($this, $this->serviceName, 'location', json_decode('{"methods": {"insert": {"scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city"], "request": {"$ref": "Location"}, "response": {"$ref": "Location"}, "httpMethod": "POST", "path": "location", "id": "latitude.location.insert"}, "delete": {"scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city"], "parameters": {"locationId": {"required": true, "type": "string", "location": "path"}}, "httpMethod": "DELETE", "path": "location/{locationId}", "id": "latitude.location.delete"}, "list": {"scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city"], "parameters": {"max-results": {"type": "string", "location": "query"}, "max-time": {"type": "string", "location": "query"}, "min-time": {"type": "string", "location": "query"}, "granularity": {"type": "string", "location": "query"}}, "response": {"$ref": "LocationFeed"}, "httpMethod": "GET", "path": "location", "id": "latitude.location.list"}, "get": {"scopes": ["https://www.googleapis.com/auth/latitude.all.best", "https://www.googleapis.com/auth/latitude.all.city"], "parameters": {"locationId": {"required": true, "type": "string", "location": "path"}, "granularity": {"type": "string", "location": "query"}}, "id": "latitude.location.get", "httpMethod": "GET", "path": "location/{locationId}", "response": {"$ref": "Location"}}}}', true));
}
}
class Location extends apiModel {
public $kind;
public $altitude;
public $longitude;
public $activityId;
public $latitude;
public $altitudeAccuracy;
public $timestampMs;
public $speed;
public $heading;
public $accuracy;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setAltitude($altitude) {
$this->altitude = $altitude;
}
public function getAltitude() {
return $this->altitude;
}
public function setLongitude($longitude) {
$this->longitude = $longitude;
}
public function getLongitude() {
return $this->longitude;
}
public function setActivityId($activityId) {
$this->activityId = $activityId;
}
public function getActivityId() {
return $this->activityId;
}
public function setLatitude($latitude) {
$this->latitude = $latitude;
}
public function getLatitude() {
return $this->latitude;
}
public function setAltitudeAccuracy($altitudeAccuracy) {
$this->altitudeAccuracy = $altitudeAccuracy;
}
public function getAltitudeAccuracy() {
return $this->altitudeAccuracy;
}
public function setTimestampMs($timestampMs) {
$this->timestampMs = $timestampMs;
}
public function getTimestampMs() {
return $this->timestampMs;
}
public function setSpeed($speed) {
$this->speed = $speed;
}
public function getSpeed() {
return $this->speed;
}
public function setHeading($heading) {
$this->heading = $heading;
}
public function getHeading() {
return $this->heading;
}
public function setAccuracy($accuracy) {
$this->accuracy = $accuracy;
}
public function getAccuracy() {
return $this->accuracy;
}
}
class LocationFeed extends apiModel {
protected $__itemsType = 'Location';
protected $__itemsDataType = 'array';
public $items;
public $kind;
public function setItems(/* array(Location) */ $items) {
$this->assertIsArray($items, 'Location', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,307 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "userinfo" collection of methods.
* Typical usage is:
* <code>
* $oauth2Service = new apiOauth2Service(...);
* $userinfo = $oauth2Service->userinfo;
* </code>
*/
class UserinfoServiceResource extends apiServiceResource {
/**
* (userinfo.get)
*
* @return Userinfo
*/
public function get($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Userinfo($data);
} else {
return $data;
}
}
}
/**
* The "v2" collection of methods.
* Typical usage is:
* <code>
* $oauth2Service = new apiOauth2Service(...);
* $v2 = $oauth2Service->v2;
* </code>
*/
class UserinfoV2ServiceResource extends apiServiceResource {
}
/**
* The "me" collection of methods.
* Typical usage is:
* <code>
* $oauth2Service = new apiOauth2Service(...);
* $me = $oauth2Service->me;
* </code>
*/
class UserinfoV2MeServiceResource extends apiServiceResource {
/**
* (me.get)
*
* @return Userinfo
*/
public function get($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Userinfo($data);
} else {
return $data;
}
}
}
/**
* The "tokeninfo" collection of methods.
* Typical usage is:
* <code>
* $oauth2Service = new apiOauth2Service(...);
* $tokeninfo = $oauth2Service->tokeninfo;
* </code>
*/
class TokeninfoServiceResource extends apiServiceResource {
/**
* (tokeninfo.tokeninfo)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string access_token
* @opt_param string id_token
* @return Tokeninfo
*/
public function tokeninfo($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('tokeninfo', array($params));
if ($this->useObjects()) {
return new Tokeninfo($data);
} else {
return $data;
}
}
}
/**
* Service definition for Oauth2 (v2).
*
* <p>
* OAuth2 API
* </p>
*
* <p>
* For more information about this service, see the
* <a href="" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiOauth2Service extends apiService {
public $tokeninfo;
public $userinfo;
public $userinfo_v2;
/**
* Constructs the internal representation of the Oauth2 service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/';
$this->version = 'v2';
$this->serviceName = 'oauth2';
$apiClient->addService($this->serviceName, $this->version);
$this->userinfo = new UserinfoServiceResource($this, $this->serviceName, 'userinfo', json_decode('{"methods": {"get": {"path": "oauth2/v2/userinfo", "response": {"$ref": "Userinfo"}, "httpMethod": "GET", "id": "oauth2.userinfo.get"}}}', true));
$this->userinfo_v2 = new UserinfoV2ServiceResource($this, $this->serviceName, 'v2', json_decode('{}', true));
$this->tokeninfo = new TokeninfoServiceResource($this, $this->serviceName, 'tokeninfo', json_decode('{"id": "oauth2.tokeninfo", "path": "oauth2/v2/tokeninfo", "response": {"$ref": "Tokeninfo"}, "parameters": {"access_token": {"type": "string", "location": "query"}, "id_token": {"type": "string", "location": "query"}}, "httpMethod": "GET"}', true));
}
}
class Tokeninfo extends apiModel {
public $issued_to;
public $user_id;
public $expires_in;
public $access_type;
public $audience;
public $scope;
public $email;
public $verified_email;
public function setIssued_to($issued_to) {
$this->issued_to = $issued_to;
}
public function getIssued_to() {
return $this->issued_to;
}
public function setUser_id($user_id) {
$this->user_id = $user_id;
}
public function getUser_id() {
return $this->user_id;
}
public function setExpires_in($expires_in) {
$this->expires_in = $expires_in;
}
public function getExpires_in() {
return $this->expires_in;
}
public function setAccess_type($access_type) {
$this->access_type = $access_type;
}
public function getAccess_type() {
return $this->access_type;
}
public function setAudience($audience) {
$this->audience = $audience;
}
public function getAudience() {
return $this->audience;
}
public function setScope($scope) {
$this->scope = $scope;
}
public function getScope() {
return $this->scope;
}
public function setEmail($email) {
$this->email = $email;
}
public function getEmail() {
return $this->email;
}
public function setVerified_email($verified_email) {
$this->verified_email = $verified_email;
}
public function getVerified_email() {
return $this->verified_email;
}
}
class Userinfo extends apiModel {
public $family_name;
public $name;
public $picture;
public $locale;
public $gender;
public $email;
public $birthday;
public $link;
public $given_name;
public $timezone;
public $id;
public $verified_email;
public function setFamily_name($family_name) {
$this->family_name = $family_name;
}
public function getFamily_name() {
return $this->family_name;
}
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function setPicture($picture) {
$this->picture = $picture;
}
public function getPicture() {
return $this->picture;
}
public function setLocale($locale) {
$this->locale = $locale;
}
public function getLocale() {
return $this->locale;
}
public function setGender($gender) {
$this->gender = $gender;
}
public function getGender() {
return $this->gender;
}
public function setEmail($email) {
$this->email = $email;
}
public function getEmail() {
return $this->email;
}
public function setBirthday($birthday) {
$this->birthday = $birthday;
}
public function getBirthday() {
return $this->birthday;
}
public function setLink($link) {
$this->link = $link;
}
public function getLink() {
return $this->link;
}
public function setGiven_name($given_name) {
$this->given_name = $given_name;
}
public function getGiven_name() {
return $this->given_name;
}
public function setTimezone($timezone) {
$this->timezone = $timezone;
}
public function getTimezone() {
return $this->timezone;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setVerified_email($verified_email) {
$this->verified_email = $verified_email;
}
public function getVerified_email() {
return $this->verified_email;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,482 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "pagespeedapi" collection of methods.
* Typical usage is:
* <code>
* $pagespeedonlineService = new apiPagespeedonlineService(...);
* $pagespeedapi = $pagespeedonlineService->pagespeedapi;
* </code>
*/
class PagespeedapiServiceResource extends apiServiceResource {
/**
* Runs Page Speed analysis on the page at the specified URL, and returns a Page Speed score, a list
* of suggestions to make that page faster, and other information. (pagespeedapi.runpagespeed)
*
* @param string $url The URL to fetch and analyze
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string locale The locale used to localize formatted results
* @opt_param string rule A Page Speed rule to run; if none are given, all rules are run
* @opt_param string strategy The analysis strategy to use
* @return Result
*/
public function runpagespeed($url, $optParams = array()) {
$params = array('url' => $url);
$params = array_merge($params, $optParams);
$data = $this->__call('runpagespeed', array($params));
if ($this->useObjects()) {
return new Result($data);
} else {
return $data;
}
}
}
/**
* Service definition for Pagespeedonline (v1).
*
* <p>
* Lets you analyze the performance of a web page and get tailored suggestions to make that page faster.
* </p>
*
* <p>
* For more information about this service, see the
* <a href="https://code.google.com/apis/pagespeedonline/v1/getting_started.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiPagespeedonlineService extends apiService {
public $pagespeedapi;
/**
* Constructs the internal representation of the Pagespeedonline service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/pagespeedonline/v1/';
$this->version = 'v1';
$this->serviceName = 'pagespeedonline';
$apiClient->addService($this->serviceName, $this->version);
$this->pagespeedapi = new PagespeedapiServiceResource($this, $this->serviceName, 'pagespeedapi', json_decode('{"methods": {"runpagespeed": {"parameters": {"locale": {"type": "string", "location": "query"}, "url": {"required": true, "type": "string", "location": "query"}, "rule": {"repeated": true, "type": "string", "location": "query"}, "strategy": {"enum": ["desktop", "mobile"], "type": "string", "location": "query"}}, "id": "pagespeedonline.pagespeedapi.runpagespeed", "httpMethod": "GET", "path": "runPagespeed", "response": {"$ref": "Result"}}}}', true));
}
}
class Result extends apiModel {
public $kind;
protected $__formattedResultsType = 'ResultFormattedResults';
protected $__formattedResultsDataType = '';
public $formattedResults;
public $title;
protected $__versionType = 'ResultVersion';
protected $__versionDataType = '';
public $version;
public $score;
public $responseCode;
public $invalidRules;
protected $__pageStatsType = 'ResultPageStats';
protected $__pageStatsDataType = '';
public $pageStats;
public $id;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setFormattedResults(ResultFormattedResults $formattedResults) {
$this->formattedResults = $formattedResults;
}
public function getFormattedResults() {
return $this->formattedResults;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
public function setVersion(ResultVersion $version) {
$this->version = $version;
}
public function getVersion() {
return $this->version;
}
public function setScore($score) {
$this->score = $score;
}
public function getScore() {
return $this->score;
}
public function setResponseCode($responseCode) {
$this->responseCode = $responseCode;
}
public function getResponseCode() {
return $this->responseCode;
}
public function setInvalidRules(/* array(string) */ $invalidRules) {
$this->assertIsArray($invalidRules, 'string', __METHOD__);
$this->invalidRules = $invalidRules;
}
public function getInvalidRules() {
return $this->invalidRules;
}
public function setPageStats(ResultPageStats $pageStats) {
$this->pageStats = $pageStats;
}
public function getPageStats() {
return $this->pageStats;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
}
class ResultFormattedResults extends apiModel {
public $locale;
protected $__ruleResultsType = 'ResultFormattedResultsRuleResults';
protected $__ruleResultsDataType = 'map';
public $ruleResults;
public function setLocale($locale) {
$this->locale = $locale;
}
public function getLocale() {
return $this->locale;
}
public function setRuleResults(ResultFormattedResultsRuleResults $ruleResults) {
$this->ruleResults = $ruleResults;
}
public function getRuleResults() {
return $this->ruleResults;
}
}
class ResultFormattedResultsRuleResults extends apiModel {
public $localizedRuleName;
protected $__urlBlocksType = 'ResultFormattedResultsRuleResultsUrlBlocks';
protected $__urlBlocksDataType = 'array';
public $urlBlocks;
public $ruleScore;
public $ruleImpact;
public function setLocalizedRuleName($localizedRuleName) {
$this->localizedRuleName = $localizedRuleName;
}
public function getLocalizedRuleName() {
return $this->localizedRuleName;
}
public function setUrlBlocks(/* array(ResultFormattedResultsRuleResultsUrlBlocks) */ $urlBlocks) {
$this->assertIsArray($urlBlocks, 'ResultFormattedResultsRuleResultsUrlBlocks', __METHOD__);
$this->urlBlocks = $urlBlocks;
}
public function getUrlBlocks() {
return $this->urlBlocks;
}
public function setRuleScore($ruleScore) {
$this->ruleScore = $ruleScore;
}
public function getRuleScore() {
return $this->ruleScore;
}
public function setRuleImpact($ruleImpact) {
$this->ruleImpact = $ruleImpact;
}
public function getRuleImpact() {
return $this->ruleImpact;
}
}
class ResultFormattedResultsRuleResultsUrlBlocks extends apiModel {
protected $__headerType = 'ResultFormattedResultsRuleResultsUrlBlocksHeader';
protected $__headerDataType = '';
public $header;
protected $__urlsType = 'ResultFormattedResultsRuleResultsUrlBlocksUrls';
protected $__urlsDataType = 'array';
public $urls;
public function setHeader(ResultFormattedResultsRuleResultsUrlBlocksHeader $header) {
$this->header = $header;
}
public function getHeader() {
return $this->header;
}
public function setUrls(/* array(ResultFormattedResultsRuleResultsUrlBlocksUrls) */ $urls) {
$this->assertIsArray($urls, 'ResultFormattedResultsRuleResultsUrlBlocksUrls', __METHOD__);
$this->urls = $urls;
}
public function getUrls() {
return $this->urls;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksHeader extends apiModel {
protected $__argsType = 'ResultFormattedResultsRuleResultsUrlBlocksHeaderArgs';
protected $__argsDataType = 'array';
public $args;
public $format;
public function setArgs(/* array(ResultFormattedResultsRuleResultsUrlBlocksHeaderArgs) */ $args) {
$this->assertIsArray($args, 'ResultFormattedResultsRuleResultsUrlBlocksHeaderArgs', __METHOD__);
$this->args = $args;
}
public function getArgs() {
return $this->args;
}
public function setFormat($format) {
$this->format = $format;
}
public function getFormat() {
return $this->format;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksHeaderArgs extends apiModel {
public $type;
public $value;
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
public function setValue($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksUrls extends apiModel {
protected $__detailsType = 'ResultFormattedResultsRuleResultsUrlBlocksUrlsDetails';
protected $__detailsDataType = 'array';
public $details;
protected $__resultType = 'ResultFormattedResultsRuleResultsUrlBlocksUrlsResult';
protected $__resultDataType = '';
public $result;
public function setDetails(/* array(ResultFormattedResultsRuleResultsUrlBlocksUrlsDetails) */ $details) {
$this->assertIsArray($details, 'ResultFormattedResultsRuleResultsUrlBlocksUrlsDetails', __METHOD__);
$this->details = $details;
}
public function getDetails() {
return $this->details;
}
public function setResult(ResultFormattedResultsRuleResultsUrlBlocksUrlsResult $result) {
$this->result = $result;
}
public function getResult() {
return $this->result;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksUrlsDetails extends apiModel {
protected $__argsType = 'ResultFormattedResultsRuleResultsUrlBlocksUrlsDetailsArgs';
protected $__argsDataType = 'array';
public $args;
public $format;
public function setArgs(/* array(ResultFormattedResultsRuleResultsUrlBlocksUrlsDetailsArgs) */ $args) {
$this->assertIsArray($args, 'ResultFormattedResultsRuleResultsUrlBlocksUrlsDetailsArgs', __METHOD__);
$this->args = $args;
}
public function getArgs() {
return $this->args;
}
public function setFormat($format) {
$this->format = $format;
}
public function getFormat() {
return $this->format;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksUrlsDetailsArgs extends apiModel {
public $type;
public $value;
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
public function setValue($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksUrlsResult extends apiModel {
protected $__argsType = 'ResultFormattedResultsRuleResultsUrlBlocksUrlsResultArgs';
protected $__argsDataType = 'array';
public $args;
public $format;
public function setArgs(/* array(ResultFormattedResultsRuleResultsUrlBlocksUrlsResultArgs) */ $args) {
$this->assertIsArray($args, 'ResultFormattedResultsRuleResultsUrlBlocksUrlsResultArgs', __METHOD__);
$this->args = $args;
}
public function getArgs() {
return $this->args;
}
public function setFormat($format) {
$this->format = $format;
}
public function getFormat() {
return $this->format;
}
}
class ResultFormattedResultsRuleResultsUrlBlocksUrlsResultArgs extends apiModel {
public $type;
public $value;
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
public function setValue($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
class ResultPageStats extends apiModel {
public $otherResponseBytes;
public $flashResponseBytes;
public $totalRequestBytes;
public $numberCssResources;
public $numberResources;
public $cssResponseBytes;
public $javascriptResponseBytes;
public $imageResponseBytes;
public $numberHosts;
public $numberStaticResources;
public $htmlResponseBytes;
public $numberJsResources;
public $textResponseBytes;
public function setOtherResponseBytes($otherResponseBytes) {
$this->otherResponseBytes = $otherResponseBytes;
}
public function getOtherResponseBytes() {
return $this->otherResponseBytes;
}
public function setFlashResponseBytes($flashResponseBytes) {
$this->flashResponseBytes = $flashResponseBytes;
}
public function getFlashResponseBytes() {
return $this->flashResponseBytes;
}
public function setTotalRequestBytes($totalRequestBytes) {
$this->totalRequestBytes = $totalRequestBytes;
}
public function getTotalRequestBytes() {
return $this->totalRequestBytes;
}
public function setNumberCssResources($numberCssResources) {
$this->numberCssResources = $numberCssResources;
}
public function getNumberCssResources() {
return $this->numberCssResources;
}
public function setNumberResources($numberResources) {
$this->numberResources = $numberResources;
}
public function getNumberResources() {
return $this->numberResources;
}
public function setCssResponseBytes($cssResponseBytes) {
$this->cssResponseBytes = $cssResponseBytes;
}
public function getCssResponseBytes() {
return $this->cssResponseBytes;
}
public function setJavascriptResponseBytes($javascriptResponseBytes) {
$this->javascriptResponseBytes = $javascriptResponseBytes;
}
public function getJavascriptResponseBytes() {
return $this->javascriptResponseBytes;
}
public function setImageResponseBytes($imageResponseBytes) {
$this->imageResponseBytes = $imageResponseBytes;
}
public function getImageResponseBytes() {
return $this->imageResponseBytes;
}
public function setNumberHosts($numberHosts) {
$this->numberHosts = $numberHosts;
}
public function getNumberHosts() {
return $this->numberHosts;
}
public function setNumberStaticResources($numberStaticResources) {
$this->numberStaticResources = $numberStaticResources;
}
public function getNumberStaticResources() {
return $this->numberStaticResources;
}
public function setHtmlResponseBytes($htmlResponseBytes) {
$this->htmlResponseBytes = $htmlResponseBytes;
}
public function getHtmlResponseBytes() {
return $this->htmlResponseBytes;
}
public function setNumberJsResources($numberJsResources) {
$this->numberJsResources = $numberJsResources;
}
public function getNumberJsResources() {
return $this->numberJsResources;
}
public function setTextResponseBytes($textResponseBytes) {
$this->textResponseBytes = $textResponseBytes;
}
public function getTextResponseBytes() {
return $this->textResponseBytes;
}
}
class ResultVersion extends apiModel {
public $major;
public $minor;
public function setMajor($major) {
$this->major = $major;
}
public function getMajor() {
return $this->major;
}
public function setMinor($minor) {
$this->minor = $minor;
}
public function getMinor() {
return $this->minor;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,431 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "trainedmodels" collection of methods.
* Typical usage is:
* <code>
* $predictionService = new apiPredictionService(...);
* $trainedmodels = $predictionService->trainedmodels;
* </code>
*/
class TrainedmodelsServiceResource extends apiServiceResource {
/**
* Submit model id and request a prediction (trainedmodels.predict)
*
* @param string $id The unique name for the predictive model.
* @param Input $postBody
* @return Output
*/
public function predict($id, Input $postBody, $optParams = array()) {
$params = array('id' => $id, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('predict', array($params));
if ($this->useObjects()) {
return new Output($data);
} else {
return $data;
}
}
/**
* Begin training your model. (trainedmodels.insert)
*
* @param Training $postBody
* @return Training
*/
public function insert(Training $postBody, $optParams = array()) {
$params = array('postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new Training($data);
} else {
return $data;
}
}
/**
* Check training status of your model. (trainedmodels.get)
*
* @param string $id The unique name for the predictive model.
* @return Training
*/
public function get($id, $optParams = array()) {
$params = array('id' => $id);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Training($data);
} else {
return $data;
}
}
/**
* Add new data to a trained model. (trainedmodels.update)
*
* @param string $id The unique name for the predictive model.
* @param Update $postBody
* @return Training
*/
public function update($id, Update $postBody, $optParams = array()) {
$params = array('id' => $id, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('update', array($params));
if ($this->useObjects()) {
return new Training($data);
} else {
return $data;
}
}
/**
* Delete a trained model. (trainedmodels.delete)
*
* @param string $id The unique name for the predictive model.
*/
public function delete($id, $optParams = array()) {
$params = array('id' => $id);
$params = array_merge($params, $optParams);
$data = $this->__call('delete', array($params));
return $data;
}
}
/**
* The "hostedmodels" collection of methods.
* Typical usage is:
* <code>
* $predictionService = new apiPredictionService(...);
* $hostedmodels = $predictionService->hostedmodels;
* </code>
*/
class HostedmodelsServiceResource extends apiServiceResource {
/**
* Submit input and request an output against a hosted model. (hostedmodels.predict)
*
* @param string $hostedModelName The name of a hosted model.
* @param Input $postBody
* @return Output
*/
public function predict($hostedModelName, Input $postBody, $optParams = array()) {
$params = array('hostedModelName' => $hostedModelName, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('predict', array($params));
if ($this->useObjects()) {
return new Output($data);
} else {
return $data;
}
}
}
/**
* Service definition for Prediction (v1.4).
*
* <p>
* Lets you access a cloud hosted machine learning service that makes it easy to build smart apps
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/predict/docs/developer-guide.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiPredictionService extends apiService {
public $trainedmodels;
public $hostedmodels;
/**
* Constructs the internal representation of the Prediction service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/prediction/v1.4/';
$this->version = 'v1.4';
$this->serviceName = 'prediction';
$apiClient->addService($this->serviceName, $this->version);
$this->trainedmodels = new TrainedmodelsServiceResource($this, $this->serviceName, 'trainedmodels', json_decode('{"methods": {"predict": {"scopes": ["https://www.googleapis.com/auth/prediction"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "Input"}, "id": "prediction.trainedmodels.predict", "httpMethod": "POST", "path": "trainedmodels/{id}/predict", "response": {"$ref": "Output"}}, "insert": {"scopes": ["https://www.googleapis.com/auth/prediction"], "request": {"$ref": "Training"}, "response": {"$ref": "Training"}, "httpMethod": "POST", "path": "trainedmodels", "id": "prediction.trainedmodels.insert"}, "delete": {"scopes": ["https://www.googleapis.com/auth/prediction"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "httpMethod": "DELETE", "path": "trainedmodels/{id}", "id": "prediction.trainedmodels.delete"}, "update": {"scopes": ["https://www.googleapis.com/auth/prediction"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "Update"}, "id": "prediction.trainedmodels.update", "httpMethod": "PUT", "path": "trainedmodels/{id}", "response": {"$ref": "Training"}}, "get": {"scopes": ["https://www.googleapis.com/auth/prediction"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "id": "prediction.trainedmodels.get", "httpMethod": "GET", "path": "trainedmodels/{id}", "response": {"$ref": "Training"}}}}', true));
$this->hostedmodels = new HostedmodelsServiceResource($this, $this->serviceName, 'hostedmodels', json_decode('{"methods": {"predict": {"scopes": ["https://www.googleapis.com/auth/prediction"], "parameters": {"hostedModelName": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "Input"}, "id": "prediction.hostedmodels.predict", "httpMethod": "POST", "path": "hostedmodels/{hostedModelName}/predict", "response": {"$ref": "Output"}}}}', true));
}
}
class Input extends apiModel {
protected $__inputType = 'InputInput';
protected $__inputDataType = '';
public $input;
public function setInput(InputInput $input) {
$this->input = $input;
}
public function getInput() {
return $this->input;
}
}
class InputInput extends apiModel {
public $csvInstance;
public function setCsvInstance(/* array(object) */ $csvInstance) {
$this->assertIsArray($csvInstance, 'object', __METHOD__);
$this->csvInstance = $csvInstance;
}
public function getCsvInstance() {
return $this->csvInstance;
}
}
class Output extends apiModel {
public $kind;
public $outputLabel;
public $id;
protected $__outputMultiType = 'OutputOutputMulti';
protected $__outputMultiDataType = 'array';
public $outputMulti;
public $outputValue;
public $selfLink;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setOutputLabel($outputLabel) {
$this->outputLabel = $outputLabel;
}
public function getOutputLabel() {
return $this->outputLabel;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setOutputMulti(/* array(OutputOutputMulti) */ $outputMulti) {
$this->assertIsArray($outputMulti, 'OutputOutputMulti', __METHOD__);
$this->outputMulti = $outputMulti;
}
public function getOutputMulti() {
return $this->outputMulti;
}
public function setOutputValue($outputValue) {
$this->outputValue = $outputValue;
}
public function getOutputValue() {
return $this->outputValue;
}
public function setSelfLink($selfLink) {
$this->selfLink = $selfLink;
}
public function getSelfLink() {
return $this->selfLink;
}
}
class OutputOutputMulti extends apiModel {
public $score;
public $label;
public function setScore($score) {
$this->score = $score;
}
public function getScore() {
return $this->score;
}
public function setLabel($label) {
$this->label = $label;
}
public function getLabel() {
return $this->label;
}
}
class Training extends apiModel {
public $kind;
public $storageDataLocation;
public $storagePMMLModelLocation;
protected $__dataAnalysisType = 'TrainingDataAnalysis';
protected $__dataAnalysisDataType = '';
public $dataAnalysis;
public $trainingStatus;
protected $__modelInfoType = 'TrainingModelInfo';
protected $__modelInfoDataType = '';
public $modelInfo;
public $storagePMMLLocation;
public $id;
public $selfLink;
public $utility;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setStorageDataLocation($storageDataLocation) {
$this->storageDataLocation = $storageDataLocation;
}
public function getStorageDataLocation() {
return $this->storageDataLocation;
}
public function setStoragePMMLModelLocation($storagePMMLModelLocation) {
$this->storagePMMLModelLocation = $storagePMMLModelLocation;
}
public function getStoragePMMLModelLocation() {
return $this->storagePMMLModelLocation;
}
public function setDataAnalysis(TrainingDataAnalysis $dataAnalysis) {
$this->dataAnalysis = $dataAnalysis;
}
public function getDataAnalysis() {
return $this->dataAnalysis;
}
public function setTrainingStatus($trainingStatus) {
$this->trainingStatus = $trainingStatus;
}
public function getTrainingStatus() {
return $this->trainingStatus;
}
public function setModelInfo(TrainingModelInfo $modelInfo) {
$this->modelInfo = $modelInfo;
}
public function getModelInfo() {
return $this->modelInfo;
}
public function setStoragePMMLLocation($storagePMMLLocation) {
$this->storagePMMLLocation = $storagePMMLLocation;
}
public function getStoragePMMLLocation() {
return $this->storagePMMLLocation;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setSelfLink($selfLink) {
$this->selfLink = $selfLink;
}
public function getSelfLink() {
return $this->selfLink;
}
public function setUtility(/* array(double) */ $utility) {
$this->assertIsArray($utility, 'double', __METHOD__);
$this->utility = $utility;
}
public function getUtility() {
return $this->utility;
}
}
class TrainingDataAnalysis extends apiModel {
public $warnings;
public function setWarnings(/* array(string) */ $warnings) {
$this->assertIsArray($warnings, 'string', __METHOD__);
$this->warnings = $warnings;
}
public function getWarnings() {
return $this->warnings;
}
}
class TrainingModelInfo extends apiModel {
public $confusionMatrixRowTotals;
public $numberLabels;
public $confusionMatrix;
public $meanSquaredError;
public $modelType;
public $numberInstances;
public $classWeightedAccuracy;
public $classificationAccuracy;
public function setConfusionMatrixRowTotals($confusionMatrixRowTotals) {
$this->confusionMatrixRowTotals = $confusionMatrixRowTotals;
}
public function getConfusionMatrixRowTotals() {
return $this->confusionMatrixRowTotals;
}
public function setNumberLabels($numberLabels) {
$this->numberLabels = $numberLabels;
}
public function getNumberLabels() {
return $this->numberLabels;
}
public function setConfusionMatrix($confusionMatrix) {
$this->confusionMatrix = $confusionMatrix;
}
public function getConfusionMatrix() {
return $this->confusionMatrix;
}
public function setMeanSquaredError($meanSquaredError) {
$this->meanSquaredError = $meanSquaredError;
}
public function getMeanSquaredError() {
return $this->meanSquaredError;
}
public function setModelType($modelType) {
$this->modelType = $modelType;
}
public function getModelType() {
return $this->modelType;
}
public function setNumberInstances($numberInstances) {
$this->numberInstances = $numberInstances;
}
public function getNumberInstances() {
return $this->numberInstances;
}
public function setClassWeightedAccuracy($classWeightedAccuracy) {
$this->classWeightedAccuracy = $classWeightedAccuracy;
}
public function getClassWeightedAccuracy() {
return $this->classWeightedAccuracy;
}
public function setClassificationAccuracy($classificationAccuracy) {
$this->classificationAccuracy = $classificationAccuracy;
}
public function getClassificationAccuracy() {
return $this->classificationAccuracy;
}
}
class Update extends apiModel {
public $csvInstance;
public $label;
public function setCsvInstance(/* array(object) */ $csvInstance) {
$this->assertIsArray($csvInstance, 'object', __METHOD__);
$this->csvInstance = $csvInstance;
}
public function getCsvInstance() {
return $this->csvInstance;
}
public function setLabel($label) {
$this->label = $label;
}
public function getLabel() {
return $this->label;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "webResource" collection of methods.
* Typical usage is:
* <code>
* $siteVerificationService = new apiSiteVerificationService(...);
* $webResource = $siteVerificationService->webResource;
* </code>
*/
class WebResourceServiceResource extends apiServiceResource {
/**
* Attempt verification of a website or domain. (webResource.insert)
*
* @param string $verificationMethod The method to use for verifying a site or domain.
* @param SiteVerificationWebResourceResource $postBody
* @return SiteVerificationWebResourceResource
*/
public function insert($verificationMethod, SiteVerificationWebResourceResource $postBody, $optParams = array()) {
$params = array('verificationMethod' => $verificationMethod, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new SiteVerificationWebResourceResource($data);
} else {
return $data;
}
}
/**
* Get the most current data for a website or domain. (webResource.get)
*
* @param string $id The id of a verified site or domain.
* @return SiteVerificationWebResourceResource
*/
public function get($id, $optParams = array()) {
$params = array('id' => $id);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new SiteVerificationWebResourceResource($data);
} else {
return $data;
}
}
/**
* Get the list of your verified websites and domains. (webResource.list)
*
* @return SiteVerificationWebResourceListResponse
*/
public function listWebResource($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new SiteVerificationWebResourceListResponse($data);
} else {
return $data;
}
}
/**
* Modify the list of owners for your website or domain. (webResource.update)
*
* @param string $id The id of a verified site or domain.
* @param SiteVerificationWebResourceResource $postBody
* @return SiteVerificationWebResourceResource
*/
public function update($id, SiteVerificationWebResourceResource $postBody, $optParams = array()) {
$params = array('id' => $id, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('update', array($params));
if ($this->useObjects()) {
return new SiteVerificationWebResourceResource($data);
} else {
return $data;
}
}
/**
* Modify the list of owners for your website or domain. This method supports patch semantics.
* (webResource.patch)
*
* @param string $id The id of a verified site or domain.
* @param SiteVerificationWebResourceResource $postBody
* @return SiteVerificationWebResourceResource
*/
public function patch($id, SiteVerificationWebResourceResource $postBody, $optParams = array()) {
$params = array('id' => $id, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('patch', array($params));
if ($this->useObjects()) {
return new SiteVerificationWebResourceResource($data);
} else {
return $data;
}
}
/**
* Get a verification token for placing on a website or domain. (webResource.getToken)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string verificationMethod The method to use for verifying a site or domain.
* @opt_param string identifier The URL or domain to verify.
* @opt_param string type Type of resource to verify. Can be 'site' (URL) or 'inet_domain' (domain name).
* @return SiteVerificationWebResourceGettokenResponse
*/
public function getToken($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('getToken', array($params));
if ($this->useObjects()) {
return new SiteVerificationWebResourceGettokenResponse($data);
} else {
return $data;
}
}
/**
* Relinquish ownership of a website or domain. (webResource.delete)
*
* @param string $id The id of a verified site or domain.
*/
public function delete($id, $optParams = array()) {
$params = array('id' => $id);
$params = array_merge($params, $optParams);
$data = $this->__call('delete', array($params));
return $data;
}
}
/**
* Service definition for SiteVerification (v1).
*
* <p>
* Lets you programatically verify ownership of websites or domains with Google.
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/siteverification/" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiSiteVerificationService extends apiService {
public $webResource;
/**
* Constructs the internal representation of the SiteVerification service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/siteVerification/v1/';
$this->version = 'v1';
$this->serviceName = 'siteVerification';
$apiClient->addService($this->serviceName, $this->version);
$this->webResource = new WebResourceServiceResource($this, $this->serviceName, 'webResource', json_decode('{"methods": {"insert": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "parameters": {"verificationMethod": {"required": true, "type": "string", "location": "query"}}, "request": {"$ref": "SiteVerificationWebResourceResource"}, "id": "siteVerification.webResource.insert", "httpMethod": "POST", "path": "webResource", "response": {"$ref": "SiteVerificationWebResourceResource"}}, "get": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "id": "siteVerification.webResource.get", "httpMethod": "GET", "path": "webResource/{id}", "response": {"$ref": "SiteVerificationWebResourceResource"}}, "list": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "id": "siteVerification.webResource.list", "httpMethod": "GET", "path": "webResource", "response": {"$ref": "SiteVerificationWebResourceListResponse"}}, "update": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "SiteVerificationWebResourceResource"}, "id": "siteVerification.webResource.update", "httpMethod": "PUT", "path": "webResource/{id}", "response": {"$ref": "SiteVerificationWebResourceResource"}}, "patch": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "SiteVerificationWebResourceResource"}, "id": "siteVerification.webResource.patch", "httpMethod": "PATCH", "path": "webResource/{id}", "response": {"$ref": "SiteVerificationWebResourceResource"}}, "getToken": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "parameters": {"type": {"type": "string", "location": "query"}, "identifier": {"type": "string", "location": "query"}, "verificationMethod": {"type": "string", "location": "query"}}, "response": {"$ref": "SiteVerificationWebResourceGettokenResponse"}, "httpMethod": "GET", "path": "token", "id": "siteVerification.webResource.getToken"}, "delete": {"scopes": ["https://www.googleapis.com/auth/siteverification"], "parameters": {"id": {"required": true, "type": "string", "location": "path"}}, "httpMethod": "DELETE", "path": "webResource/{id}", "id": "siteVerification.webResource.delete"}}}', true));
}
}
class SiteVerificationWebResourceGettokenRequest extends apiModel {
public $verificationMethod;
protected $__siteType = 'SiteVerificationWebResourceGettokenRequestSite';
protected $__siteDataType = '';
public $site;
public function setVerificationMethod($verificationMethod) {
$this->verificationMethod = $verificationMethod;
}
public function getVerificationMethod() {
return $this->verificationMethod;
}
public function setSite(SiteVerificationWebResourceGettokenRequestSite $site) {
$this->site = $site;
}
public function getSite() {
return $this->site;
}
}
class SiteVerificationWebResourceGettokenRequestSite extends apiModel {
public $identifier;
public $type;
public function setIdentifier($identifier) {
$this->identifier = $identifier;
}
public function getIdentifier() {
return $this->identifier;
}
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
}
class SiteVerificationWebResourceGettokenResponse extends apiModel {
public $token;
public $method;
public function setToken($token) {
$this->token = $token;
}
public function getToken() {
return $this->token;
}
public function setMethod($method) {
$this->method = $method;
}
public function getMethod() {
return $this->method;
}
}
class SiteVerificationWebResourceListResponse extends apiModel {
protected $__itemsType = 'SiteVerificationWebResourceResource';
protected $__itemsDataType = 'array';
public $items;
public function setItems(/* array(SiteVerificationWebResourceResource) */ $items) {
$this->assertIsArray($items, 'SiteVerificationWebResourceResource', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
}
class SiteVerificationWebResourceResource extends apiModel {
public $owners;
public $id;
protected $__siteType = 'SiteVerificationWebResourceResourceSite';
protected $__siteDataType = '';
public $site;
public function setOwners(/* array(string) */ $owners) {
$this->assertIsArray($owners, 'string', __METHOD__);
$this->owners = $owners;
}
public function getOwners() {
return $this->owners;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setSite(SiteVerificationWebResourceResourceSite $site) {
$this->site = $site;
}
public function getSite() {
return $this->site;
}
}
class SiteVerificationWebResourceResourceSite extends apiModel {
public $identifier;
public $type;
public function setIdentifier($identifier) {
$this->identifier = $identifier;
}
public function getIdentifier() {
return $this->identifier;
}
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
}

View File

@ -0,0 +1,571 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "tasks" collection of methods.
* Typical usage is:
* <code>
* $tasksService = new apiTasksService(...);
* $tasks = $tasksService->tasks;
* </code>
*/
class TasksServiceResource extends apiServiceResource {
/**
* Creates a new task on the specified task list. (tasks.insert)
*
* @param string $tasklist Task list identifier.
* @param Task $postBody
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string parent Parent task identifier. If the task is created at the top level, this parameter is omitted. Optional.
* @opt_param string previous Previous sibling task identifier. If the task is created at the first position among its siblings, this parameter is omitted. Optional.
* @return Task
*/
public function insert($tasklist, Task $postBody, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new Task($data);
} else {
return $data;
}
}
/**
* Returns the specified task. (tasks.get)
*
* @param string $tasklist Task list identifier.
* @param string $task Task identifier.
* @return Task
*/
public function get($tasklist, $task, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'task' => $task);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Task($data);
} else {
return $data;
}
}
/**
* Clears all completed tasks from the specified task list. The affected tasks will be marked as
* 'hidden' and no longer be returned by default when retrieving all tasks for a task list.
* (tasks.clear)
*
* @param string $tasklist Task list identifier.
*/
public function clear($tasklist, $optParams = array()) {
$params = array('tasklist' => $tasklist);
$params = array_merge($params, $optParams);
$data = $this->__call('clear', array($params));
return $data;
}
/**
* Moves the specified task to another position in the task list. This can include putting it as a
* child task under a new parent and/or move it to a different position among its sibling tasks.
* (tasks.move)
*
* @param string $tasklist Task list identifier.
* @param string $task Task identifier.
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string parent New parent task identifier. If the task is moved to the top level, this parameter is omitted. Optional.
* @opt_param string previous New previous sibling task identifier. If the task is moved to the first position among its siblings, this parameter is omitted. Optional.
* @return Task
*/
public function move($tasklist, $task, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'task' => $task);
$params = array_merge($params, $optParams);
$data = $this->__call('move', array($params));
if ($this->useObjects()) {
return new Task($data);
} else {
return $data;
}
}
/**
* Returns all tasks in the specified task list. (tasks.list)
*
* @param string $tasklist Task list identifier.
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string dueMax Upper bound for a task's due date (as a RFC 3339 timestamp) to filter by. Optional. The default is not to filter by due date.
* @opt_param bool showDeleted Flag indicating whether deleted tasks are returned in the result. Optional. The default is False.
* @opt_param string updatedMin Lower bound for a task's last modification time (as a RFC 3339 timestamp) to filter by. Optional. The default is not to filter by last modification time.
* @opt_param string completedMin Lower bound for a task's completion date (as a RFC 3339 timestamp) to filter by. Optional. The default is not to filter by completion date.
* @opt_param string maxResults Maximum number of task lists returned on one page. Optional. The default is 100.
* @opt_param bool showCompleted Flag indicating whether completed tasks are returned in the result. Optional. The default is True.
* @opt_param string pageToken Token specifying the result page to return. Optional.
* @opt_param string completedMax Upper bound for a task's completion date (as a RFC 3339 timestamp) to filter by. Optional. The default is not to filter by completion date.
* @opt_param bool showHidden Flag indicating whether hidden tasks are returned in the result. Optional. The default is False.
* @opt_param string dueMin Lower bound for a task's due date (as a RFC 3339 timestamp) to filter by. Optional. The default is not to filter by due date.
* @return Tasks
*/
public function listTasks($tasklist, $optParams = array()) {
$params = array('tasklist' => $tasklist);
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new Tasks($data);
} else {
return $data;
}
}
/**
* Updates the specified task. (tasks.update)
*
* @param string $tasklist Task list identifier.
* @param string $task Task identifier.
* @param Task $postBody
* @return Task
*/
public function update($tasklist, $task, Task $postBody, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'task' => $task, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('update', array($params));
if ($this->useObjects()) {
return new Task($data);
} else {
return $data;
}
}
/**
* Updates the specified task. This method supports patch semantics. (tasks.patch)
*
* @param string $tasklist Task list identifier.
* @param string $task Task identifier.
* @param Task $postBody
* @return Task
*/
public function patch($tasklist, $task, Task $postBody, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'task' => $task, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('patch', array($params));
if ($this->useObjects()) {
return new Task($data);
} else {
return $data;
}
}
/**
* Deletes the specified task from the task list. (tasks.delete)
*
* @param string $tasklist Task list identifier.
* @param string $task Task identifier.
*/
public function delete($tasklist, $task, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'task' => $task);
$params = array_merge($params, $optParams);
$data = $this->__call('delete', array($params));
return $data;
}
}
/**
* The "tasklists" collection of methods.
* Typical usage is:
* <code>
* $tasksService = new apiTasksService(...);
* $tasklists = $tasksService->tasklists;
* </code>
*/
class TasklistsServiceResource extends apiServiceResource {
/**
* Creates a new task list and adds it to the authenticated user's task lists. (tasklists.insert)
*
* @param TaskList $postBody
* @return TaskList
*/
public function insert(TaskList $postBody, $optParams = array()) {
$params = array('postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new TaskList($data);
} else {
return $data;
}
}
/**
* Returns the authenticated user's specified task list. (tasklists.get)
*
* @param string $tasklist Task list identifier.
* @return TaskList
*/
public function get($tasklist, $optParams = array()) {
$params = array('tasklist' => $tasklist);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new TaskList($data);
} else {
return $data;
}
}
/**
* Returns all the authenticated user's task lists. (tasklists.list)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string pageToken Token specifying the result page to return. Optional.
* @opt_param string maxResults Maximum number of task lists returned on one page. Optional. The default is 100.
* @return TaskLists
*/
public function listTasklists($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new TaskLists($data);
} else {
return $data;
}
}
/**
* Updates the authenticated user's specified task list. (tasklists.update)
*
* @param string $tasklist Task list identifier.
* @param TaskList $postBody
* @return TaskList
*/
public function update($tasklist, TaskList $postBody, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('update', array($params));
if ($this->useObjects()) {
return new TaskList($data);
} else {
return $data;
}
}
/**
* Updates the authenticated user's specified task list. This method supports patch semantics.
* (tasklists.patch)
*
* @param string $tasklist Task list identifier.
* @param TaskList $postBody
* @return TaskList
*/
public function patch($tasklist, TaskList $postBody, $optParams = array()) {
$params = array('tasklist' => $tasklist, 'postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('patch', array($params));
if ($this->useObjects()) {
return new TaskList($data);
} else {
return $data;
}
}
/**
* Deletes the authenticated user's specified task list. (tasklists.delete)
*
* @param string $tasklist Task list identifier.
*/
public function delete($tasklist, $optParams = array()) {
$params = array('tasklist' => $tasklist);
$params = array_merge($params, $optParams);
$data = $this->__call('delete', array($params));
return $data;
}
}
/**
* Service definition for Tasks (v1).
*
* <p>
* Lets you manage your tasks and task lists.
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/tasks/v1/using.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiTasksService extends apiService {
public $tasks;
public $tasklists;
/**
* Constructs the internal representation of the Tasks service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/tasks/v1/';
$this->version = 'v1';
$this->serviceName = 'tasks';
$apiClient->addService($this->serviceName, $this->version);
$this->tasks = new TasksServiceResource($this, $this->serviceName, 'tasks', json_decode('{"methods": {"insert": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}, "parent": {"type": "string", "location": "query"}, "previous": {"type": "string", "location": "query"}}, "request": {"$ref": "Task"}, "id": "tasks.tasks.insert", "httpMethod": "POST", "path": "lists/{tasklist}/tasks", "response": {"$ref": "Task"}}, "get": {"scopes": ["https://www.googleapis.com/auth/tasks", "https://www.googleapis.com/auth/tasks.readonly"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}, "task": {"required": true, "type": "string", "location": "path"}}, "id": "tasks.tasks.get", "httpMethod": "GET", "path": "lists/{tasklist}/tasks/{task}", "response": {"$ref": "Task"}}, "clear": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}}, "httpMethod": "POST", "path": "lists/{tasklist}/clear", "id": "tasks.tasks.clear"}, "move": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"previous": {"type": "string", "location": "query"}, "tasklist": {"required": true, "type": "string", "location": "path"}, "parent": {"type": "string", "location": "query"}, "task": {"required": true, "type": "string", "location": "path"}}, "id": "tasks.tasks.move", "httpMethod": "POST", "path": "lists/{tasklist}/tasks/{task}/move", "response": {"$ref": "Task"}}, "list": {"scopes": ["https://www.googleapis.com/auth/tasks", "https://www.googleapis.com/auth/tasks.readonly"], "parameters": {"dueMax": {"type": "string", "location": "query"}, "tasklist": {"required": true, "type": "string", "location": "path"}, "pageToken": {"type": "string", "location": "query"}, "updatedMin": {"type": "string", "location": "query"}, "completedMin": {"type": "string", "location": "query"}, "maxResults": {"format": "int64", "type": "string", "location": "query"}, "showCompleted": {"type": "boolean", "location": "query"}, "showDeleted": {"type": "boolean", "location": "query"}, "completedMax": {"type": "string", "location": "query"}, "showHidden": {"type": "boolean", "location": "query"}, "dueMin": {"type": "string", "location": "query"}}, "id": "tasks.tasks.list", "httpMethod": "GET", "path": "lists/{tasklist}/tasks", "response": {"$ref": "Tasks"}}, "update": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}, "task": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "Task"}, "id": "tasks.tasks.update", "httpMethod": "PUT", "path": "lists/{tasklist}/tasks/{task}", "response": {"$ref": "Task"}}, "patch": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}, "task": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "Task"}, "id": "tasks.tasks.patch", "httpMethod": "PATCH", "path": "lists/{tasklist}/tasks/{task}", "response": {"$ref": "Task"}}, "delete": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}, "task": {"required": true, "type": "string", "location": "path"}}, "httpMethod": "DELETE", "path": "lists/{tasklist}/tasks/{task}", "id": "tasks.tasks.delete"}}}', true));
$this->tasklists = new TasklistsServiceResource($this, $this->serviceName, 'tasklists', json_decode('{"methods": {"insert": {"scopes": ["https://www.googleapis.com/auth/tasks"], "request": {"$ref": "TaskList"}, "response": {"$ref": "TaskList"}, "httpMethod": "POST", "path": "users/@me/lists", "id": "tasks.tasklists.insert"}, "get": {"scopes": ["https://www.googleapis.com/auth/tasks", "https://www.googleapis.com/auth/tasks.readonly"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}}, "id": "tasks.tasklists.get", "httpMethod": "GET", "path": "users/@me/lists/{tasklist}", "response": {"$ref": "TaskList"}}, "list": {"scopes": ["https://www.googleapis.com/auth/tasks", "https://www.googleapis.com/auth/tasks.readonly"], "parameters": {"pageToken": {"type": "string", "location": "query"}, "maxResults": {"format": "int64", "type": "string", "location": "query"}}, "response": {"$ref": "TaskLists"}, "httpMethod": "GET", "path": "users/@me/lists", "id": "tasks.tasklists.list"}, "update": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "TaskList"}, "id": "tasks.tasklists.update", "httpMethod": "PUT", "path": "users/@me/lists/{tasklist}", "response": {"$ref": "TaskList"}}, "patch": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}}, "request": {"$ref": "TaskList"}, "id": "tasks.tasklists.patch", "httpMethod": "PATCH", "path": "users/@me/lists/{tasklist}", "response": {"$ref": "TaskList"}}, "delete": {"scopes": ["https://www.googleapis.com/auth/tasks"], "parameters": {"tasklist": {"required": true, "type": "string", "location": "path"}}, "httpMethod": "DELETE", "path": "users/@me/lists/{tasklist}", "id": "tasks.tasklists.delete"}}}', true));
}
}
class Task extends apiModel {
public $status;
public $kind;
public $updated;
public $parent;
protected $__linksType = 'TaskLinks';
protected $__linksDataType = 'array';
public $links;
public $title;
public $deleted;
public $completed;
public $due;
public $etag;
public $notes;
public $position;
public $hidden;
public $id;
public $selfLink;
public function setStatus($status) {
$this->status = $status;
}
public function getStatus() {
return $this->status;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setUpdated($updated) {
$this->updated = $updated;
}
public function getUpdated() {
return $this->updated;
}
public function setParent($parent) {
$this->parent = $parent;
}
public function getParent() {
return $this->parent;
}
public function setLinks(/* array(TaskLinks) */ $links) {
$this->assertIsArray($links, 'TaskLinks', __METHOD__);
$this->links = $links;
}
public function getLinks() {
return $this->links;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
public function setDeleted($deleted) {
$this->deleted = $deleted;
}
public function getDeleted() {
return $this->deleted;
}
public function setCompleted($completed) {
$this->completed = $completed;
}
public function getCompleted() {
return $this->completed;
}
public function setDue($due) {
$this->due = $due;
}
public function getDue() {
return $this->due;
}
public function setEtag($etag) {
$this->etag = $etag;
}
public function getEtag() {
return $this->etag;
}
public function setNotes($notes) {
$this->notes = $notes;
}
public function getNotes() {
return $this->notes;
}
public function setPosition($position) {
$this->position = $position;
}
public function getPosition() {
return $this->position;
}
public function setHidden($hidden) {
$this->hidden = $hidden;
}
public function getHidden() {
return $this->hidden;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setSelfLink($selfLink) {
$this->selfLink = $selfLink;
}
public function getSelfLink() {
return $this->selfLink;
}
}
class TaskLinks extends apiModel {
public $type;
public $link;
public $description;
public function setType($type) {
$this->type = $type;
}
public function getType() {
return $this->type;
}
public function setLink($link) {
$this->link = $link;
}
public function getLink() {
return $this->link;
}
public function setDescription($description) {
$this->description = $description;
}
public function getDescription() {
return $this->description;
}
}
class TaskList extends apiModel {
public $kind;
public $etag;
public $id;
public $selfLink;
public $title;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setEtag($etag) {
$this->etag = $etag;
}
public function getEtag() {
return $this->etag;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function setSelfLink($selfLink) {
$this->selfLink = $selfLink;
}
public function getSelfLink() {
return $this->selfLink;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
}
class TaskLists extends apiModel {
public $nextPageToken;
protected $__itemsType = 'TaskList';
protected $__itemsDataType = 'array';
public $items;
public $kind;
public $etag;
public function setNextPageToken($nextPageToken) {
$this->nextPageToken = $nextPageToken;
}
public function getNextPageToken() {
return $this->nextPageToken;
}
public function setItems(/* array(TaskList) */ $items) {
$this->assertIsArray($items, 'TaskList', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setEtag($etag) {
$this->etag = $etag;
}
public function getEtag() {
return $this->etag;
}
}
class Tasks extends apiModel {
public $nextPageToken;
protected $__itemsType = 'Task';
protected $__itemsDataType = 'array';
public $items;
public $kind;
public $etag;
public function setNextPageToken($nextPageToken) {
$this->nextPageToken = $nextPageToken;
}
public function getNextPageToken() {
return $this->nextPageToken;
}
public function setItems(/* array(Task) */ $items) {
$this->assertIsArray($items, 'Task', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setEtag($etag) {
$this->etag = $etag;
}
public function getEtag() {
return $this->etag;
}
}

View File

@ -0,0 +1,254 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "languages" collection of methods.
* Typical usage is:
* <code>
* $translateService = new apiTranslateService(...);
* $languages = $translateService->languages;
* </code>
*/
class LanguagesServiceResource extends apiServiceResource {
/**
* List the source/target languages supported by the API (languages.list)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string target the language and collation in which the localized results should be returned
* @return LanguagesListResponse
*/
public function listLanguages($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new LanguagesListResponse($data);
} else {
return $data;
}
}
}
/**
* The "detections" collection of methods.
* Typical usage is:
* <code>
* $translateService = new apiTranslateService(...);
* $detections = $translateService->detections;
* </code>
*/
class DetectionsServiceResource extends apiServiceResource {
/**
* Detect the language of text. (detections.list)
*
* @param string $q The text to detect
* @return DetectionsListResponse
*/
public function listDetections($q, $optParams = array()) {
$params = array('q' => $q);
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new DetectionsListResponse($data);
} else {
return $data;
}
}
}
/**
* The "translations" collection of methods.
* Typical usage is:
* <code>
* $translateService = new apiTranslateService(...);
* $translations = $translateService->translations;
* </code>
*/
class TranslationsServiceResource extends apiServiceResource {
/**
* Returns text translations from one language to another. (translations.list)
*
* @param string $q The text to translate
* @param string $target The target language into which the text should be translated
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string source The source language of the text
* @opt_param string format The format of the text
* @opt_param string cid The customization id for translate
* @return TranslationsListResponse
*/
public function listTranslations($q, $target, $optParams = array()) {
$params = array('q' => $q, 'target' => $target);
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new TranslationsListResponse($data);
} else {
return $data;
}
}
}
/**
* Service definition for Translate (v2).
*
* <p>
* Lets you translate text from one language to another
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/language/translate/v2/using_rest.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiTranslateService extends apiService {
public $languages;
public $detections;
public $translations;
/**
* Constructs the internal representation of the Translate service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/language/translate/';
$this->version = 'v2';
$this->serviceName = 'translate';
$apiClient->addService($this->serviceName, $this->version);
$this->languages = new LanguagesServiceResource($this, $this->serviceName, 'languages', json_decode('{"methods": {"list": {"parameters": {"target": {"type": "string", "location": "query"}}, "id": "language.languages.list", "httpMethod": "GET", "path": "v2/languages", "response": {"$ref": "LanguagesListResponse"}}}}', true));
$this->detections = new DetectionsServiceResource($this, $this->serviceName, 'detections', json_decode('{"methods": {"list": {"parameters": {"q": {"repeated": true, "required": true, "type": "string", "location": "query"}}, "id": "language.detections.list", "httpMethod": "GET", "path": "v2/detect", "response": {"$ref": "DetectionsListResponse"}}}}', true));
$this->translations = new TranslationsServiceResource($this, $this->serviceName, 'translations', json_decode('{"methods": {"list": {"parameters": {"q": {"repeated": true, "required": true, "type": "string", "location": "query"}, "source": {"type": "string", "location": "query"}, "cid": {"repeated": true, "type": "string", "location": "query"}, "target": {"required": true, "type": "string", "location": "query"}, "format": {"enum": ["html", "text"], "type": "string", "location": "query"}}, "id": "language.translations.list", "httpMethod": "GET", "path": "v2", "response": {"$ref": "TranslationsListResponse"}}}}', true));
}
}
class DetectionsListResponse extends apiModel {
protected $__detectionsType = 'DetectionsResourceItems';
protected $__detectionsDataType = 'array';
public $detections;
public function setDetections(/* array(DetectionsResourceItems) */ $detections) {
$this->assertIsArray($detections, 'DetectionsResourceItems', __METHOD__);
$this->detections = $detections;
}
public function getDetections() {
return $this->detections;
}
}
class DetectionsResource extends apiModel {
}
class DetectionsResourceItems extends apiModel {
public $isReliable;
public $confidence;
public $language;
public function setIsReliable($isReliable) {
$this->isReliable = $isReliable;
}
public function getIsReliable() {
return $this->isReliable;
}
public function setConfidence($confidence) {
$this->confidence = $confidence;
}
public function getConfidence() {
return $this->confidence;
}
public function setLanguage($language) {
$this->language = $language;
}
public function getLanguage() {
return $this->language;
}
}
class LanguagesListResponse extends apiModel {
protected $__languagesType = 'LanguagesResource';
protected $__languagesDataType = 'array';
public $languages;
public function setLanguages(/* array(LanguagesResource) */ $languages) {
$this->assertIsArray($languages, 'LanguagesResource', __METHOD__);
$this->languages = $languages;
}
public function getLanguages() {
return $this->languages;
}
}
class LanguagesResource extends apiModel {
public $name;
public $language;
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function setLanguage($language) {
$this->language = $language;
}
public function getLanguage() {
return $this->language;
}
}
class TranslationsListResponse extends apiModel {
protected $__translationsType = 'TranslationsResource';
protected $__translationsDataType = 'array';
public $translations;
public function setTranslations(/* array(TranslationsResource) */ $translations) {
$this->assertIsArray($translations, 'TranslationsResource', __METHOD__);
$this->translations = $translations;
}
public function getTranslations() {
return $this->translations;
}
}
class TranslationsResource extends apiModel {
public $detectedSourceLanguage;
public $translatedText;
public function setDetectedSourceLanguage($detectedSourceLanguage) {
$this->detectedSourceLanguage = $detectedSourceLanguage;
}
public function getDetectedSourceLanguage() {
return $this->detectedSourceLanguage;
}
public function setTranslatedText($translatedText) {
$this->translatedText = $translatedText;
}
public function getTranslatedText() {
return $this->translatedText;
}
}

View File

@ -0,0 +1,332 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "url" collection of methods.
* Typical usage is:
* <code>
* $urlshortenerService = new apiUrlshortenerService(...);
* $url = $urlshortenerService->url;
* </code>
*/
class UrlServiceResource extends apiServiceResource {
/**
* Creates a new short URL. (url.insert)
*
* @param Url $postBody
* @return Url
*/
public function insert(Url $postBody, $optParams = array()) {
$params = array('postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
return new Url($data);
} else {
return $data;
}
}
/**
* Retrieves a list of URLs shortened by a user. (url.list)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string start-token Token for requesting successive pages of results.
* @opt_param string projection Additional information to return.
* @return UrlHistory
*/
public function listUrl($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new UrlHistory($data);
} else {
return $data;
}
}
/**
* Expands a short URL or gets creation time and analytics. (url.get)
*
* @param string $shortUrl The short URL, including the protocol.
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string projection Additional information to return.
* @return Url
*/
public function get($shortUrl, $optParams = array()) {
$params = array('shortUrl' => $shortUrl);
$params = array_merge($params, $optParams);
$data = $this->__call('get', array($params));
if ($this->useObjects()) {
return new Url($data);
} else {
return $data;
}
}
}
/**
* Service definition for Urlshortener (v1).
*
* <p>
* Lets you create, inspect, and manage goo.gl short URLs
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/urlshortener/v1/getting_started.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiUrlshortenerService extends apiService {
public $url;
/**
* Constructs the internal representation of the Urlshortener service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/urlshortener/v1/';
$this->version = 'v1';
$this->serviceName = 'urlshortener';
$apiClient->addService($this->serviceName, $this->version);
$this->url = new UrlServiceResource($this, $this->serviceName, 'url', json_decode('{"methods": {"insert": {"scopes": ["https://www.googleapis.com/auth/urlshortener"], "request": {"$ref": "Url"}, "response": {"$ref": "Url"}, "httpMethod": "POST", "path": "url", "id": "urlshortener.url.insert"}, "list": {"scopes": ["https://www.googleapis.com/auth/urlshortener"], "parameters": {"start-token": {"type": "string", "location": "query"}, "projection": {"enum": ["ANALYTICS_CLICKS", "FULL"], "type": "string", "location": "query"}}, "response": {"$ref": "UrlHistory"}, "httpMethod": "GET", "path": "url/history", "id": "urlshortener.url.list"}, "get": {"parameters": {"shortUrl": {"required": true, "type": "string", "location": "query"}, "projection": {"enum": ["ANALYTICS_CLICKS", "ANALYTICS_TOP_STRINGS", "FULL"], "type": "string", "location": "query"}}, "id": "urlshortener.url.get", "httpMethod": "GET", "path": "url", "response": {"$ref": "Url"}}}}', true));
}
}
class AnalyticsSnapshot extends apiModel {
public $shortUrlClicks;
protected $__countriesType = 'StringCount';
protected $__countriesDataType = 'array';
public $countries;
protected $__platformsType = 'StringCount';
protected $__platformsDataType = 'array';
public $platforms;
protected $__browsersType = 'StringCount';
protected $__browsersDataType = 'array';
public $browsers;
protected $__referrersType = 'StringCount';
protected $__referrersDataType = 'array';
public $referrers;
public $longUrlClicks;
public function setShortUrlClicks($shortUrlClicks) {
$this->shortUrlClicks = $shortUrlClicks;
}
public function getShortUrlClicks() {
return $this->shortUrlClicks;
}
public function setCountries(/* array(StringCount) */ $countries) {
$this->assertIsArray($countries, 'StringCount', __METHOD__);
$this->countries = $countries;
}
public function getCountries() {
return $this->countries;
}
public function setPlatforms(/* array(StringCount) */ $platforms) {
$this->assertIsArray($platforms, 'StringCount', __METHOD__);
$this->platforms = $platforms;
}
public function getPlatforms() {
return $this->platforms;
}
public function setBrowsers(/* array(StringCount) */ $browsers) {
$this->assertIsArray($browsers, 'StringCount', __METHOD__);
$this->browsers = $browsers;
}
public function getBrowsers() {
return $this->browsers;
}
public function setReferrers(/* array(StringCount) */ $referrers) {
$this->assertIsArray($referrers, 'StringCount', __METHOD__);
$this->referrers = $referrers;
}
public function getReferrers() {
return $this->referrers;
}
public function setLongUrlClicks($longUrlClicks) {
$this->longUrlClicks = $longUrlClicks;
}
public function getLongUrlClicks() {
return $this->longUrlClicks;
}
}
class AnalyticsSummary extends apiModel {
protected $__weekType = 'AnalyticsSnapshot';
protected $__weekDataType = '';
public $week;
protected $__allTimeType = 'AnalyticsSnapshot';
protected $__allTimeDataType = '';
public $allTime;
protected $__twoHoursType = 'AnalyticsSnapshot';
protected $__twoHoursDataType = '';
public $twoHours;
protected $__dayType = 'AnalyticsSnapshot';
protected $__dayDataType = '';
public $day;
protected $__monthType = 'AnalyticsSnapshot';
protected $__monthDataType = '';
public $month;
public function setWeek(AnalyticsSnapshot $week) {
$this->week = $week;
}
public function getWeek() {
return $this->week;
}
public function setAllTime(AnalyticsSnapshot $allTime) {
$this->allTime = $allTime;
}
public function getAllTime() {
return $this->allTime;
}
public function setTwoHours(AnalyticsSnapshot $twoHours) {
$this->twoHours = $twoHours;
}
public function getTwoHours() {
return $this->twoHours;
}
public function setDay(AnalyticsSnapshot $day) {
$this->day = $day;
}
public function getDay() {
return $this->day;
}
public function setMonth(AnalyticsSnapshot $month) {
$this->month = $month;
}
public function getMonth() {
return $this->month;
}
}
class StringCount extends apiModel {
public $count;
public $id;
public function setCount($count) {
$this->count = $count;
}
public function getCount() {
return $this->count;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
}
class Url extends apiModel {
public $status;
public $kind;
public $created;
protected $__analyticsType = 'AnalyticsSummary';
protected $__analyticsDataType = '';
public $analytics;
public $longUrl;
public $id;
public function setStatus($status) {
$this->status = $status;
}
public function getStatus() {
return $this->status;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setCreated($created) {
$this->created = $created;
}
public function getCreated() {
return $this->created;
}
public function setAnalytics(AnalyticsSummary $analytics) {
$this->analytics = $analytics;
}
public function getAnalytics() {
return $this->analytics;
}
public function setLongUrl($longUrl) {
$this->longUrl = $longUrl;
}
public function getLongUrl() {
return $this->longUrl;
}
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
}
class UrlHistory extends apiModel {
public $nextPageToken;
protected $__itemsType = 'Url';
protected $__itemsDataType = 'array';
public $items;
public $kind;
public $itemsPerPage;
public $totalItems;
public function setNextPageToken($nextPageToken) {
$this->nextPageToken = $nextPageToken;
}
public function getNextPageToken() {
return $this->nextPageToken;
}
public function setItems(/* array(Url) */ $items) {
$this->assertIsArray($items, 'Url', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setItemsPerPage($itemsPerPage) {
$this->itemsPerPage = $itemsPerPage;
}
public function getItemsPerPage() {
return $this->itemsPerPage;
}
public function setTotalItems($totalItems) {
$this->totalItems = $totalItems;
}
public function getTotalItems() {
return $this->totalItems;
}
}

View File

@ -0,0 +1,138 @@
<?php
/*
* Copyright (c) 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiModel.php';
require_once 'service/apiService.php';
require_once 'service/apiServiceRequest.php';
/**
* The "webfonts" collection of methods.
* Typical usage is:
* <code>
* $webfontsService = new apiWebfontsService(...);
* $webfonts = $webfontsService->webfonts;
* </code>
*/
class WebfontsServiceResource extends apiServiceResource {
/**
* Retrieves the list of fonts currently served by the Google Web Fonts Developer API
* (webfonts.list)
*
* @param array $optParams Optional parameters. Valid optional parameters are listed below.
*
* @opt_param string sort Enables sorting of the list
* @return WebfontList
*/
public function listWebfonts($optParams = array()) {
$params = array();
$params = array_merge($params, $optParams);
$data = $this->__call('list', array($params));
if ($this->useObjects()) {
return new WebfontList($data);
} else {
return $data;
}
}
}
/**
* Service definition for Webfonts (v1).
*
* <p>
* The Google Web Fonts Developer API.
* </p>
*
* <p>
* For more information about this service, see the
* <a href="http://code.google.com/apis/webfonts/docs/developer_api.html" target="_blank">API Documentation</a>
* </p>
*
* @author Google, Inc.
*/
class apiWebfontsService extends apiService {
public $webfonts;
/**
* Constructs the internal representation of the Webfonts service.
*
* @param apiClient apiClient
*/
public function __construct(apiClient $apiClient) {
$this->rpcPath = '/rpc';
$this->restBasePath = '/webfonts/v1/';
$this->version = 'v1';
$this->serviceName = 'webfonts';
$apiClient->addService($this->serviceName, $this->version);
$this->webfonts = new WebfontsServiceResource($this, $this->serviceName, 'webfonts', json_decode('{"methods": {"list": {"parameters": {"sort": {"enum": ["alpha", "date", "popularity", "style", "trending"], "type": "string", "location": "query"}}, "id": "webfonts.webfonts.list", "httpMethod": "GET", "path": "webfonts", "response": {"$ref": "WebfontList"}}}}', true));
}
}
class Webfont extends apiModel {
public $kind;
public $variants;
public $subsets;
public $family;
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
public function setVariants($variants) {
$this->variants = $variants;
}
public function getVariants() {
return $this->variants;
}
public function setSubsets($subsets) {
$this->subsets = $subsets;
}
public function getSubsets() {
return $this->subsets;
}
public function setFamily($family) {
$this->family = $family;
}
public function getFamily() {
return $this->family;
}
}
class WebfontList extends apiModel {
protected $__itemsType = 'Webfont';
protected $__itemsDataType = 'array';
public $items;
public $kind;
public function setItems(/* array(Webfont) */ $items) {
$this->assertIsArray($items, 'Webfont', __METHOD__);
$this->items = $items;
}
public function getItems() {
return $this->items;
}
public function setKind($kind) {
$this->kind = $kind;
}
public function getKind() {
return $this->kind;
}
}

486
webui/google-api/external/OAuth.php vendored Executable file
View File

@ -0,0 +1,486 @@
<?php
/* Generic exception class
*/
class apiClientOAuthException extends Exception {
// pass
}
class apiClientOAuthConsumer {
public $key;
public $secret;
public function __construct($key, $secret, $callback_url=NULL) {
$this->key = $key;
$this->secret = $secret;
$this->callback_url = $callback_url;
}
}
class apiClientOAuthToken {
// access tokens and request tokens
public $key;
public $secret;
/**
* key = the token
* secret = the token secret
*/
function __construct($key, $secret) {
$this->key = $key;
$this->secret = $secret;
}
/**
* generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with
*/
function to_string() {
return "oauth_token=" . apiClientOAuthUtil::urlencodeRFC3986($this->key) .
"&oauth_token_secret=" . apiClientOAuthUtil::urlencodeRFC3986($this->secret);
}
function __toString() {
return $this->to_string();
}
}
class apiClientOAuthSignatureMethod {
public function check_signature(&$request, $consumer, $token, $signature) {
$built = $this->build_signature($request, $consumer, $token);
return $built == $signature;
}
}
class apiClientOAuthSignatureMethod_HMAC_SHA1 extends apiClientOAuthSignatureMethod {
function get_name() {
return "HMAC-SHA1";
}
public function build_signature($request, $consumer, $token, $privKey=NULL) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
);
$key_parts = array_map(array('apiClientOAuthUtil','urlencodeRFC3986'), $key_parts);
$key = implode('&', $key_parts);
return base64_encode( hash_hmac('sha1', $base_string, $key, true));
}
}
class apiClientOAuthSignatureMethod_RSA_SHA1 extends apiClientOAuthSignatureMethod {
public function get_name() {
return "RSA-SHA1";
}
protected function fetch_public_cert(&$request) {
// not implemented yet, ideas are:
// (1) do a lookup in a table of trusted certs keyed off of consumer
// (2) fetch via http using a url provided by the requester
// (3) some sort of specific discovery code based on request
//
// either way should return a string representation of the certificate
throw Exception("fetch_public_cert not implemented");
}
protected function fetch_private_cert($privKey) {//&$request) {
// not implemented yet, ideas are:
// (1) do a lookup in a table of trusted certs keyed off of consumer
//
// either way should return a string representation of the certificate
throw Exception("fetch_private_cert not implemented");
}
public function build_signature(&$request, $consumer, $token, $privKey) {
$base_string = $request->get_signature_base_string();
// Fetch the private key cert based on the request
//$cert = $this->fetch_private_cert($consumer->privKey);
//Pull the private key ID from the certificate
//$privatekeyid = openssl_get_privatekey($cert);
// hacked in
if ($privKey == '') {
$fp = fopen($GLOBALS['PRIV_KEY_FILE'], "r");
$privKey = fread($fp, 8192);
fclose($fp);
}
$privatekeyid = openssl_get_privatekey($privKey);
//Check the computer signature against the one passed in the query
$ok = openssl_sign($base_string, $signature, $privatekeyid);
//Release the key resource
openssl_free_key($privatekeyid);
return base64_encode($signature);
}
public function check_signature(&$request, $consumer, $token, $signature) {
$decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string();
// Fetch the public key cert based on the request
$cert = $this->fetch_public_cert($request);
//Pull the public key ID from the certificate
$publickeyid = openssl_get_publickey($cert);
//Check the computer signature against the one passed in the query
$ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
//Release the key resource
openssl_free_key($publickeyid);
return $ok == 1;
}
}
class apiClientOAuthRequest {
private $parameters;
private $http_method;
private $http_url;
// for debug purposes
public $base_string;
public static $version = '1.0';
function __construct($http_method, $http_url, $parameters=NULL) {
@$parameters or $parameters = array();
$this->parameters = $parameters;
$this->http_method = $http_method;
$this->http_url = $http_url;
}
/**
* attempt to build up a request from what was passed to the server
*/
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https';
@$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
@$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
$request_headers = apiClientOAuthRequest::get_headers();
// let the library user override things however they'd like, if they know
// which parameters to use then go for it, for example XMLRPC might want to
// do this
if ($parameters) {
$req = new apiClientOAuthRequest($http_method, $http_url, $parameters);
}
// next check for the auth header, we need to do some extra stuff
// if that is the case, namely suck in the parameters from GET or POST
// so that we can include them in the signature
else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") {
$header_parameters = apiClientOAuthRequest::split_header($request_headers['Authorization']);
if ($http_method == "GET") {
$req_parameters = $_GET;
}
else if ($http_method = "POST") {
$req_parameters = $_POST;
}
$parameters = array_merge($header_parameters, $req_parameters);
$req = new apiClientOAuthRequest($http_method, $http_url, $parameters);
}
else if ($http_method == "GET") {
$req = new apiClientOAuthRequest($http_method, $http_url, $_GET);
}
else if ($http_method == "POST") {
$req = new apiClientOAuthRequest($http_method, $http_url, $_POST);
}
return $req;
}
/**
* pretty much a helper function to set up the request
*/
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
@$parameters or $parameters = array();
$defaults = array("oauth_version" => apiClientOAuthRequest::$version,
"oauth_nonce" => apiClientOAuthRequest::generate_nonce(),
"oauth_timestamp" => apiClientOAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
$parameters = array_merge($defaults, $parameters);
if ($token) {
$parameters['oauth_token'] = $token->key;
}
// oauth v1.0a
/*if (isset($_REQUEST['oauth_verifier'])) {
$parameters['oauth_verifier'] = $_REQUEST['oauth_verifier'];
}*/
return new apiClientOAuthRequest($http_method, $http_url, $parameters);
}
public function set_parameter($name, $value) {
$this->parameters[$name] = $value;
}
public function get_parameter($name) {
return $this->parameters[$name];
}
public function get_parameters() {
return $this->parameters;
}
/**
* Returns the normalized parameters of the request
*
* This will be all (except oauth_signature) parameters,
* sorted first by key, and if duplicate keys, then by
* value.
*
* The returned string will be all the key=value pairs
* concated by &.
*
* @return string
*/
public function get_signable_parameters() {
// Grab all parameters
$params = $this->parameters;
// Remove oauth_signature if present
if (isset($params['oauth_signature'])) {
unset($params['oauth_signature']);
}
// Urlencode both keys and values
$keys = array_map(array('apiClientOAuthUtil', 'urlencodeRFC3986'), array_keys($params));
$values = array_map(array('apiClientOAuthUtil', 'urlencodeRFC3986'), array_values($params));
$params = array_combine($keys, $values);
// Sort by keys (natsort)
uksort($params, 'strnatcmp');
if(isset($params['title']) && isset($params['title-exact'])) {
$temp = $params['title-exact'];
$title = $params['title'];
unset($params['title']);
unset($params['title-exact']);
$params['title-exact'] = $temp;
$params['title'] = $title;
}
// Generate key=value pairs
$pairs = array();
foreach ($params as $key=>$value ) {
if (is_array($value)) {
// If the value is an array, it's because there are multiple
// with the same key, sort them, then add all the pairs
natsort($value);
foreach ($value as $v2) {
$pairs[] = $key . '=' . $v2;
}
} else {
$pairs[] = $key . '=' . $value;
}
}
// Return the pairs, concated with &
return implode('&', $pairs);
}
/**
* Returns the base string of this request
*
* The base string defined as the method, the url
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
public function get_signature_base_string() {
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
$this->get_signable_parameters()
);
$parts = array_map(array('apiClientOAuthUtil', 'urlencodeRFC3986'), $parts);
return implode('&', $parts);
}
/**
* just uppercases the http method
*/
public function get_normalized_http_method() {
return strtoupper($this->http_method);
}
/**
* parses the url and rebuilds it to be
* scheme://host/path
*/
public function get_normalized_http_url() {
$parts = parse_url($this->http_url);
// FIXME: port should handle according to http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226
$port = (isset($parts['port']) && $parts['port'] != '80') ? ':' . $parts['port'] : '';
$path = (isset($parts['path'])) ? $parts['path'] : '';
return $parts['scheme'] . '://' . $parts['host'] . $port . $path;
}
/**
* builds a url usable for a GET request
*/
public function to_url() {
$out = $this->get_normalized_http_url() . "?";
$out .= $this->to_postdata();
return $out;
}
/**
* builds the data one would send in a POST request
*/
public function to_postdata() {
$total = array();
foreach ($this->parameters as $k => $v) {
$total[] = apiClientOAuthUtil::urlencodeRFC3986($k) . "=" . apiClientOAuthUtil::urlencodeRFC3986($v);
}
$out = implode("&", $total);
return $out;
}
/**
* builds the Authorization: header
*/
public function to_header() {
$out ='Authorization: OAuth ';
$total = array();
foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue;
$out .= apiClientOAuthUtil::urlencodeRFC3986($k) . '="' . apiClientOAuthUtil::urlencodeRFC3986($v) . '", ';
}
$out = substr_replace($out, '', strlen($out) - 2);
return $out;
}
public function __toString() {
return $this->to_url();
}
public function sign_request($signature_method, $consumer, $token, $privKey=NULL) {
$this->set_parameter("oauth_signature_method", $signature_method->get_name());
$signature = $this->build_signature($signature_method, $consumer, $token, $privKey);
$this->set_parameter("oauth_signature", $signature);
}
public function build_signature($signature_method, $consumer, $token, $privKey=NULL) {
$signature = $signature_method->build_signature($this, $consumer, $token, $privKey);
return $signature;
}
/**
* util function: current timestamp
*/
private static function generate_timestamp() {
return time();
}
/**
* util function: current nonce
*/
private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
}
/**
* util function for turning the Authorization: header into
* parameters, has to do some unescaping
*/
private static function split_header($header) {
// this should be a regex
// error cases: commas in parameter values
$parts = explode(",", $header);
$out = array();
foreach ($parts as $param) {
$param = ltrim($param);
// skip the "realm" param, nobody ever uses it anyway
if (substr($param, 0, 5) != "oauth") continue;
$param_parts = explode("=", $param);
// rawurldecode() used because urldecode() will turn a "+" in the
// value into a space
$out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1));
}
return $out;
}
/**
* helper to try to sort out headers for people who aren't running apache
*/
private static function get_headers() {
if (function_exists('apache_request_headers')) {
// we need this to get the actual Authorization: header
// because apache tends to tell us it doesn't exist
return apache_request_headers();
}
// otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need
$out = array();
foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 5) == "HTTP_") {
// this is chaos, basically it is just there to capitalize the first
// letter of every word that is not an initial HTTP and strip HTTP
// code from przemek
$key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
$out[$key] = $value;
}
}
return $out;
}
}
class apiClientOAuthDataStore {
function lookup_consumer($consumer_key) {
// implement me
}
function lookup_token($consumer, $token_type, $token) {
// implement me
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
// implement me
}
function fetch_request_token($consumer) {
// return a new token attached to this consumer
}
function fetch_access_token($token, $consumer) {
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
}
}
class apiClientOAuthUtil {
public static function urlencodeRFC3986($string) {
return str_replace('%7E', '~', rawurlencode($string));
}
public static function urldecodeRFC3986($string) {
return rawurldecode($string);
}
}

View File

@ -0,0 +1,209 @@
<?php
/*
Copyright (c) 2010 Kevin M Burns Jr, http://kevburnsjr.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* A URI Template Parser which is used by the apiREST class to resolve the REST requests
* Blogpost: http://lab.kevburnsjr.com/php-uri-template-parser
* Source: http://github.com/KevBurnsJr/php-uri-template-parser
*/
class URI_Template_Parser {
public static $operators = array('+', ';', '?', '/', '.');
public static $reserved_operators = array('|', '!', '@');
public static $explode_modifiers = array('+', '*');
public static $partial_modifiers = array(':', '^');
public static $gen_delims = array(':', '/', '?', '#', '[', ']', '@');
public static $gen_delims_pct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40');
public static $sub_delims = array('!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=');
public static $sub_delims_pct = array('%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D');
public static $reserved;
public static $reserved_pct;
public function __construct($template) {
self::$reserved = array_merge(self::$gen_delims, self::$sub_delims);
self::$reserved_pct = array_merge(self::$gen_delims_pct, self::$sub_delims_pct);
$this->template = $template;
}
public function expand($data) {
// Modification to make this a bit more performant (since gettype is very slow)
if (! is_array($data)) {
$data = (array)$data;
}
/*
// Original code, which uses a slow gettype() statement, kept in place for if the assumption that is_array always works here is incorrect
switch (gettype($data)) {
case "boolean":
case "integer":
case "double":
case "string":
case "object":
$data = (array)$data;
break;
}
*/
// Resolve template vars
preg_match_all('/\{([^\}]*)\}/', $this->template, $em);
foreach ($em[1] as $i => $bare_expression) {
preg_match('/^([\+\;\?\/\.]{1})?(.*)$/', $bare_expression, $lm);
$exp = new StdClass();
$exp->expression = $em[0][$i];
$exp->operator = $lm[1];
$exp->variable_list = $lm[2];
$exp->varspecs = explode(',', $exp->variable_list);
$exp->vars = array();
foreach ($exp->varspecs as $varspec) {
preg_match('/^([a-zA-Z0-9_]+)([\*\+]{1})?([\:\^][0-9-]+)?(\=[^,]+)?$/', $varspec, $vm);
$var = new StdClass();
$var->name = $vm[1];
$var->modifier = isset($vm[2]) && $vm[2] ? $vm[2] : null;
$var->modifier = isset($vm[3]) && $vm[3] ? $vm[3] : $var->modifier;
$var->default = isset($vm[4]) ? substr($vm[4], 1) : null;
$exp->vars[] = $var;
}
// Add processing flags
$exp->reserved = false;
$exp->prefix = '';
$exp->delimiter = ',';
switch ($exp->operator) {
case '+':
$exp->reserved = 'true';
break;
case ';':
$exp->prefix = ';';
$exp->delimiter = ';';
break;
case '?':
$exp->prefix = '?';
$exp->delimiter = '&';
break;
case '/':
$exp->prefix = '/';
$exp->delimiter = '/';
break;
case '.':
$exp->prefix = '.';
$exp->delimiter = '.';
break;
}
$expressions[] = $exp;
}
// Expansion
$this->expansion = $this->template;
foreach ($expressions as $exp) {
$part = $exp->prefix;
$exp->one_var_defined = false;
foreach ($exp->vars as $var) {
$val = '';
if ($exp->one_var_defined && isset($data[$var->name])) {
$part .= $exp->delimiter;
}
// Variable present
if (isset($data[$var->name])) {
$exp->one_var_defined = true;
$var->data = $data[$var->name];
$val = self::val_from_var($var, $exp);
// Variable missing
} else {
if ($var->default) {
$exp->one_var_defined = true;
$val = $var->default;
}
}
$part .= $val;
}
if (! $exp->one_var_defined) $part = '';
$this->expansion = str_replace($exp->expression, $part, $this->expansion);
}
return $this->expansion;
}
private function val_from_var($var, $exp) {
$val = '';
if (is_array($var->data)) {
$i = 0;
if ($exp->operator == '?' && ! $var->modifier) {
$val .= $var->name . '=';
}
foreach ($var->data as $k => $v) {
$del = $var->modifier ? $exp->delimiter : ',';
$ek = rawurlencode($k);
$ev = rawurlencode($v);
// Array
if ($k !== $i) {
if ($var->modifier == '+') {
$val .= $var->name . '.';
}
if ($exp->operator == '?' && $var->modifier || $exp->operator == ';' && $var->modifier == '*' || $exp->operator == ';' && $var->modifier == '+') {
$val .= $ek . '=';
} else {
$val .= $ek . $del;
}
// List
} else {
if ($var->modifier == '+') {
if ($exp->operator == ';' && $var->modifier == '*' || $exp->operator == ';' && $var->modifier == '+' || $exp->operator == '?' && $var->modifier == '+') {
$val .= $var->name . '=';
} else {
$val .= $var->name . '.';
}
}
}
$val .= $ev . $del;
$i ++;
}
$val = trim($val, $del);
// Strings, numbers, etc.
} else {
if ($exp->operator == '?') {
$val = $var->name . (isset($var->data) ? '=' : '');
} else if ($exp->operator == ';') {
$val = $var->name . ($var->data ? '=' : '');
}
$val .= rawurlencode($var->data);
if ($exp->operator == '+') {
$val = str_replace(self::$reserved_pct, self::$reserved, $val);
}
}
return $val;
}
public function match($uri) {}
public function __toString() {
return $this->template;
}
}

View File

@ -0,0 +1,173 @@
<?php
/*
* Copyright 2012 Google Inc.
*
* 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.
*/
/**
* Implement the caching directives specified in rfc2616. This
* implementation is guided by the guidance offered in rfc2616-sec13.
* @author Chirag Shah <chirags@google.com>
*/
class apiCacheParser {
public static $CACHEABLE_HTTP_METHODS = array('GET', 'HEAD');
public static $CACHEABLE_STATUS_CODES = array('200', '203', '300', '301');
private function __construct() {}
/**
* Check if an HTTP request can be cached by a private local cache.
*
* @static
* @param apiHttpRequest $resp
* @return bool True if the request is cacheable.
* False if the request is uncacheable.
*/
public static function isRequestCacheable (apiHttpRequest $resp) {
$method = $resp->getRequestMethod();
if (! in_array($method, self::$CACHEABLE_HTTP_METHODS)) {
return false;
}
// Don't cache authorized requests/responses.
// [rfc2616-14.8] When a shared cache receives a request containing an
// Authorization field, it MUST NOT return the corresponding response
// as a reply to any other request...
if ($resp->getRequestHeader("authorization")) {
return false;
}
return true;
}
/**
* Check if an HTTP response can be cached by a private local cache.
*
* @static
* @param apiHttpRequest $resp
* @return bool True if the response is cacheable.
* False if the response is un-cacheable.
*/
public static function isResponseCacheable (apiHttpRequest $resp) {
// First, check if the HTTP request was cacheable before inspecting the
// HTTP response.
if (false == self::isRequestCacheable($resp)) {
return false;
}
$code = $resp->getResponseHttpCode();
if (! in_array($code, self::$CACHEABLE_STATUS_CODES)) {
return false;
}
// The resource is uncacheable if the resource is already expired and
// the resource doesn't have an ETag for revalidation.
$etag = $resp->getResponseHeader("etag");
if (self::isExpired($resp) && $etag == false) {
return false;
}
// [rfc2616-14.9.2] If [no-store is] sent in a response, a cache MUST NOT
// store any part of either this response or the request that elicited it.
$cacheControl = $resp->getParsedCacheControl();
if (isset($cacheControl['no-store'])) {
return false;
}
// Pragma: no-cache is an http request directive, but is occasionally
// used as a response header incorrectly.
$pragma = $resp->getResponseHeader('pragma');
if ($pragma == 'no-cache' || strpos($pragma, 'no-cache') !== false) {
return false;
}
// [rfc2616-14.44] Vary: * is extremely difficult to cache. "It implies that
// a cache cannot determine from the request headers of a subsequent request
// whether this response is the appropriate representation."
// Given this, we deem responses with the Vary header as uncacheable.
$vary = $resp->getResponseHeader('vary');
if ($vary) {
return false;
}
return true;
}
/**
* @static
* @param apiHttpRequest $resp
* @return bool True if the HTTP response is considered to be expired.
* False if it is considered to be fresh.
*/
public static function isExpired(apiHttpRequest $resp) {
// HTTP/1.1 clients and caches MUST treat other invalid date formats,
// especially including the value “0”, as in the past.
$parsedExpires = false;
$responseHeaders = $resp->getResponseHeaders();
if (isset($responseHeaders['expires'])) {
$rawExpires = $responseHeaders['expires'];
// Check for a malformed expires header first.
if (empty($rawExpires) || (is_numeric($rawExpires) && $rawExpires <= 0)) {
return true;
}
// See if we can parse the expires header.
$parsedExpires = strtotime($rawExpires);
if (false == $parsedExpires || $parsedExpires <= 0) {
return true;
}
}
// Calculate the freshness of an http response.
$freshnessLifetime = false;
$cacheControl = $resp->getParsedCacheControl();
if (isset($cacheControl['max-age'])) {
$freshnessLifetime = $cacheControl['max-age'];
}
$rawDate = $resp->getResponseHeader('date');
$parsedDate = strtotime($rawDate);
if (empty($rawDate) || false == $parsedDate) {
$parsedDate = time();
}
if (false == $freshnessLifetime && isset($responseHeaders['expires'])) {
$freshnessLifetime = $parsedExpires - $parsedDate;
}
if (false == $freshnessLifetime) {
return true;
}
// Calculate the age of an http response.
$age = max(0, time() - $parsedDate);
if (isset($responseHeaders['age'])) {
$age = max($age, strtotime($responseHeaders['age']));
}
return $freshnessLifetime <= $age;
}
/**
* Determine if a cache entry should be revalidated with by the origin.
*
* @param apiHttpRequest $response
* @return bool True if the entry is expired, else return false.
*/
public static function mustRevalidate(apiHttpRequest $response) {
// [13.3] When a cache has a stale entry that it would like to use as a
// response to a client's request, it first has to check with the origin
// server to see if its cached entry is still usable.
return self::isExpired($response);
}
}

View File

@ -0,0 +1,254 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
/**
* Curl based implementation of apiIO.
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*/
require_once 'apiCacheParser.php';
class apiCurlIO implements apiIO {
const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n";
const FORM_URLENCODED = 'application/x-www-form-urlencoded';
private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null);
private static $HOP_BY_HOP = array(
'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',
'te', 'trailers', 'transfer-encoding', 'upgrade');
private static $DEFAULT_CURL_PARAMS = array (
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => 0,
CURLOPT_FAILONERROR => false,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_HEADER => true,
);
/**
* Perform an authenticated / signed apiHttpRequest.
* This function takes the apiHttpRequest, calls apiAuth->sign on it
* (which can modify the request in what ever way fits the auth mechanism)
* and then calls apiCurlIO::makeRequest on the signed request
*
* @param apiHttpRequest $request
* @return apiHttpRequest The resulting HTTP response including the
* responseHttpCode, responseHeaders and responseBody.
*/
public function authenticatedRequest(apiHttpRequest $request) {
$request = apiClient::$auth->sign($request);
return $this->makeRequest($request);
}
/**
* Execute a apiHttpRequest
*
* @param apiHttpRequest $request the http request to be executed
* @return apiHttpRequest http request with the response http code, response
* headers and response body filled in
* @throws apiIOException on curl or IO error
*/
public function makeRequest(apiHttpRequest $request) {
// First, check to see if we have a valid cached version.
$cached = $this->getCachedRequest($request);
if ($cached !== false) {
if (apiCacheParser::mustRevalidate($cached)) {
$addHeaders = array();
if ($cached->getResponseHeader('etag')) {
// [13.3.4] If an entity tag has been provided by the origin server,
// we must use that entity tag in any cache-conditional request.
$addHeaders['If-None-Match'] = $cached->getResponseHeader('etag');
} elseif ($cached->getResponseHeader('date')) {
$addHeaders['If-Modified-Since'] = $cached->getResponseHeader('date');
}
$request->setRequestHeaders($addHeaders);
} else {
// No need to revalidate the request, return it directly
return $cached;
}
}
if (array_key_exists($request->getRequestMethod(),
self::$ENTITY_HTTP_METHODS)) {
$request = $this->processEntityRequest($request);
}
$ch = curl_init();
curl_setopt_array($ch, self::$DEFAULT_CURL_PARAMS);
curl_setopt($ch, CURLOPT_URL, $request->getUrl());
if ($request->getPostBody()) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getPostBody());
}
$requestHeaders = $request->getRequestHeaders();
if ($requestHeaders && is_array($requestHeaders)) {
$parsed = array();
foreach ($requestHeaders as $k => $v) {
$parsed[] = "$k: $v";
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $parsed);
}
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->getRequestMethod());
curl_setopt($ch, CURLOPT_USERAGENT, $request->getUserAgent());
$respData = curl_exec($ch);
// Retry if certificates are missing.
if (curl_errno($ch) == CURLE_SSL_CACERT) {
error_log('SSL certificate problem, verify that the CA cert is OK.'
. ' Retrying with the CA cert bundle from google-api-php-client.');
curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacerts.pem');
$respData = curl_exec($ch);
}
$respHeaderSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$respHttpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlErrorNum = curl_errno($ch);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlErrorNum != CURLE_OK) {
throw new apiIOException("HTTP Error: ($respHttpCode) $curlError");
}
// Parse out the raw response into usable bits
list($responseHeaders, $responseBody) =
$this->parseHttpResponseBody($respData, $respHeaderSize);
if ($respHttpCode == 304 && $cached) {
// If the server responded NOT_MODIFIED, return the cached request.
if (isset($responseHeaders['connection'])) {
$hopByHop = array_merge(
self::$HOP_BY_HOP,
explode(',', $responseHeaders['connection'])
);
$endToEnd = array();
foreach($hopByHop as $key) {
if (isset($responseHeaders[$key])) {
$endToEnd[$key] = $responseHeaders[$key];
}
}
$cached->setResponseHeaders($endToEnd);
}
return $cached;
}
// Fill in the apiHttpRequest with the response values
$request->setResponseHttpCode($respHttpCode);
$request->setResponseHeaders($responseHeaders);
$request->setResponseBody($responseBody);
// Store the request in cache (the function checks to see if the request
// can actually be cached)
$this->setCachedRequest($request);
// And finally return it
return $request;
}
/**
* @visible for testing.
* Cache the response to an HTTP request if it is cacheable.
* @param apiHttpRequest $request
* @return bool Returns true if the insertion was successful.
* Otherwise, return false.
*/
public function setCachedRequest(apiHttpRequest $request) {
// Determine if the request is cacheable.
if (apiCacheParser::isResponseCacheable($request)) {
apiClient::$cache->set($request->getCacheKey(), $request);
return true;
}
return false;
}
/**
* @visible for testing.
* @param apiHttpRequest $request
* @return apiHttpRequest|bool Returns the cached object or
* false if the operation was unsuccessful.
*/
public function getCachedRequest(apiHttpRequest $request) {
if (false == apiCacheParser::isRequestCacheable($request)) {
false;
}
return apiClient::$cache->get($request->getCacheKey());
}
/**
* @param $respData
* @param $headerSize
* @return array
*/
public function parseHttpResponseBody($respData, $headerSize) {
if (stripos($respData, self::CONNECTION_ESTABLISHED) !== false) {
$respData = str_ireplace(self::CONNECTION_ESTABLISHED, '', $respData);
}
$responseBody = substr($respData, $headerSize);
$responseHeaderLines = explode("\r\n", substr($respData, 0, $headerSize));
$responseHeaders = array();
foreach ($responseHeaderLines as $headerLine) {
if ($headerLine && strpos($headerLine, ':') !== false) {
list($header, $value) = explode(': ', $headerLine, 2);
$header = strtolower($header);
if (isset($responseHeaders[$header])) {
$responseHeaders[$header] .= "\n" . $value;
} else {
$responseHeaders[$header] = $value;
}
}
}
return array($responseHeaders, $responseBody);
}
/**
* @visible for testing
* Process an http request that contains an enclosed entity.
* @param apiHttpRequest $request
* @return apiHttpRequest Processed request with the enclosed entity.
*/
public function processEntityRequest(apiHttpRequest $request) {
$postBody = $request->getPostBody();
$contentType = $request->getRequestHeader("content-type");
// Set the default content-type as application/x-www-form-urlencoded.
if (false == $contentType) {
$contentType = self::FORM_URLENCODED;
$request->setRequestHeaders(array('content-type' => $contentType));
}
// Force the payload to match the content-type asserted in the header.
if ($contentType == self::FORM_URLENCODED && is_array($postBody)) {
$postBody = http_build_query($postBody, '', '&');
$request->setPostBody($postBody);
}
// Make sure the content-length header is set.
if (!$postBody || is_string($postBody)) {
$postsLength = strlen($postBody);
$request->setRequestHeaders(array('content-length' => $postsLength));
}
return $request;
}
}

View File

@ -0,0 +1,262 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
/**
* HTTP Request to be executed by apiIO classes. Upon execution, the
* responseHttpCode, responseHeaders and responseBody will be filled in.
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*
*/
class apiHttpRequest {
const USER_AGENT_SUFFIX = "google-api-php-client/0.5.0";
protected $url;
protected $requestMethod;
protected $requestHeaders;
protected $postBody;
protected $userAgent;
protected $responseHttpCode;
protected $responseHeaders;
protected $responseBody;
public $accessKey;
public function __construct($url, $method = 'GET', $headers = array(), $postBody = null) {
$this->url = $url;
$this->setRequestMethod($method);
$this->setRequestHeaders($headers);
$this->setPostBody($postBody);
global $apiConfig;
if (empty($apiConfig['application_name'])) {
$this->userAgent = self::USER_AGENT_SUFFIX;
} else {
$this->userAgent = $apiConfig['application_name'] . " " . self::USER_AGENT_SUFFIX;
}
}
/**
* Misc function that returns the base url component of the $url
* used by the OAuth signing class to calculate the base string
* @return string The base url component of the $url.
* @see http://oauth.net/core/1.0a/#anchor13
*/
public function getBaseUrl() {
if ($pos = strpos($this->url, '?')) {
return substr($this->url, 0, $pos);
}
return $this->url;
}
/**
* Misc function that returns an array of the query parameters of the current
* url used by the OAuth signing class to calculate the signature
* @return array Query parameters in the query string.
*/
public function getQueryParams() {
if ($pos = strpos($this->url, '?')) {
$queryStr = substr($this->url, $pos + 1);
$params = array();
parse_str($queryStr, $params);
return $params;
}
return array();
}
/**
* @return string HTTP Response Code.
*/
public function getResponseHttpCode() {
return (int) $this->responseHttpCode;
}
/**
* @param int $responseHttpCode HTTP Response Code.
*/
public function setResponseHttpCode($responseHttpCode) {
$this->responseHttpCode = $responseHttpCode;
}
/**
* @return $responseHeaders (array) HTTP Response Headers.
*/
public function getResponseHeaders() {
return $this->responseHeaders;
}
/**
* @return string HTTP Response Body
*/
public function getResponseBody() {
return $this->responseBody;
}
/**
* @param array $headers The HTTP response headers
* to be normalized.
*/
public function setResponseHeaders($headers) {
$headers = apiUtils::normalize($headers);
if ($this->responseHeaders) {
$headers = array_merge($this->responseHeaders, $headers);
}
$this->responseHeaders = $headers;
}
/**
* @param string $key
* @return array|boolean Returns the requested HTTP header or
* false if unavailable.
*/
public function getResponseHeader($key) {
return isset($this->responseHeaders[$key])
? $this->responseHeaders[$key]
: false;
}
/**
* @param string $responseBody The HTTP response body.
*/
public function setResponseBody($responseBody) {
$this->responseBody = $responseBody;
}
/**
* @return string $url The request URL.
*/
public function getUrl() {
return $this->url;
}
/**
* @return string $method HTTP Request Method.
*/
public function getRequestMethod() {
return $this->requestMethod;
}
/**
* @return array $headers HTTP Request Headers.
*/
public function getRequestHeaders() {
return $this->requestHeaders;
}
/**
* @param string $key
* @return array|boolean Returns the requested HTTP header or
* false if unavailable.
*/
public function getRequestHeader($key) {
return isset($this->requestHeaders[$key])
? $this->requestHeaders[$key]
: false;
}
/**
* @return string $postBody HTTP Request Body.
*/
public function getPostBody() {
return $this->postBody;
}
/**
* @param string $url the url to set
*/
public function setUrl($url) {
$this->url = $url;
}
/**
* @param string $method Set he HTTP Method and normalize
* it to upper-case, as required by HTTP.
*
*/
public function setRequestMethod($method) {
$this->requestMethod = strtoupper($method);
}
/**
* @param array $headers The HTTP request headers
* to be set and normalized.
*/
public function setRequestHeaders($headers) {
$headers = apiUtils::normalize($headers);
if ($this->requestHeaders) {
$headers = array_merge($this->requestHeaders, $headers);
}
$this->requestHeaders = $headers;
}
/**
* @param string $postBody the postBody to set
*/
public function setPostBody($postBody) {
$this->postBody = $postBody;
}
/**
* Set the User-Agent Header.
* @param string $userAgent The User-Agent.
*/
public function setUserAgent($userAgent) {
$this->userAgent = $userAgent;
}
/**
* @return string The User-Agent.
*/
public function getUserAgent() {
return $this->userAgent;
}
/**
* Returns a cache key depending on if this was an OAuth signed request
* in which case it will use the non-signed url and access key to make this
* cache key unique per authenticated user, else use the plain request url
* @return The md5 hash of the request cache key.
*/
public function getCacheKey() {
$key = $this->getUrl();
if (isset($this->accessKey)) {
$key .= $this->accessKey;
}
if (isset($this->requestHeaders['authorization'])) {
$key .= $this->requestHeaders['authorization'];
}
return md5($key);
}
public function getParsedCacheControl() {
$parsed = array();
$rawCacheControl = $this->getResponseHeader('cache-control');
if ($rawCacheControl) {
$rawCacheControl = str_replace(", ", "&", $rawCacheControl);
parse_str($rawCacheControl, $parsed);
}
return $parsed;
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Copyright 2010 Google Inc.
*
* 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.
*/
require_once 'io/apiHttpRequest.php';
require_once 'io/apiCurlIO.php';
require_once 'io/apiREST.php';
require_once 'io/apiRPC.php';
/**
* Abstract IO class
*
* @author Chris Chabot <chabotc@google.com>
*/
interface apiIO {
/**
* An utility function that first calls $this->auth->sign($request) and then executes makeRequest()
* on that signed request. Used for when a request should be authenticated
* @param apiHttpRequest $request
* @return apiHttpRequest $request
*/
public function authenticatedRequest(apiHttpRequest $request);
/**
* Executes a apIHttpRequest and returns the resulting populated httpRequest
* @param apiHttpRequest $request
* @return apiHttpRequest $request
*/
public function makeRequest(apiHttpRequest $request);
}

View File

@ -0,0 +1,148 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
require_once "external/URITemplateParser.php";
require_once "service/apiUtils.php";
/**
* This class implements the RESTful transport of apiServiceRequest()'s
*
* @author Chris Chabot <chabotc@google.com>
* @author Chirag Shah <chirags@google.com>
*/
class apiREST {
/**
* Executes a apiServiceRequest using a RESTful call by transforming it into
* an apiHttpRequest, and executed via apiIO::authenticatedRequest().
*
* @param apiServiceRequest $req
* @return array decoded result
* @throws apiServiceException on server side error (ie: not authenticated, invalid or
* malformed post body, invalid url)
*/
static public function execute(apiServiceRequest $req) {
$result = null;
$postBody = $req->getPostBody();
$url = self::createRequestUri(
$req->getRestBasePath(), $req->getRestPath(), $req->getParameters());
$httpRequest = new apiHttpRequest($url, $req->getHttpMethod(), null, $postBody);
if ($postBody) {
$contentTypeHeader = array();
if (isset($req->contentType) && $req->contentType) {
$contentTypeHeader['content-type'] = $req->contentType;
} else {
$contentTypeHeader['content-type'] = 'application/json; charset=UTF-8';
$contentTypeHeader['content-length'] = apiUtils::getStrLen($postBody);
}
$httpRequest->setRequestHeaders($contentTypeHeader);
}
$httpRequest = apiClient::$io->authenticatedRequest($httpRequest);
$decodedResponse = self::decodeHttpResponse($httpRequest);
//FIXME currently everything is wrapped in a data envelope, but hopefully this might change some day
$ret = isset($decodedResponse['data']) ? $decodedResponse['data'] : $decodedResponse;
return $ret;
}
/**
* Decode an HTTP Response.
* @static
* @throws apiServiceException
* @param apiHttpRequest $response The http response to be decoded.
* @return mixed|null
*/
static function decodeHttpResponse($response) {
$code = $response->getResponseHttpCode();
$body = $response->getResponseBody();
$decoded = null;
if ($code != '200' && $code != '201' && $code != '204') {
$decoded = json_decode($body, true);
$err = 'Error calling ' . $response->getRequestMethod() . ' ' . $response->getUrl();
if ($decoded != null && isset($decoded['error']['message']) && isset($decoded['error']['code'])) {
// if we're getting a json encoded error definition, use that instead of the raw response
// body for improved readability
$err .= ": ({$decoded['error']['code']}) {$decoded['error']['message']}";
} else {
$err .= ": ($code) $body";
}
throw new apiServiceException($err, $code);
}
// Only attempt to decode the response, if the response code wasn't (204) 'no content'
if ($code != '204') {
$decoded = json_decode($body, true);
if ($decoded == null) {
throw new apiServiceException("Invalid json in service response: $body");
}
}
return $decoded;
}
/**
* Parse/expand request parameters and create a fully qualified
* request uri.
* @static
* @param string $basePath
* @param string $restPath
* @param array $params
* @return string $requestUrl
*/
static function createRequestUri($basePath, $restPath, $params) {
$requestUrl = $basePath . $restPath;
$uriTemplateVars = array();
$queryVars = array();
foreach ($params as $paramName => $paramSpec) {
// Discovery v1.0 puts the canonical location under the 'location' field.
if (! isset($paramSpec['location'])) {
$paramSpec['location'] = $paramSpec['restParameterType'];
}
if ($paramSpec['type'] == 'boolean') {
$paramSpec['value'] = ($paramSpec['value']) ? 'true' : 'false';
}
if ($paramSpec['location'] == 'path') {
$uriTemplateVars[$paramName] = $paramSpec['value'];
} else {
if (isset($paramSpec['repeated']) && is_array($paramSpec['value'])) {
foreach ($paramSpec['value'] as $value) {
$queryVars[] = $paramName . '=' . rawurlencode($value);
}
} else {
$queryVars[] = $paramName . '=' . rawurlencode($paramSpec['value']);
}
}
}
if (count($uriTemplateVars)) {
$uriTemplateParser = new URI_Template_Parser($requestUrl);
$requestUrl = $uriTemplateParser->expand($uriTemplateVars);
}
//FIXME work around for the the uri template lib which url encodes
// the @'s & confuses our servers.
$requestUrl = str_replace('%40', '@', $requestUrl);
if (count($queryVars)) {
$requestUrl .= '?' . implode($queryVars, '&');
}
return $requestUrl;
}
}

View File

@ -0,0 +1,63 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
/**
* This class implements the experimental JSON-RPC transport for executing apiServiceRequest'
*
* @author Chris Chabot <chabotc@google.com>
*/
class apiRPC {
static public function execute($requests) {
$jsonRpcRequest = array();
foreach ($requests as $request) {
$parameters = array();
foreach ($request->getParameters() as $parameterName => $parameterVal) {
$parameters[$parameterName] = $parameterVal['value'];
}
$jsonRpcRequest[] = array(
'id' => $request->getBatchKey(),
'method' => $request->getRpcName(),
'params' => $parameters,
'apiVersion' => 'v1'
);
}
$httpRequest = new apiHttpRequest($request->getRpcPath());
$httpRequest->setRequestHeaders(array('Content-Type' => 'application/json'));
$httpRequest->setRequestMethod('POST');
$httpRequest->setPostBody(json_encode($jsonRpcRequest));
$httpRequest = apiClient::$io->authenticatedRequest($httpRequest);
if (($decodedResponse = json_decode($httpRequest->getResponseBody(), true)) != false) {
$ret = array();
foreach ($decodedResponse as $response) {
$ret[$response['id']] = self::checkNextLink($response['result']);
}
return $ret;
} else {
throw new apiServiceException("Invalid json returned by the json-rpc end-point");
}
}
static private function checkNextLink($response) {
if (isset($response['links']) && isset($response['links']['next'][0]['href'])) {
parse_str($response['links']['next'][0]['href'], $params);
if (isset($params['c'])) {
$response['continuationToken'] = $params['c'];
}
}
return $response;
}
}

View File

@ -0,0 +1,714 @@
# Certifcate Authority certificates for validating SSL connections.
#
# This file contains PEM format certificates generated from
# http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Netscape security libraries.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1994-2000
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
Verisign/RSA Secure Server CA
=============================
-----BEGIN CERTIFICATE-----
MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
-----END CERTIFICATE-----
Thawte Personal Basic CA
========================
-----BEGIN CERTIFICATE-----
MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj
IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X
DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw
EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE
ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy
dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD
QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN
BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53
dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK
wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7
G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF
AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P
9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
-----END CERTIFICATE-----
Thawte Personal Premium CA
==========================
-----BEGIN CERTIFICATE-----
MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p
dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv
bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa
QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY
BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u
IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl
bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu
Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs
Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI
Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD
ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh
KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
-----END CERTIFICATE-----
Thawte Personal Freemail CA
===========================
-----BEGIN CERTIFICATE-----
MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt
YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu
Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT
AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa
MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp
b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG
cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh
d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY
DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E
rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq
uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa
/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei
gQ==
-----END CERTIFICATE-----
Thawte Server CA
================
-----BEGIN CERTIFICATE-----
MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
-----END CERTIFICATE-----
Thawte Premium Server CA
========================
-----BEGIN CERTIFICATE-----
MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
-----END CERTIFICATE-----
Equifax Secure CA
=================
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----
Verisign Class 1 Public Primary Certification Authority
=======================================================
-----BEGIN CERTIFICATE-----
MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp
bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N
H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR
4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN
BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo
EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
lA==
-----END CERTIFICATE-----
Verisign Class 2 Public Primary Certification Authority
=======================================================
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt
YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh
YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7
FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G
CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg
J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc
r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
-----END CERTIFICATE-----
Verisign Class 3 Public Primary Certification Authority
=======================================================
-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
-----END CERTIFICATE-----
Verisign Class 1 Public Primary Certification Authority - G2
============================================================
-----BEGIN CERTIFICATE-----
MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg
UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK
VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm
Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID
AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J
h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68
DzFc6PLZ
-----END CERTIFICATE-----
Verisign Class 2 Public Primary Certification Authority - G2
============================================================
-----BEGIN CERTIFICATE-----
MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe
Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX
MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj
IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx
KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM
HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw
DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC
AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji
nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
jBJ7xUS0rg==
-----END CERTIFICATE-----
Verisign Class 3 Public Primary Certification Authority - G2
============================================================
-----BEGIN CERTIFICATE-----
MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
oJ2daZH9
-----END CERTIFICATE-----
Verisign Class 4 Public Primary Certification Authority - G2
============================================================
-----BEGIN CERTIFICATE-----
MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg
UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM
HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK
qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID
AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj
cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP
T8qAkbYp
-----END CERTIFICATE-----
Verisign Class 1 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
-----END CERTIFICATE-----
Verisign Class 2 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s
IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp
Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV
BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp
Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu
Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g
Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU
J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO
JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY
wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o
koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E
Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe
xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u
7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
-----END CERTIFICATE-----
Verisign Class 3 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
-----END CERTIFICATE-----
Verisign Class 4 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
-----END CERTIFICATE-----
Equifax Secure Global eBusiness CA
==================================
-----BEGIN CERTIFICATE-----
MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
-----END CERTIFICATE-----
Equifax Secure eBusiness CA 1
=============================
-----BEGIN CERTIFICATE-----
MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
-----END CERTIFICATE-----
Equifax Secure eBusiness CA 2
=============================
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
-----END CERTIFICATE-----
Thawte Time Stamping CA
=======================
-----BEGIN CERTIFICATE-----
MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx
FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN
BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd
BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN
MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g
Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG
A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l
c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT
6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa
Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL
8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC
9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ
pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ
CayJSdM=
-----END CERTIFICATE-----
thawte Primary Root CA
======================
-----BEGIN CERTIFICATE-----
MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
jVaMaA==
-----END CERTIFICATE-----
VeriSign Class 3 Public Primary Certification Authority - G5
============================================================
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
-----END CERTIFICATE-----
Entrust.net Secure Server Certification Authority
=================================================
-----BEGIN CERTIFICATE-----
MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
-----END CERTIFICATE-----
Go Daddy Certification Authority Root Certificate Bundle
========================================================
-----BEGIN CERTIFICATE-----
MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx
ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw
MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH
QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j
b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j
b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj
YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H
KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm
VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR
SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT
cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ
6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu
MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS
kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB
BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f
BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv
c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH
AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO
BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG
OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU
A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o
0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX
RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH
qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV
U+4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh
bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe
BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX
DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE
YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0
aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC
ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q
N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO
r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN
f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH
U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU
TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb
VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg
SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv
biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg
MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw
AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv
ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu
Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd
IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv
bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1
QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O
WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf
SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
-----END CERTIFICATE-----

View File

@ -0,0 +1,39 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
/**
* Wrapper for the (experimental!) JSON-RPC protocol, for production use regular REST calls instead
*
* @author Chris Chabot <chabotc@google.com>
*/
class apiBatch {
/**
* Execute one or multiple Google API requests, takes one or multiple requests as param
* Example usage:
* $ret = apiBatch::execute(
* $apiClient->activities->list(array('@public', '@me'), 'listActivitiesKey'),
* $apiClient->people->get(array('userId' => '@me'), 'getPeopleKey')
* );
* print_r($ret['getPeopleKey']);
*/
static public function execute( /* polymorphic */) {
$requests = func_get_args();
return apiRPC::execute($requests);
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Copyright 2012 Google Inc.
*
* 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.
*/
/**
* @author Chirag Shah <chirags@google.com>
*
*/
class apiMediaFileUpload {
public $mimeType;
public $fileName;
public $chunkSize;
public static function process($metadata, $method, &$params) {
$payload = array();
$data = isset($params['data']) ? $params['data']['value'] : false;
$mimeType = isset($params['mimeType']) ? $params['mimeType']['value'] : false;
$file = isset($params['file']) ? $params['file']['value'] : false;
$uploadPath = $method['mediaUpload']['protocols']['simple']['path'];
unset($params['data']);
unset($params['mimeType']);
unset($params['file']);
if ($file) {
if (substr($file, 0, 1) != '@') {
$file = '@' . $file;
}
$payload['file'] = $file;
$payload['content-type'] = 'multipart/form-data';
$payload['restBasePath'] = $uploadPath;
// This is a standard file upload with curl.
return $payload;
}
$parsedMeta = is_string($metadata) ? json_decode($metadata, true) : $metadata;
if ($metadata && false == $data) {
// Process as a normal API request.
return false;
}
// Process as a media upload request.
$params['uploadType'] = array(
'type' => 'string',
'location' => 'query',
'value' => 'media',
);
// Determine which type.
$payload['restBasePath'] = $uploadPath;
if (false == $metadata || false == $parsedMeta) {
// This is a simple media upload.
$payload['content-type'] = $mimeType;
$payload['data'] = $data;
} else {
// This is a multipart/related upload.
$boundary = isset($params['boundary']) ? $params['boundary'] : mt_rand();
$boundary = str_replace('"', '', $boundary);
$payload['content-type'] = 'multipart/related; boundary=' . $boundary;
$related = "--$boundary\r\n";
$related .= "Content-Type: application/json; charset=UTF-8\r\n";
$related .= "\r\n" . $metadata . "\r\n";
$related .= "--$boundary\r\n";
$related .= "Content-Type: $mimeType\r\n";
$related .= "Content-Transfer-Encoding: base64\r\n";
$related .= "\r\n" . base64_encode($data) . "\r\n";
$related .= "--$boundary--";
$payload['data'] = $related;
}
return $payload;
}
}

View File

@ -0,0 +1,115 @@
<?php
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
/**
* This class defines attributes, valid values, and usage which is generated from
* a given json schema. http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5
*
* @author Chirag Shah <chirags@google.com>
*
*/
class apiModel {
public function __construct( /* polymorphic */ ) {
if (func_num_args() == 1 && is_array(func_get_arg(0))) {
// Initialize the model with the array's contents.
$array = func_get_arg(0);
$this->mapTypes($array);
}
}
/**
* Initialize this object's properties from an array.
*
* @param array Used to seed this object's properties.
* @return void
*/
private function mapTypes($array) {
foreach ($array as $key => $val) {
$this->$key = $val;
$keyTypeName = "__$key" . 'Type';
$keyDataType = "__$key" . 'DataType';
if ($this->useObjects() && property_exists($this, $keyTypeName)) {
if ($this->isAssociativeArray($val)) {
if (isset($this->$keyDataType) && 'map' == $this->$keyDataType) {
foreach($val as $arrayKey => $arrayItem) {
$val[$arrayKey] = $this->createObjectFromName($keyTypeName, $arrayItem);
}
$this->$key = $val;
} else {
$this->$key = $this->createObjectFromName($keyTypeName, $val);
}
} else if (is_array($val)) {
$arrayObject = array();
foreach ($val as $arrayIndex => $arrayItem) {
$arrayObject[$arrayIndex] = $this->createObjectFromName($keyTypeName, $arrayItem);
}
$this->$key = $arrayObject;
}
}
}
}
/**
* Returns true only if the array is associative.
* @param array $array
* @return bool True if the array is associative.
*/
private function isAssociativeArray($array) {
if (!is_array($array)) {
return false;
}
$keys = array_keys($array);
foreach($keys as $key) {
if (is_string($key)) {
return true;
}
}
return false;
}
/**
* Given a variable name, discover its type.
*
* @param $name
* @param $item
* @return object The object from the item.
*/
private function createObjectFromName($name, $item) {
$type = $this->$name;
return new $type($item);
}
protected function useObjects() {
global $apiConfig;
return (isset($apiConfig['use_objects']) && $apiConfig['use_objects']);
}
/**
* Verify if $obj is an array.
* @throws apiException Thrown if $obj isn't an array.
* @param array $obj Items that should be validated.
* @param string $type Array items should be of this type.
* @param string $method Method expecting an array as an argument.
*/
protected function assertIsArray($obj, $type, $method) {
if ($obj && !is_array($obj)) {
throw new apiException("Incorrect parameter type passed to $method(), expected an"
. " array containing items of type $type.");
}
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* Copyright 2010 Google Inc.
*
* 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.
*/
require_once 'service/apiServiceResource.php';
require_once 'service/apiServiceRequest.php';
require_once 'service/apiBatch.php';
/**
* This class parses the service end points of the api discovery document and constructs
* serviceResource variables for all of them.
*
* For instance when calling with the service document for Plus, it will create apiServiceResource's
* for $this->activities, $this->comments, $this->people, etc.
*
* @author Chris Chabot <chabotc@google.com>
*
*/
class apiService {
public $version = null;
public $restBasePath;
public $rpcPath;
public $resource = null;
public function __construct($serviceName, $discoveryDocument) {
global $apiConfig;
if (!isset($discoveryDocument['version']) || !isset($discoveryDocument['restBasePath']) || !isset($discoveryDocument['rpcPath'])) {
throw new apiServiceException("Invalid discovery document");
}
$this->version = $discoveryDocument['version'];
$this->restBasePath = $apiConfig['basePath'] . $discoveryDocument['restBasePath'];
$this->rpcPath = $apiConfig['basePath'] . $discoveryDocument['rpcPath'];
foreach ($discoveryDocument['resources'] as $resourceName => $resourceTypes) {
$this->$resourceName = new apiServiceResource($this, $serviceName, $resourceName, $resourceTypes);
}
}
/**
* @return string $restBasePath
*/
public function getRestBasePath() {
return $this->restBasePath;
}
/**
* @return string $rpcPath
*/
public function getRpcPath() {
return $this->rpcPath;
}
}

Some files were not shown because too many files have changed in this diff Show More