Merge branch 'master' of git://gitorious.org/owncloud/owncloud into oracle-support
Conflicts: 3rdparty/Sabre/CardDAV/Plugin.php 3rdparty/smb4php/smb.php apps/bookmarks/ajax/addBookmark.php apps/bookmarks/ajax/editBookmark.php apps/bookmarks/appinfo/migrate.php apps/calendar/ajax/calendar/edit.form.php apps/calendar/ajax/changeview.php apps/calendar/ajax/import/import.php apps/calendar/ajax/settings/guesstimezone.php apps/calendar/ajax/settings/setfirstday.php apps/calendar/ajax/settings/settimeformat.php apps/calendar/ajax/share/changepermission.php apps/calendar/ajax/share/share.php apps/calendar/ajax/share/unshare.php apps/calendar/appinfo/app.php apps/calendar/appinfo/remote.php apps/calendar/appinfo/update.php apps/calendar/appinfo/version apps/calendar/js/calendar.js apps/calendar/l10n/da.php apps/calendar/l10n/de.php apps/calendar/l10n/fi_FI.php apps/calendar/l10n/gl.php apps/calendar/l10n/he.php apps/calendar/l10n/hr.php apps/calendar/l10n/ja_JP.php apps/calendar/l10n/lb.php apps/calendar/l10n/lt_LT.php apps/calendar/l10n/nb_NO.php apps/calendar/l10n/pl.php apps/calendar/l10n/pt_PT.php apps/calendar/l10n/ro.php apps/calendar/l10n/ru.php apps/calendar/l10n/sv.php apps/calendar/l10n/zh_CN.php apps/calendar/l10n/zh_TW.php apps/calendar/lib/app.php apps/calendar/lib/calendar.php apps/calendar/lib/object.php apps/calendar/lib/share.php apps/calendar/templates/part.choosecalendar.rowfields.php apps/calendar/templates/part.import.php apps/calendar/templates/settings.php apps/contacts/ajax/activation.php apps/contacts/ajax/addressbook/delete.php apps/contacts/ajax/contact/add.php apps/contacts/ajax/contact/addproperty.php apps/contacts/ajax/contact/delete.php apps/contacts/ajax/contact/deleteproperty.php apps/contacts/ajax/contact/saveproperty.php apps/contacts/ajax/createaddressbook.php apps/contacts/ajax/cropphoto.php apps/contacts/ajax/currentphoto.php apps/contacts/ajax/importaddressbook.php apps/contacts/ajax/oc_photo.php apps/contacts/ajax/savecrop.php apps/contacts/ajax/selectaddressbook.php apps/contacts/ajax/updateaddressbook.php apps/contacts/ajax/uploadimport.php apps/contacts/ajax/uploadphoto.php apps/contacts/appinfo/migrate.php apps/contacts/appinfo/remote.php apps/contacts/css/contacts.css apps/contacts/import.php apps/contacts/index.php apps/contacts/js/contacts.js apps/contacts/l10n/ca.php apps/contacts/l10n/cs_CZ.php apps/contacts/l10n/da.php apps/contacts/l10n/de.php apps/contacts/l10n/el.php apps/contacts/l10n/eo.php apps/contacts/l10n/es.php apps/contacts/l10n/et_EE.php apps/contacts/l10n/eu.php apps/contacts/l10n/fa.php apps/contacts/l10n/fi_FI.php apps/contacts/l10n/fr.php apps/contacts/l10n/he.php apps/contacts/l10n/hr.php apps/contacts/l10n/hu_HU.php apps/contacts/l10n/ia.php apps/contacts/l10n/it.php apps/contacts/l10n/ja_JP.php apps/contacts/l10n/ko.php apps/contacts/l10n/lb.php apps/contacts/l10n/mk.php apps/contacts/l10n/nb_NO.php apps/contacts/l10n/nl.php apps/contacts/l10n/pl.php apps/contacts/l10n/pt_BR.php apps/contacts/l10n/pt_PT.php apps/contacts/l10n/ro.php apps/contacts/l10n/ru.php apps/contacts/l10n/sk_SK.php apps/contacts/l10n/sl.php apps/contacts/l10n/sv.php apps/contacts/l10n/th_TH.php apps/contacts/l10n/tr.php apps/contacts/l10n/zh_CN.php apps/contacts/l10n/zh_TW.php apps/contacts/lib/addressbook.php apps/contacts/lib/hooks.php apps/contacts/lib/vcard.php apps/contacts/photo.php apps/contacts/templates/part.contact.php apps/contacts/templates/part.contacts.php apps/contacts/templates/part.cropphoto.php apps/contacts/templates/part.importaddressbook.php apps/contacts/templates/part.selectaddressbook.php apps/contacts/thumbnail.php apps/files/ajax/download.php apps/files/ajax/newfile.php apps/files/ajax/timezone.php apps/files/appinfo/update.php apps/files/appinfo/version apps/files/index.php apps/files/js/fileactions.js apps/files/js/filelist.js apps/files/js/files.js apps/files/l10n/ar.php apps/files/l10n/bg_BG.php apps/files/l10n/ca.php apps/files/l10n/cs_CZ.php apps/files/l10n/da.php apps/files/l10n/de.php apps/files/l10n/el.php apps/files/l10n/eo.php apps/files/l10n/es.php apps/files/l10n/et_EE.php apps/files/l10n/eu.php apps/files/l10n/fa.php apps/files/l10n/fi_FI.php apps/files/l10n/fr.php apps/files/l10n/gl.php apps/files/l10n/he.php apps/files/l10n/hr.php apps/files/l10n/hu_HU.php apps/files/l10n/ia.php apps/files/l10n/id.php apps/files/l10n/it.php apps/files/l10n/ja_JP.php apps/files/l10n/ko.php apps/files/l10n/lb.php apps/files/l10n/lt_LT.php apps/files/l10n/mk.php apps/files/l10n/ms_MY.php apps/files/l10n/nb_NO.php apps/files/l10n/nl.php apps/files/l10n/nn_NO.php apps/files/l10n/pl.php apps/files/l10n/pt_BR.php apps/files/l10n/pt_PT.php apps/files/l10n/ro.php apps/files/l10n/ru.php apps/files/l10n/sk_SK.php apps/files/l10n/sl.php apps/files/l10n/sr.php apps/files/l10n/sr@latin.php apps/files/l10n/sv.php apps/files/l10n/th_TH.php apps/files/l10n/tr.php apps/files/l10n/uk.php apps/files/l10n/zh_CN.php apps/files/l10n/zh_TW.php apps/files_archive/js/archive.js apps/files_encryption/lib/cryptstream.php apps/files_encryption/lib/proxy.php apps/files_encryption/tests/proxy.php apps/files_external/appinfo/app.php apps/files_external/lib/smb.php apps/files_external/lib/streamwrapper.php apps/files_external/tests/config.php apps/files_external/tests/smb.php apps/files_sharing/ajax/email.php apps/files_sharing/ajax/getitem.php apps/files_sharing/ajax/setpermissions.php apps/files_sharing/ajax/share.php apps/files_sharing/ajax/toggleresharing.php apps/files_sharing/ajax/unshare.php apps/files_sharing/ajax/userautocomplete.php apps/files_sharing/js/settings.js apps/files_sharing/js/share.js apps/files_sharing/lib_share.php apps/files_sharing/settings.php apps/files_sharing/sharedstorage.php apps/files_sharing/templates/settings.php apps/files_versions/ajax/rollbackVersion.php apps/files_versions/versions.php apps/gallery/ajax/thumbnail.php apps/gallery/appinfo/app.php apps/gallery/appinfo/update.php apps/gallery/appinfo/version apps/gallery/css/styles.css apps/gallery/index.php apps/gallery/js/pictures.js apps/gallery/l10n/ca.php apps/gallery/l10n/cs_CZ.php apps/gallery/l10n/de.php apps/gallery/l10n/el.php apps/gallery/l10n/es.php apps/gallery/l10n/fi_FI.php apps/gallery/l10n/fr.php apps/gallery/l10n/it.php apps/gallery/l10n/pl.php apps/gallery/l10n/pt_PT.php apps/gallery/l10n/ru.php apps/gallery/l10n/sl.php apps/gallery/l10n/sv.php apps/gallery/l10n/th_TH.php apps/gallery/l10n/tr.php apps/gallery/l10n/zh_CN.php apps/gallery/lib/album.php apps/gallery/lib/hooks_handlers.php apps/gallery/lib/managers.php apps/gallery/lib/photo.php apps/gallery/lib/tiles.php apps/gallery/lib/tiles_test.php apps/gallery/templates/index.php apps/media/lib_ampache.php apps/media/lib_collection.php apps/media/lib_media.php apps/remoteStorage/lib_remoteStorage.php apps/tasks/ajax/addtaskform.php apps/tasks/ajax/edittask.php apps/user_ldap/appinfo/update.php apps/user_ldap/group_ldap.php apps/user_ldap/lib_ldap.php apps/user_ldap/settings.php apps/user_ldap/templates/settings.php apps/user_ldap/user_ldap.php apps/user_migrate/appinfo/app.php apps/user_migrate/templates/settings.php apps/user_webfinger/host-meta.php config/config.sample.php core/js/js.js core/l10n/da.php core/l10n/de.php core/l10n/fi_FI.php core/l10n/gl.php core/l10n/he.php core/l10n/hr.php core/l10n/id.php core/l10n/ja_JP.php core/l10n/lb.php core/l10n/lt_LT.php core/l10n/nb_NO.php core/l10n/pl.php core/l10n/pt_PT.php core/l10n/ro.php core/l10n/ru.php core/l10n/sv.php core/lostpassword/index.php core/templates/layout.user.php core/templates/login.php db_structure.xml index.php l10n/af/calendar.po l10n/af/contacts.po l10n/af/core.po l10n/af/files.po l10n/af/settings.po l10n/ar/calendar.po l10n/ar/contacts.po l10n/ar/core.po l10n/ar/files.po l10n/ar/media.po l10n/ar/settings.po l10n/bg_BG/calendar.po l10n/bg_BG/contacts.po l10n/bg_BG/core.po l10n/bg_BG/files.po l10n/bg_BG/media.po l10n/bg_BG/settings.po l10n/ca/calendar.po l10n/ca/contacts.po l10n/ca/core.po l10n/ca/files.po l10n/ca/gallery.po l10n/ca/settings.po l10n/cs_CZ/calendar.po l10n/cs_CZ/contacts.po l10n/cs_CZ/core.po l10n/cs_CZ/files.po l10n/cs_CZ/gallery.po l10n/cs_CZ/settings.po l10n/da/calendar.po l10n/da/contacts.po l10n/da/core.po l10n/da/files.po l10n/da/settings.po l10n/de/calendar.po l10n/de/contacts.po l10n/de/core.po l10n/de/files.po l10n/de/gallery.po l10n/de/settings.po l10n/el/calendar.po l10n/el/contacts.po l10n/el/core.po l10n/el/files.po l10n/el/gallery.po l10n/el/settings.po l10n/eo/calendar.po l10n/eo/contacts.po l10n/eo/core.po l10n/eo/files.po l10n/eo/media.po l10n/eo/settings.po l10n/es/calendar.po l10n/es/contacts.po l10n/es/core.po l10n/es/files.po l10n/es/gallery.po l10n/es/settings.po l10n/et_EE/calendar.po l10n/et_EE/contacts.po l10n/et_EE/core.po l10n/et_EE/files.po l10n/et_EE/settings.po l10n/eu/calendar.po l10n/eu/contacts.po l10n/eu/core.po l10n/eu/files.po l10n/eu/settings.po l10n/fa/calendar.po l10n/fa/contacts.po l10n/fa/core.po l10n/fa/files.po l10n/fa/settings.po l10n/fi_FI/calendar.po l10n/fi_FI/contacts.po l10n/fi_FI/core.po l10n/fi_FI/files.po l10n/fi_FI/gallery.po l10n/fi_FI/settings.po l10n/fr/calendar.po l10n/fr/contacts.po l10n/fr/core.po l10n/fr/files.po l10n/fr/gallery.po l10n/fr/media.po l10n/fr/settings.po l10n/gl/calendar.po l10n/gl/contacts.po l10n/gl/core.po l10n/gl/files.po l10n/gl/settings.po l10n/he/calendar.po l10n/he/contacts.po l10n/he/core.po l10n/he/files.po l10n/he/settings.po l10n/hr/calendar.po l10n/hr/contacts.po l10n/hr/core.po l10n/hr/files.po l10n/hr/settings.po l10n/hu_HU/calendar.po l10n/hu_HU/contacts.po l10n/hu_HU/core.po l10n/hu_HU/files.po l10n/hu_HU/settings.po l10n/hy/calendar.po l10n/hy/contacts.po l10n/hy/core.po l10n/hy/files.po l10n/hy/settings.po l10n/ia/calendar.po l10n/ia/contacts.po l10n/ia/core.po l10n/ia/files.po l10n/ia/settings.po l10n/id/calendar.po l10n/id/contacts.po l10n/id/core.po l10n/id/files.po l10n/id/settings.po l10n/it/calendar.po l10n/it/contacts.po l10n/it/core.po l10n/it/files.po l10n/it/gallery.po l10n/it/settings.po l10n/ja_JP/calendar.po l10n/ja_JP/contacts.po l10n/ja_JP/core.po l10n/ja_JP/files.po l10n/ja_JP/settings.po l10n/ko/calendar.po l10n/ko/contacts.po l10n/ko/core.po l10n/ko/files.po l10n/ko/settings.po l10n/lb/calendar.po l10n/lb/contacts.po l10n/lb/core.po l10n/lb/files.po l10n/lb/settings.po l10n/lt_LT/calendar.po l10n/lt_LT/contacts.po l10n/lt_LT/core.po l10n/lt_LT/files.po l10n/lt_LT/settings.po l10n/mk/calendar.po l10n/mk/contacts.po l10n/mk/core.po l10n/mk/files.po l10n/mk/settings.po l10n/ms_MY/calendar.po l10n/ms_MY/contacts.po l10n/ms_MY/core.po l10n/ms_MY/files.po l10n/ms_MY/settings.po l10n/nb_NO/calendar.po l10n/nb_NO/contacts.po l10n/nb_NO/core.po l10n/nb_NO/files.po l10n/nb_NO/settings.po l10n/nl/calendar.po l10n/nl/contacts.po l10n/nl/core.po l10n/nl/files.po l10n/nl/settings.po l10n/nn_NO/calendar.po l10n/nn_NO/contacts.po l10n/nn_NO/core.po l10n/nn_NO/files.po l10n/nn_NO/settings.po l10n/pl/calendar.po l10n/pl/contacts.po l10n/pl/core.po l10n/pl/files.po l10n/pl/gallery.po l10n/pl/settings.po l10n/pt_BR/calendar.po l10n/pt_BR/contacts.po l10n/pt_BR/core.po l10n/pt_BR/files.po l10n/pt_BR/settings.po l10n/pt_PT/calendar.po l10n/pt_PT/contacts.po l10n/pt_PT/core.po l10n/pt_PT/files.po l10n/pt_PT/gallery.po l10n/pt_PT/settings.po l10n/ro/calendar.po l10n/ro/contacts.po l10n/ro/core.po l10n/ro/files.po l10n/ro/settings.po l10n/ru/calendar.po l10n/ru/contacts.po l10n/ru/core.po l10n/ru/files.po l10n/ru/gallery.po l10n/ru/settings.po l10n/sk_SK/calendar.po l10n/sk_SK/contacts.po l10n/sk_SK/core.po l10n/sk_SK/files.po l10n/sk_SK/settings.po l10n/sl/calendar.po l10n/sl/contacts.po l10n/sl/core.po l10n/sl/files.po l10n/sl/gallery.po l10n/sl/settings.po l10n/sr/calendar.po l10n/sr/contacts.po l10n/sr/core.po l10n/sr/files.po l10n/sr/settings.po l10n/sr@latin/calendar.po l10n/sr@latin/contacts.po l10n/sr@latin/core.po l10n/sr@latin/files.po l10n/sr@latin/settings.po l10n/sv/calendar.po l10n/sv/contacts.po l10n/sv/core.po l10n/sv/files.po l10n/sv/gallery.po l10n/sv/media.po l10n/sv/settings.po l10n/templates/bookmarks.pot l10n/templates/calendar.pot l10n/templates/contacts.pot l10n/templates/core.pot l10n/templates/files.pot l10n/templates/gallery.pot l10n/templates/media.pot l10n/templates/settings.pot l10n/th_TH/calendar.po l10n/th_TH/contacts.po l10n/th_TH/core.po l10n/th_TH/files.po l10n/th_TH/gallery.po l10n/th_TH/settings.po l10n/tr/calendar.po l10n/tr/contacts.po l10n/tr/core.po l10n/tr/files.po l10n/tr/gallery.po l10n/tr/settings.po l10n/uk/calendar.po l10n/uk/contacts.po l10n/uk/core.po l10n/uk/files.po l10n/uk/media.po l10n/uk/settings.po l10n/zh_CN/calendar.po l10n/zh_CN/contacts.po l10n/zh_CN/core.po l10n/zh_CN/files.po l10n/zh_CN/gallery.po l10n/zh_CN/settings.po l10n/zh_TW/calendar.po l10n/zh_TW/contacts.po l10n/zh_TW/core.po l10n/zh_TW/files.po l10n/zh_TW/settings.po lib/app.php lib/base.php lib/connector/sabre/file.php lib/connector/sabre/locks.php lib/connector/sabre/node.php lib/db.php lib/filecache.php lib/fileproxy/quota.php lib/files.php lib/filestorage/local.php lib/filesystemview.php lib/group/database.php lib/helper.php lib/installer.php lib/json.php lib/l10n.php lib/migrate.php lib/mimetypes.fixlist.php lib/ocs.php lib/preferences.php lib/public/json.php lib/public/util.php lib/template.php lib/user.php lib/user/database.php lib/util.php lib/vcategories.php ocs/providers.php settings/admin.php settings/ajax/lostpassword.php settings/ajax/removeuser.php settings/ajax/setbackgroundjobsmode.php settings/ajax/setlanguage.php settings/ajax/setquota.php settings/ajax/togglegroups.php settings/apps.php settings/css/settings.css settings/js/apps.js settings/js/users.js settings/l10n/bg_BG.php settings/l10n/ca.php settings/l10n/cs_CZ.php settings/l10n/da.php settings/l10n/de.php settings/l10n/el.php settings/l10n/eo.php settings/l10n/es.php settings/l10n/et_EE.php settings/l10n/eu.php settings/l10n/fa.php settings/l10n/fi_FI.php settings/l10n/fr.php settings/l10n/gl.php settings/l10n/he.php settings/l10n/hr.php settings/l10n/hu_HU.php settings/l10n/it.php settings/l10n/ja_JP.php settings/l10n/ko.php settings/l10n/lt_LT.php settings/l10n/mk.php settings/l10n/ms_MY.php settings/l10n/nb_NO.php settings/l10n/nl.php settings/l10n/nn_NO.php settings/l10n/pl.php settings/l10n/pt_BR.php settings/l10n/pt_PT.php settings/l10n/ru.php settings/l10n/sk_SK.php settings/l10n/sl.php settings/l10n/sv.php settings/l10n/th_TH.php settings/l10n/tr.php settings/l10n/zh_CN.php settings/personal.php settings/templates/admin.php settings/templates/users.php
|
@ -34,6 +34,9 @@ RCS/*
|
|||
# netbeans
|
||||
nbproject
|
||||
|
||||
# phpStorm
|
||||
.idea
|
||||
|
||||
# geany
|
||||
*.geany
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ class Crypt_Blowfish
|
|||
function decrypt($cipherText)
|
||||
{
|
||||
if (!is_string($cipherText)) {
|
||||
PEAR::raiseError('Chiper text must be a string', 1, PEAR_ERROR_DIE);
|
||||
PEAR::raiseError('Cipher text must be a string', 1, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
if (extension_loaded('mcrypt')) {
|
||||
|
|
|
@ -0,0 +1,380 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox API class
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
class Dropbox_API {
|
||||
|
||||
/**
|
||||
* Sandbox root-path
|
||||
*/
|
||||
const ROOT_SANDBOX = 'sandbox';
|
||||
|
||||
/**
|
||||
* Dropbox root-path
|
||||
*/
|
||||
const ROOT_DROPBOX = 'dropbox';
|
||||
|
||||
/**
|
||||
* API URl
|
||||
*/
|
||||
protected $api_url = 'https://api.dropbox.com/1/';
|
||||
|
||||
/**
|
||||
* Content API URl
|
||||
*/
|
||||
protected $api_content_url = 'https://api-content.dropbox.com/1/';
|
||||
|
||||
/**
|
||||
* OAuth object
|
||||
*
|
||||
* @var Dropbox_OAuth
|
||||
*/
|
||||
protected $oauth;
|
||||
|
||||
/**
|
||||
* Default root-path, this will most likely be 'sandbox' or 'dropbox'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $root;
|
||||
protected $useSSL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Dropbox_OAuth Dropbox_Auth object
|
||||
* @param string $root default root path (sandbox or dropbox)
|
||||
*/
|
||||
public function __construct(Dropbox_OAuth $oauth, $root = self::ROOT_DROPBOX, $useSSL = true) {
|
||||
|
||||
$this->oauth = $oauth;
|
||||
$this->root = $root;
|
||||
$this->useSSL = $useSSL;
|
||||
if (!$this->useSSL)
|
||||
{
|
||||
throw new Dropbox_Exception('Dropbox REST API now requires that all requests use SSL');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about the current dropbox account
|
||||
*
|
||||
* @return stdclass
|
||||
*/
|
||||
public function getAccountInfo() {
|
||||
|
||||
$data = $this->oauth->fetch($this->api_url . 'account/info');
|
||||
return json_decode($data['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file's contents
|
||||
*
|
||||
* @param string $path path
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return string
|
||||
*/
|
||||
public function getFile($path = '', $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
$result = $this->oauth->fetch($this->api_content_url . 'files/' . $root . '/' . ltrim($path,'/'));
|
||||
return $result['body'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads a new file
|
||||
*
|
||||
* @param string $path Target path (including filename)
|
||||
* @param string $file Either a path to a file or a stream resource
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return bool
|
||||
*/
|
||||
public function putFile($path, $file, $root = null) {
|
||||
|
||||
$directory = dirname($path);
|
||||
$filename = basename($path);
|
||||
|
||||
if($directory==='.') $directory = '';
|
||||
$directory = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($directory));
|
||||
// $filename = str_replace('~', '%7E', rawurlencode($filename));
|
||||
if (is_null($root)) $root = $this->root;
|
||||
|
||||
if (is_string($file)) {
|
||||
|
||||
$file = fopen($file,'rb');
|
||||
|
||||
} elseif (!is_resource($file)) {
|
||||
throw new Dropbox_Exception('File must be a file-resource or a string');
|
||||
}
|
||||
$result=$this->multipartFetch($this->api_content_url . 'files/' .
|
||||
$root . '/' . trim($directory,'/'), $file, $filename);
|
||||
|
||||
if(!isset($result["httpStatus"]) || $result["httpStatus"] != 200)
|
||||
throw new Dropbox_Exception("Uploading file to Dropbox failed");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies a file or directory from one location to another
|
||||
*
|
||||
* This method returns the file information of the newly created file.
|
||||
*
|
||||
* @param string $from source path
|
||||
* @param string $to destination path
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return stdclass
|
||||
*/
|
||||
public function copy($from, $to, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$response = $this->oauth->fetch($this->api_url . 'fileops/copy', array('from_path' => $from, 'to_path' => $to, 'root' => $root), 'POST');
|
||||
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new folder
|
||||
*
|
||||
* This method returns the information from the newly created directory
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return stdclass
|
||||
*/
|
||||
public function createFolder($path, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
|
||||
// Making sure the path starts with a /
|
||||
// $path = '/' . ltrim($path,'/');
|
||||
|
||||
$response = $this->oauth->fetch($this->api_url . 'fileops/create_folder', array('path' => $path, 'root' => $root),'POST');
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file or folder.
|
||||
*
|
||||
* This method will return the metadata information from the deleted file or folder, if successful.
|
||||
*
|
||||
* @param string $path Path to new folder
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return array
|
||||
*/
|
||||
public function delete($path, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$response = $this->oauth->fetch($this->api_url . 'fileops/delete', array('path' => $path, 'root' => $root), 'POST');
|
||||
return json_decode($response['body']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a file or directory to a new location
|
||||
*
|
||||
* This method returns the information from the newly created directory
|
||||
*
|
||||
* @param mixed $from Source path
|
||||
* @param mixed $to destination path
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return stdclass
|
||||
*/
|
||||
public function move($from, $to, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$response = $this->oauth->fetch($this->api_url . 'fileops/move', array('from_path' => rawurldecode($from), 'to_path' => rawurldecode($to), 'root' => $root), 'POST');
|
||||
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file and directory information
|
||||
*
|
||||
* @param string $path Path to receive information from
|
||||
* @param bool $list When set to true, this method returns information from all files in a directory. When set to false it will only return infromation from the specified directory.
|
||||
* @param string $hash If a hash is supplied, this method simply returns true if nothing has changed since the last request. Good for caching.
|
||||
* @param int $fileLimit Maximum number of file-information to receive
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return array|true
|
||||
*/
|
||||
public function getMetaData($path, $list = true, $hash = null, $fileLimit = null, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
|
||||
$args = array(
|
||||
'list' => $list,
|
||||
);
|
||||
|
||||
if (!is_null($hash)) $args['hash'] = $hash;
|
||||
if (!is_null($fileLimit)) $args['file_limit'] = $fileLimit;
|
||||
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
$response = $this->oauth->fetch($this->api_url . 'metadata/' . $root . '/' . ltrim($path,'/'), $args);
|
||||
|
||||
/* 304 is not modified */
|
||||
if ($response['httpStatus']==304) {
|
||||
return true;
|
||||
} else {
|
||||
return json_decode($response['body'],true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A way of letting you keep up with changes to files and folders in a user's Dropbox. You can periodically call /delta to get a list of "delta entries", which are instructions on how to update your local state to match the server's state.
|
||||
*
|
||||
* This method returns the information from the newly created directory
|
||||
*
|
||||
* @param string $cursor A string that is used to keep track of your current state. On the next call pass in this value to return delta entries that have been recorded since the cursor was returned.
|
||||
* @return stdclass
|
||||
*/
|
||||
public function delta($cursor) {
|
||||
|
||||
$arg['cursor'] = $cursor;
|
||||
|
||||
$response = $this->oauth->fetch($this->api_url . 'delta', $arg, 'POST');
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a thumbnail (as a string) for a file path.
|
||||
*
|
||||
* @param string $path Path to file
|
||||
* @param string $size small, medium or large
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @return string
|
||||
*/
|
||||
public function getThumbnail($path, $size = 'small', $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
$response = $this->oauth->fetch($this->api_content_url . 'thumbnails/' . $root . '/' . ltrim($path,'/'),array('size' => $size));
|
||||
|
||||
return $response['body'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to generate multipart POST requests for file upload
|
||||
*
|
||||
* @param string $uri
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected function multipartFetch($uri, $file, $filename) {
|
||||
|
||||
/* random string */
|
||||
$boundary = 'R50hrfBj5JYyfR3vF3wR96GPCC9Fd2q2pVMERvEaOE3D8LZTgLLbRpNwXek3';
|
||||
|
||||
$headers = array(
|
||||
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
|
||||
);
|
||||
|
||||
$body="--" . $boundary . "\r\n";
|
||||
$body.="Content-Disposition: form-data; name=file; filename=".rawurldecode($filename)."\r\n";
|
||||
$body.="Content-type: application/octet-stream\r\n";
|
||||
$body.="\r\n";
|
||||
$body.=stream_get_contents($file);
|
||||
$body.="\r\n";
|
||||
$body.="--" . $boundary . "--";
|
||||
|
||||
// Dropbox requires the filename to also be part of the regular arguments, so it becomes
|
||||
// part of the signature.
|
||||
$uri.='?file=' . $filename;
|
||||
|
||||
return $this->oauth->fetch($uri, $body, 'POST', $headers);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search
|
||||
*
|
||||
* Returns metadata for all files and folders that match the search query.
|
||||
*
|
||||
* @added by: diszo.sasil
|
||||
*
|
||||
* @param string $query
|
||||
* @param string $root Use this to override the default root path (sandbox/dropbox)
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
public function search($query = '', $root = null, $path = ''){
|
||||
if (is_null($root)) $root = $this->root;
|
||||
if(!empty($path)){
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
}
|
||||
$response = $this->oauth->fetch($this->api_url . 'search/' . $root . '/' . ltrim($path,'/'),array('query' => $query));
|
||||
return json_decode($response['body'],true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a shareable link to files or folders.
|
||||
*
|
||||
* Note: Links created by the /shares API call expire after thirty days.
|
||||
*
|
||||
* @param type $path
|
||||
* @param type $root
|
||||
* @return type
|
||||
*/
|
||||
public function share($path, $root = null) {
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
$response = $this->oauth->fetch($this->api_url. 'shares/'. $root . '/' . ltrim($path, '/'), array(), 'POST');
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a link directly to a file.
|
||||
* Similar to /shares. The difference is that this bypasses the Dropbox webserver, used to provide a preview of the file, so that you can effectively stream the contents of your media.
|
||||
*
|
||||
* Note: The /media link expires after four hours, allotting enough time to stream files, but not enough to leave a connection open indefinitely.
|
||||
*
|
||||
* @param type $path
|
||||
* @param type $root
|
||||
* @return type
|
||||
*/
|
||||
public function media($path, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
$response = $this->oauth->fetch($this->api_url. 'media/'. $root . '/' . ltrim($path, '/'), array(), 'POST');
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a copy_ref to a file. This reference string can be used to copy that file to another user's Dropbox by passing it in as the from_copy_ref parameter on /fileops/copy.
|
||||
*
|
||||
* @param type $path
|
||||
* @param type $root
|
||||
* @return type
|
||||
*/
|
||||
public function copy_ref($path, $root = null) {
|
||||
|
||||
if (is_null($root)) $root = $this->root;
|
||||
$path = str_replace(array('%2F','~'), array('/','%7E'), rawurlencode($path));
|
||||
$response = $this->oauth->fetch($this->api_url. 'copy_ref/'. $root . '/' . ltrim($path, '/'));
|
||||
return json_decode($response['body'],true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox base exception
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base exception class
|
||||
*/
|
||||
class Dropbox_Exception extends Exception { }
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox Forbidden exception
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* This exception is thrown when we receive the 403 forbidden response
|
||||
*/
|
||||
class Dropbox_Exception_Forbidden extends Dropbox_Exception {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox Not Found exception
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* This exception is thrown when a non-existant uri is accessed.
|
||||
*
|
||||
* Basically, this exception is used when we get back a 404.
|
||||
*/
|
||||
class Dropbox_Exception_NotFound extends Dropbox_Exception {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox Over Quota exception
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* This exception is thrown when the operation required more space than the available quota.
|
||||
*
|
||||
* Basically, this exception is used when we get back a 507.
|
||||
*/
|
||||
class Dropbox_Exception_OverQuota extends Dropbox_Exception {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox RequestToken exception
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* This exception is thrown when an error occured during the request_token process.
|
||||
*/
|
||||
class Dropbox_Exception_RequestToken extends Dropbox_Exception {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2010 Rooftop Solutions
|
||||
|
||||
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.
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox OAuth
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* This class is an abstract OAuth class.
|
||||
*
|
||||
* It must be extended by classes who wish to provide OAuth functionality
|
||||
* using different libraries.
|
||||
*/
|
||||
abstract class Dropbox_OAuth {
|
||||
|
||||
/**
|
||||
* After a user has authorized access, dropbox can redirect the user back
|
||||
* to this url.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $authorizeCallbackUrl = null;
|
||||
|
||||
/**
|
||||
* Uri used to fetch request tokens
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const URI_REQUEST_TOKEN = 'https://api.dropbox.com/1/oauth/request_token';
|
||||
|
||||
/**
|
||||
* Uri used to redirect the user to for authorization.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const URI_AUTHORIZE = 'https://www.dropbox.com/1/oauth/authorize';
|
||||
|
||||
/**
|
||||
* Uri used to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const URI_ACCESS_TOKEN = 'https://api.dropbox.com/1/oauth/access_token';
|
||||
|
||||
/**
|
||||
* An OAuth request token.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauth_token = null;
|
||||
|
||||
/**
|
||||
* OAuth token secret
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauth_token_secret = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $consumerKey
|
||||
* @param string $consumerSecret
|
||||
*/
|
||||
abstract public function __construct($consumerKey, $consumerSecret);
|
||||
|
||||
/**
|
||||
* Sets the request token and secret.
|
||||
*
|
||||
* The tokens can also be passed as an array into the first argument.
|
||||
* The array must have the elements token and token_secret.
|
||||
*
|
||||
* @param string|array $token
|
||||
* @param string $token_secret
|
||||
* @return void
|
||||
*/
|
||||
public function setToken($token, $token_secret = null) {
|
||||
|
||||
if (is_array($token)) {
|
||||
$this->oauth_token = $token['token'];
|
||||
$this->oauth_token_secret = $token['token_secret'];
|
||||
} else {
|
||||
$this->oauth_token = $token;
|
||||
$this->oauth_token_secret = $token_secret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oauth request tokens as an associative array.
|
||||
*
|
||||
* The array will contain the elements 'token' and 'token_secret'.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getToken() {
|
||||
|
||||
return array(
|
||||
'token' => $this->oauth_token,
|
||||
'token_secret' => $this->oauth_token_secret,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authorization url
|
||||
*
|
||||
* @param string $callBack Specify a callback url to automatically redirect the user back
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthorizeUrl($callBack = null) {
|
||||
|
||||
// Building the redirect uri
|
||||
$token = $this->getToken();
|
||||
$uri = self::URI_AUTHORIZE . '?oauth_token=' . $token['token'];
|
||||
if ($callBack) $uri.='&oauth_callback=' . $callBack;
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a secured oauth url and returns the response body.
|
||||
*
|
||||
* @param string $uri
|
||||
* @param mixed $arguments
|
||||
* @param string $method
|
||||
* @param array $httpHeaders
|
||||
* @return string
|
||||
*/
|
||||
public abstract function fetch($uri, $arguments = array(), $method = 'GET', $httpHeaders = array());
|
||||
|
||||
/**
|
||||
* Requests the OAuth request token.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getRequestToken();
|
||||
|
||||
/**
|
||||
* Requests the OAuth access tokens.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getAccessToken();
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* HTTP OAuth Consumer
|
||||
*
|
||||
* Adapted from halldirector's code in
|
||||
* http://code.google.com/p/dropbox-php/issues/detail?id=36#c5
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2011 Joe Constant / halldirector. All rights reserved.
|
||||
* @author Joe Constant / halldirector
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
require_once 'HTTP/OAuth.php';
|
||||
require_once 'HTTP/OAuth/Consumer.php';
|
||||
|
||||
/*
|
||||
* This class is to help work around aomw ssl issues.
|
||||
*/
|
||||
class Dropbox_OAuth_Consumer_Dropbox extends HTTP_OAuth_Consumer
|
||||
{
|
||||
public function getOAuthConsumerRequest()
|
||||
{
|
||||
if (!$this->consumerRequest instanceof HTTP_OAuth_Consumer_Request) {
|
||||
$this->consumerRequest = new HTTP_OAuth_Consumer_Request;
|
||||
}
|
||||
|
||||
// TODO: Change this and add in code to validate the SSL cert.
|
||||
// see https://github.com/bagder/curl/blob/master/lib/mk-ca-bundle.pl
|
||||
$this->consumerRequest->setConfig(array(
|
||||
'ssl_verify_peer' => false,
|
||||
'ssl_verify_host' => false
|
||||
));
|
||||
|
||||
return $this->consumerRequest;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Dropbox OAuth
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2011 Daniel Huesken
|
||||
* @author Daniel Huesken (http://www.danielhuesken.de/)
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class is used to sign all requests to dropbox.
|
||||
*
|
||||
* This specific class uses WordPress WP_Http to authenticate.
|
||||
*/
|
||||
class Dropbox_OAuth_Curl extends Dropbox_OAuth {
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string ConsumerKey
|
||||
*/
|
||||
protected $consumerKey = null;
|
||||
/**
|
||||
*
|
||||
* @var string ConsumerSecret
|
||||
*/
|
||||
protected $consumerSecret = null;
|
||||
/**
|
||||
*
|
||||
* @var string ProzessCallBack
|
||||
*/
|
||||
public $ProgressFunction = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $consumerKey
|
||||
* @param string $consumerSecret
|
||||
*/
|
||||
public function __construct($consumerKey, $consumerSecret) {
|
||||
if (!function_exists('curl_exec'))
|
||||
throw new Dropbox_Exception('The PHP curl functions not available!');
|
||||
|
||||
$this->consumerKey = $consumerKey;
|
||||
$this->consumerSecret = $consumerSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a secured oauth url and returns the response body.
|
||||
*
|
||||
* @param string $uri
|
||||
* @param mixed $arguments
|
||||
* @param string $method
|
||||
* @param array $httpHeaders
|
||||
* @return string
|
||||
*/
|
||||
public function fetch($uri, $arguments = array(), $method = 'GET', $httpHeaders = array()) {
|
||||
|
||||
$uri=str_replace('http://', 'https://', $uri); // all https, upload makes problems if not
|
||||
if (is_string($arguments) and strtoupper($method) == 'POST') {
|
||||
preg_match("/\?file=(.*)$/i", $uri, $matches);
|
||||
if (isset($matches[1])) {
|
||||
$uri = str_replace($matches[0], "", $uri);
|
||||
$filename = $matches[1];
|
||||
$httpHeaders=array_merge($httpHeaders,$this->getOAuthHeader($uri, array("file" => $filename), $method));
|
||||
}
|
||||
} else {
|
||||
$httpHeaders=array_merge($httpHeaders,$this->getOAuthHeader($uri, $arguments, $method));
|
||||
}
|
||||
$ch = curl_init();
|
||||
if (strtoupper($method) == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_URL, $uri);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
// if (is_array($arguments))
|
||||
// $arguments=http_build_query($arguments);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments);
|
||||
// $httpHeaders['Content-Length']=strlen($arguments);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_URL, $uri.'?'.http_build_query($arguments));
|
||||
curl_setopt($ch, CURLOPT_POST, false);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 300);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
// curl_setopt($ch, CURLOPT_CAINFO, "rootca");
|
||||
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
|
||||
//Build header
|
||||
$headers = array();
|
||||
foreach ($httpHeaders as $name => $value) {
|
||||
$headers[] = "{$name}: $value";
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
if (!ini_get('safe_mode') && !ini_get('open_basedir'))
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true );
|
||||
if (function_exists($this->ProgressFunction) and defined('CURLOPT_PROGRESSFUNCTION')) {
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, $this->ProgressFunction);
|
||||
curl_setopt($ch, CURLOPT_BUFFERSIZE, 512);
|
||||
}
|
||||
$response=curl_exec($ch);
|
||||
$errorno=curl_errno($ch);
|
||||
$error=curl_error($ch);
|
||||
$status=curl_getinfo($ch,CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
|
||||
if (!empty($errorno))
|
||||
throw new Dropbox_Exception_NotFound('Curl error: ('.$errorno.') '.$error."\n");
|
||||
|
||||
if ($status>=300) {
|
||||
$body = json_decode($response,true);
|
||||
switch ($status) {
|
||||
// Not modified
|
||||
case 304 :
|
||||
return array(
|
||||
'httpStatus' => 304,
|
||||
'body' => null,
|
||||
);
|
||||
break;
|
||||
case 403 :
|
||||
throw new Dropbox_Exception_Forbidden('Forbidden.
|
||||
This could mean a bad OAuth request, or a file or folder already existing at the target location.
|
||||
' . $body["error"] . "\n");
|
||||
case 404 :
|
||||
throw new Dropbox_Exception_NotFound('Resource at uri: ' . $uri . ' could not be found. ' .
|
||||
$body["error"] . "\n");
|
||||
case 507 :
|
||||
throw new Dropbox_Exception_OverQuota('This dropbox is full. ' .
|
||||
$body["error"] . "\n");
|
||||
}
|
||||
if (!empty($body["error"]))
|
||||
throw new Dropbox_Exception_RequestToken('Error: ('.$status.') '.$body["error"]."\n");
|
||||
}
|
||||
|
||||
return array(
|
||||
'body' => $response,
|
||||
'httpStatus' => $status
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns named array with oauth parameters for further use
|
||||
* @return array Array with oauth_ parameters
|
||||
*/
|
||||
private function getOAuthBaseParams() {
|
||||
$params['oauth_version'] = '1.0';
|
||||
$params['oauth_signature_method'] = 'HMAC-SHA1';
|
||||
|
||||
$params['oauth_consumer_key'] = $this->consumerKey;
|
||||
$tokens = $this->getToken();
|
||||
if (isset($tokens['token']) && $tokens['token']) {
|
||||
$params['oauth_token'] = $tokens['token'];
|
||||
}
|
||||
$params['oauth_timestamp'] = time();
|
||||
$params['oauth_nonce'] = md5(microtime() . mt_rand());
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates valid Authorization header for OAuth, based on URI and Params
|
||||
*
|
||||
* @param string $uri
|
||||
* @param array $params
|
||||
* @param string $method GET or POST, standard is GET
|
||||
* @param array $oAuthParams optional, pass your own oauth_params here
|
||||
* @return array Array for request's headers section like
|
||||
* array('Authorization' => 'OAuth ...');
|
||||
*/
|
||||
private function getOAuthHeader($uri, $params, $method = 'GET', $oAuthParams = null) {
|
||||
$oAuthParams = $oAuthParams ? $oAuthParams : $this->getOAuthBaseParams();
|
||||
|
||||
// create baseString to encode for the sent parameters
|
||||
$baseString = $method . '&';
|
||||
$baseString .= $this->oauth_urlencode($uri) . "&";
|
||||
|
||||
// OAuth header does not include GET-Parameters
|
||||
$signatureParams = array_merge($params, $oAuthParams);
|
||||
|
||||
// sorting the parameters
|
||||
ksort($signatureParams);
|
||||
|
||||
$encodedParams = array();
|
||||
foreach ($signatureParams as $key => $value) {
|
||||
$encodedParams[] = $this->oauth_urlencode($key) . '=' . $this->oauth_urlencode($value);
|
||||
}
|
||||
|
||||
$baseString .= $this->oauth_urlencode(implode('&', $encodedParams));
|
||||
|
||||
// encode the signature
|
||||
$tokens = $this->getToken();
|
||||
$hash = $this->hash_hmac_sha1($this->consumerSecret.'&'.$tokens['token_secret'], $baseString);
|
||||
$signature = base64_encode($hash);
|
||||
|
||||
// add signature to oAuthParams
|
||||
$oAuthParams['oauth_signature'] = $signature;
|
||||
|
||||
$oAuthEncoded = array();
|
||||
foreach ($oAuthParams as $key => $value) {
|
||||
$oAuthEncoded[] = $key . '="' . $this->oauth_urlencode($value) . '"';
|
||||
}
|
||||
|
||||
return array('Authorization' => 'OAuth ' . implode(', ', $oAuthEncoded));
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the OAuth request token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getRequestToken() {
|
||||
$result = $this->fetch(self::URI_REQUEST_TOKEN, array(), 'POST');
|
||||
if ($result['httpStatus'] == "200") {
|
||||
$tokens = array();
|
||||
parse_str($result['body'], $tokens);
|
||||
$this->setToken($tokens['oauth_token'], $tokens['oauth_token_secret']);
|
||||
return $this->getToken();
|
||||
} else {
|
||||
throw new Dropbox_Exception_RequestToken('We were unable to fetch request tokens. This likely means that your consumer key and/or secret are incorrect.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the OAuth access tokens.
|
||||
*
|
||||
* This method requires the 'unauthorized' request tokens
|
||||
* and, if successful will set the authorized request tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getAccessToken() {
|
||||
$result = $this->fetch(self::URI_ACCESS_TOKEN, array(), 'POST');
|
||||
if ($result['httpStatus'] == "200") {
|
||||
$tokens = array();
|
||||
parse_str($result['body'], $tokens);
|
||||
$this->setToken($tokens['oauth_token'], $tokens['oauth_token_secret']);
|
||||
return $this->getToken();
|
||||
} else {
|
||||
throw new Dropbox_Exception_RequestToken('We were unable to fetch request tokens. This likely means that your consumer key and/or secret are incorrect.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to properly urlencode parameters.
|
||||
* See http://php.net/manual/en/function.oauth-urlencode.php
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
private function oauth_urlencode($string) {
|
||||
return str_replace('%E7', '~', rawurlencode($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash function for hmac_sha1; uses native function if available.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
private function hash_hmac_sha1($key, $data) {
|
||||
if (function_exists('hash_hmac') && in_array('sha1', hash_algos())) {
|
||||
return hash_hmac('sha1', $data, $key, true);
|
||||
} else {
|
||||
$blocksize = 64;
|
||||
$hashfunc = 'sha1';
|
||||
if (strlen($key) > $blocksize) {
|
||||
$key = pack('H*', $hashfunc($key));
|
||||
}
|
||||
|
||||
$key = str_pad($key, $blocksize, chr(0x00));
|
||||
$ipad = str_repeat(chr(0x36), $blocksize);
|
||||
$opad = str_repeat(chr(0x5c), $blocksize);
|
||||
$hash = pack('H*', $hashfunc(( $key ^ $opad ) . pack('H*', $hashfunc(($key ^ $ipad) . $data))));
|
||||
|
||||
return $hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
Dropbox-php
|
||||
===========
|
||||
|
||||
This PHP library allows you to easily integrate dropbox with PHP.
|
||||
|
||||
The following PHP extension is required:
|
||||
|
||||
* json
|
||||
|
||||
The library makes use of OAuth. At the moment you can use either of these libraries:
|
||||
|
||||
[PHP OAuth extension](http://pecl.php.net/package/oauth)
|
||||
[PEAR's HTTP_OAUTH package](http://pear.php.net/package/http_oauth)
|
||||
|
||||
The extension is recommended, but if you can't install php extensions you should go for the pear package.
|
||||
Installing
|
||||
----------
|
||||
|
||||
pear channel-discover pear.dropbox-php.com
|
||||
pear install dropbox-php/Dropbox-alpha
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Check out the [documentation](http://www.dropbox-php.com/docs).
|
||||
|
||||
Questions?
|
||||
----------
|
||||
|
||||
[Dropbox-php Mailing list](http://groups.google.com/group/dropbox-php)
|
||||
[Official Dropbox developer forum](http://forums.dropbox.com/forum.php?id=5)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file registers a new autoload function using spl_autoload_register.
|
||||
*
|
||||
* @package Dropbox
|
||||
* @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/dropbox-php/wiki/License MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Autoloader function
|
||||
*
|
||||
* @param $className string
|
||||
* @return void
|
||||
*/
|
||||
function Dropbox_autoload($className) {
|
||||
|
||||
if(strpos($className,'Dropbox_')===0) {
|
||||
|
||||
include dirname(__FILE__) . '/' . str_replace('_','/',substr($className,8)) . '.php';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
spl_autoload_register('Dropbox_autoload');
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License
|
||||
|
||||
Copyright (c) 2007 Andy Smith
|
||||
|
||||
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.
|
|
@ -0,0 +1,751 @@
|
|||
<?php
|
||||
// vim: foldmethod=marker
|
||||
|
||||
/* Generic exception class
|
||||
*/
|
||||
class OAuthException extends Exception {/*{{{*/
|
||||
// pass
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthConsumer {/*{{{*/
|
||||
public $key;
|
||||
public $secret;
|
||||
|
||||
public function __construct($key, $secret, $callback_url=NULL) {/*{{{*/
|
||||
$this->key = $key;
|
||||
$this->secret = $secret;
|
||||
$this->callback_url = $callback_url;
|
||||
}/*}}}*/
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthToken {/*{{{*/
|
||||
// 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=" . OAuthUtil::urlencodeRFC3986($this->key) .
|
||||
"&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret);
|
||||
}/*}}}*/
|
||||
|
||||
function __toString() {/*{{{*/
|
||||
return $this->to_string();
|
||||
}/*}}}*/
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthSignatureMethod {/*{{{*/
|
||||
public function check_signature(&$request, $consumer, $token, $signature) {
|
||||
$built = $this->build_signature($request, $consumer, $token);
|
||||
return $built == $signature;
|
||||
}
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/
|
||||
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('OAuthUtil','urlencodeRFC3986'), $key_parts);
|
||||
$key = implode('&', $key_parts);
|
||||
|
||||
return base64_encode( hash_hmac('sha1', $base_string, $key, true));
|
||||
}/*}}}*/
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {/*{{{*/
|
||||
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 OAuthRequest {/*{{{*/
|
||||
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 = OAuthRequest::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 OAuthRequest($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 = OAuthRequest::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 OAuthRequest($http_method, $http_url, $parameters);
|
||||
}
|
||||
else if ($http_method == "GET") {
|
||||
$req = new OAuthRequest($http_method, $http_url, $_GET);
|
||||
}
|
||||
else if ($http_method == "POST") {
|
||||
$req = new OAuthRequest($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" => OAuthRequest::$version,
|
||||
"oauth_nonce" => OAuthRequest::generate_nonce(),
|
||||
"oauth_timestamp" => OAuthRequest::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 OAuthRequest($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('OAuthUtil', 'urlencodeRFC3986'), array_keys($params));
|
||||
$values = array_map(array('OAuthUtil', '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('OAuthUtil', '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);
|
||||
|
||||
$scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
|
||||
$port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
|
||||
$host = (isset($parts['host'])) ? strtolower($parts['host']) : '';
|
||||
$path = (isset($parts['path'])) ? $parts['path'] : '';
|
||||
|
||||
if (($scheme == 'https' && $port != '443')
|
||||
|| ($scheme == 'http' && $port != '80')) {
|
||||
$host = "$host:$port";
|
||||
}
|
||||
return "$scheme://$host$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[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v);
|
||||
}
|
||||
$out = implode("&", $total);
|
||||
return $out;
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* builds the Authorization: header
|
||||
*/
|
||||
public function to_header() {/*{{{*/
|
||||
$out ='Authorization: OAuth ';
|
||||
$total = array();
|
||||
|
||||
/*
|
||||
$sig = $this->parameters['oauth_signature'];
|
||||
unset($this->parameters['oauth_signature']);
|
||||
uksort($this->parameters, 'strnatcmp');
|
||||
$this->parameters['oauth_signature'] = $sig;
|
||||
*/
|
||||
|
||||
foreach ($this->parameters as $k => $v) {
|
||||
if (substr($k, 0, 5) != "oauth") continue;
|
||||
$out .= OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::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 OAuthServer {/*{{{*/
|
||||
protected $timestamp_threshold = 300; // in seconds, five minutes
|
||||
protected $version = 1.0; // hi blaine
|
||||
protected $signature_methods = array();
|
||||
|
||||
protected $data_store;
|
||||
|
||||
function __construct($data_store) {/*{{{*/
|
||||
$this->data_store = $data_store;
|
||||
}/*}}}*/
|
||||
|
||||
public function add_signature_method($signature_method) {/*{{{*/
|
||||
$this->signature_methods[$signature_method->get_name()] =
|
||||
$signature_method;
|
||||
}/*}}}*/
|
||||
|
||||
// high level functions
|
||||
|
||||
/**
|
||||
* process a request_token request
|
||||
* returns the request token on success
|
||||
*/
|
||||
public function fetch_request_token(&$request) {/*{{{*/
|
||||
$this->get_version($request);
|
||||
|
||||
$consumer = $this->get_consumer($request);
|
||||
|
||||
// no token required for the initial token request
|
||||
$token = NULL;
|
||||
|
||||
$this->check_signature($request, $consumer, $token);
|
||||
|
||||
$new_token = $this->data_store->new_request_token($consumer);
|
||||
|
||||
return $new_token;
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* process an access_token request
|
||||
* returns the access token on success
|
||||
*/
|
||||
public function fetch_access_token(&$request) {/*{{{*/
|
||||
$this->get_version($request);
|
||||
|
||||
$consumer = $this->get_consumer($request);
|
||||
|
||||
// requires authorized request token
|
||||
$token = $this->get_token($request, $consumer, "request");
|
||||
|
||||
$this->check_signature($request, $consumer, $token);
|
||||
|
||||
$new_token = $this->data_store->new_access_token($token, $consumer);
|
||||
|
||||
return $new_token;
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* verify an api call, checks all the parameters
|
||||
*/
|
||||
public function verify_request(&$request) {/*{{{*/
|
||||
$this->get_version($request);
|
||||
$consumer = $this->get_consumer($request);
|
||||
$token = $this->get_token($request, $consumer, "access");
|
||||
$this->check_signature($request, $consumer, $token);
|
||||
return array($consumer, $token);
|
||||
}/*}}}*/
|
||||
|
||||
// Internals from here
|
||||
/**
|
||||
* version 1
|
||||
*/
|
||||
private function get_version(&$request) {/*{{{*/
|
||||
$version = $request->get_parameter("oauth_version");
|
||||
if (!$version) {
|
||||
$version = 1.0;
|
||||
}
|
||||
if ($version && $version != $this->version) {
|
||||
throw new OAuthException("OAuth version '$version' not supported");
|
||||
}
|
||||
return $version;
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* figure out the signature with some defaults
|
||||
*/
|
||||
private function get_signature_method(&$request) {/*{{{*/
|
||||
$signature_method =
|
||||
@$request->get_parameter("oauth_signature_method");
|
||||
if (!$signature_method) {
|
||||
$signature_method = "PLAINTEXT";
|
||||
}
|
||||
if (!in_array($signature_method,
|
||||
array_keys($this->signature_methods))) {
|
||||
throw new OAuthException(
|
||||
"Signature method '$signature_method' not supported try one of the following: " . implode(", ", array_keys($this->signature_methods))
|
||||
);
|
||||
}
|
||||
return $this->signature_methods[$signature_method];
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* try to find the consumer for the provided request's consumer key
|
||||
*/
|
||||
private function get_consumer(&$request) {/*{{{*/
|
||||
$consumer_key = @$request->get_parameter("oauth_consumer_key");
|
||||
if (!$consumer_key) {
|
||||
throw new OAuthException("Invalid consumer key");
|
||||
}
|
||||
|
||||
$consumer = $this->data_store->lookup_consumer($consumer_key);
|
||||
if (!$consumer) {
|
||||
throw new OAuthException("Invalid consumer");
|
||||
}
|
||||
|
||||
return $consumer;
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* try to find the token for the provided request's token key
|
||||
*/
|
||||
private function get_token(&$request, $consumer, $token_type="access") {/*{{{*/
|
||||
$token_field = @$request->get_parameter('oauth_token');
|
||||
$token = $this->data_store->lookup_token(
|
||||
$consumer, $token_type, $token_field
|
||||
);
|
||||
if (!$token) {
|
||||
throw new OAuthException("Invalid $token_type token: $token_field");
|
||||
}
|
||||
return $token;
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* all-in-one function to check the signature on a request
|
||||
* should guess the signature method appropriately
|
||||
*/
|
||||
private function check_signature(&$request, $consumer, $token) {/*{{{*/
|
||||
// this should probably be in a different method
|
||||
$timestamp = @$request->get_parameter('oauth_timestamp');
|
||||
$nonce = @$request->get_parameter('oauth_nonce');
|
||||
|
||||
$this->check_timestamp($timestamp);
|
||||
$this->check_nonce($consumer, $token, $nonce, $timestamp);
|
||||
|
||||
$signature_method = $this->get_signature_method($request);
|
||||
|
||||
$signature = $request->get_parameter('oauth_signature');
|
||||
$valid_sig = $signature_method->check_signature(
|
||||
$request,
|
||||
$consumer,
|
||||
$token,
|
||||
$signature
|
||||
);
|
||||
|
||||
if (!$valid_sig) {
|
||||
throw new OAuthException("Invalid signature");
|
||||
}
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* check that the timestamp is new enough
|
||||
*/
|
||||
private function check_timestamp($timestamp) {/*{{{*/
|
||||
// verify that timestamp is recentish
|
||||
$now = time();
|
||||
if ($now - $timestamp > $this->timestamp_threshold) {
|
||||
throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
|
||||
}
|
||||
}/*}}}*/
|
||||
|
||||
/**
|
||||
* check that the nonce is not repeated
|
||||
*/
|
||||
private function check_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
|
||||
// verify that the nonce is uniqueish
|
||||
$found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp);
|
||||
if ($found) {
|
||||
throw new OAuthException("Nonce already used: $nonce");
|
||||
}
|
||||
}/*}}}*/
|
||||
|
||||
|
||||
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthDataStore {/*{{{*/
|
||||
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
|
||||
}/*}}}*/
|
||||
|
||||
}/*}}}*/
|
||||
|
||||
|
||||
/* A very naive dbm-based oauth storage
|
||||
*/
|
||||
class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/
|
||||
private $dbh;
|
||||
|
||||
function __construct($path = "oauth.gdbm") {/*{{{*/
|
||||
$this->dbh = dba_popen($path, 'c', 'gdbm');
|
||||
}/*}}}*/
|
||||
|
||||
function __destruct() {/*{{{*/
|
||||
dba_close($this->dbh);
|
||||
}/*}}}*/
|
||||
|
||||
function lookup_consumer($consumer_key) {/*{{{*/
|
||||
$rv = dba_fetch("consumer_$consumer_key", $this->dbh);
|
||||
if ($rv === FALSE) {
|
||||
return NULL;
|
||||
}
|
||||
$obj = unserialize($rv);
|
||||
if (!($obj instanceof OAuthConsumer)) {
|
||||
return NULL;
|
||||
}
|
||||
return $obj;
|
||||
}/*}}}*/
|
||||
|
||||
function lookup_token($consumer, $token_type, $token) {/*{{{*/
|
||||
$rv = dba_fetch("${token_type}_${token}", $this->dbh);
|
||||
if ($rv === FALSE) {
|
||||
return NULL;
|
||||
}
|
||||
$obj = unserialize($rv);
|
||||
if (!($obj instanceof OAuthToken)) {
|
||||
return NULL;
|
||||
}
|
||||
return $obj;
|
||||
}/*}}}*/
|
||||
|
||||
function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
|
||||
return dba_exists("nonce_$nonce", $this->dbh);
|
||||
}/*}}}*/
|
||||
|
||||
function new_token($consumer, $type="request") {/*{{{*/
|
||||
$key = md5(time());
|
||||
$secret = time() + time();
|
||||
$token = new OAuthToken($key, md5(md5($secret)));
|
||||
if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) {
|
||||
throw new OAuthException("doooom!");
|
||||
}
|
||||
return $token;
|
||||
}/*}}}*/
|
||||
|
||||
function new_request_token($consumer) {/*{{{*/
|
||||
return $this->new_token($consumer, "request");
|
||||
}/*}}}*/
|
||||
|
||||
function new_access_token($token, $consumer) {/*{{{*/
|
||||
|
||||
$token = $this->new_token($consumer, 'access');
|
||||
dba_delete("request_" . $token->key, $this->dbh);
|
||||
return $token;
|
||||
}/*}}}*/
|
||||
}/*}}}*/
|
||||
|
||||
class OAuthUtil {/*{{{*/
|
||||
public static function urlencodeRFC3986($string) {/*{{{*/
|
||||
return str_replace('%7E', '~', rawurlencode($string));
|
||||
}/*}}}*/
|
||||
|
||||
public static function urldecodeRFC3986($string) {/*{{{*/
|
||||
return rawurldecode($string);
|
||||
}/*}}}*/
|
||||
}/*}}}*/
|
||||
|
||||
?>
|
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
/* Copyright (c) 2009 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: Eric Bidelman <e.bidelman@google.com>
|
||||
*/
|
||||
|
||||
$PRIV_KEY_FILE = '/path/to/your/rsa_private_key.pem';
|
||||
|
||||
// OAuth library - http://oauth.googlecode.com/svn/code/php/
|
||||
require_once('OAuth.php');
|
||||
|
||||
// Google's accepted signature methods
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
$rsa_method = new OAuthSignatureMethod_RSA_SHA1();
|
||||
$SIG_METHODS = array($rsa_method->get_name() => $rsa_method,
|
||||
$hmac_method->get_name() => $hmac_method);
|
||||
|
||||
/**
|
||||
* Makes an HTTP request to the specified URL
|
||||
*
|
||||
* @param string $http_method The HTTP method (GET, POST, PUT, DELETE)
|
||||
* @param string $url Full URL of the resource to access
|
||||
* @param array $extraHeaders (optional) Additional headers to include in each
|
||||
* request. Elements are header/value pair strings ('Host: example.com')
|
||||
* @param string $postData (optional) POST/PUT request body
|
||||
* @param bool $returnResponseHeaders True if resp. headers should be returned.
|
||||
* @return string Response body from the server
|
||||
*/
|
||||
function send_signed_request($http_method, $url, $extraHeaders=null,
|
||||
$postData=null, $returnResponseHeaders=true) {
|
||||
$curl = curl_init($url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_FAILONERROR, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
|
||||
// Return request headers in the reponse
|
||||
// curl_setopt($curl, CURLINFO_HEADER_OUT, true);
|
||||
|
||||
// Return response headers ni the response?
|
||||
if ($returnResponseHeaders) {
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
}
|
||||
|
||||
$headers = array();
|
||||
//$headers[] = 'GData-Version: 2.0'; // use GData v2 by default
|
||||
if (is_array($extraHeaders)) {
|
||||
$headers = array_merge($headers, $extraHeaders);
|
||||
}
|
||||
|
||||
// Setup default curl options for each type of HTTP request.
|
||||
// This is also a great place to add additional headers for each request.
|
||||
switch($http_method) {
|
||||
case 'GET':
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
break;
|
||||
case 'POST':
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||||
break;
|
||||
case 'PUT':
|
||||
$headers[] = 'If-Match: *';
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||||
break;
|
||||
case 'DELETE':
|
||||
$headers[] = 'If-Match: *';
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method);
|
||||
break;
|
||||
default:
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
|
||||
// Execute the request. If an error occures, fill the response body with it.
|
||||
$response = curl_exec($curl);
|
||||
if (!$response) {
|
||||
$response = curl_error($curl);
|
||||
}
|
||||
|
||||
// Add server's response headers to our response body
|
||||
$response = curl_getinfo($curl, CURLINFO_HEADER_OUT) . $response;
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes XML as a string and returns it nicely indented
|
||||
*
|
||||
* @param string $xml The xml to beautify
|
||||
* @param boolean $html_output True if returned XML should be escaped for HTML.
|
||||
* @return string The beautified xml
|
||||
*/
|
||||
function xml_pretty_printer($xml, $html_output=false) {
|
||||
$xml_obj = new SimpleXMLElement($xml);
|
||||
$level = 2;
|
||||
|
||||
// Get an array containing each XML element
|
||||
$xml = explode("\n", preg_replace('/>\s*</', ">\n<", $xml_obj->asXML()));
|
||||
|
||||
// Hold current indentation level
|
||||
$indent = 0;
|
||||
|
||||
$pretty = array();
|
||||
|
||||
// Shift off opening XML tag if present
|
||||
if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) {
|
||||
$pretty[] = array_shift($xml);
|
||||
}
|
||||
|
||||
foreach ($xml as $el) {
|
||||
if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) {
|
||||
// opening tag, increase indent
|
||||
$pretty[] = str_repeat(' ', $indent) . $el;
|
||||
$indent += $level;
|
||||
} else {
|
||||
if (preg_match('/^<\/.+>$/', $el)) {
|
||||
$indent -= $level; // closing tag, decrease indent
|
||||
}
|
||||
if ($indent < 0) {
|
||||
$indent += $level;
|
||||
}
|
||||
$pretty[] = str_repeat(' ', $indent) . $el;
|
||||
}
|
||||
}
|
||||
|
||||
$xml = implode("\n", $pretty);
|
||||
return $html_output ? htmlentities($xml) : $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins key/value pairs by $inner_glue and each pair together by $outer_glue.
|
||||
*
|
||||
* Example: implode_assoc('=', '&', array('a' => 1, 'b' => 2)) === 'a=1&b=2'
|
||||
*
|
||||
* @param string $inner_glue What to implode each key/value pair with
|
||||
* @param string $outer_glue What to impode each key/value string subset with
|
||||
* @param array $array Associative array of query parameters
|
||||
* @return string Urlencoded string of query parameters
|
||||
*/
|
||||
function implode_assoc($inner_glue, $outer_glue, $array) {
|
||||
$output = array();
|
||||
foreach($array as $key => $item) {
|
||||
$output[] = $key . $inner_glue . urlencode($item);
|
||||
}
|
||||
return implode($outer_glue, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explodes a string of key/value url parameters into an associative array.
|
||||
* This method performs the compliment operations of implode_assoc().
|
||||
*
|
||||
* Example: explode_assoc('=', '&', 'a=1&b=2') === array('a' => 1, 'b' => 2)
|
||||
*
|
||||
* @param string $inner_glue What each key/value pair is joined with
|
||||
* @param string $outer_glue What each set of key/value pairs is joined with.
|
||||
* @param array $array Associative array of query parameters
|
||||
* @return array Urlencoded string of query parameters
|
||||
*/
|
||||
function explode_assoc($inner_glue, $outer_glue, $params) {
|
||||
$tempArr = explode($outer_glue, $params);
|
||||
foreach($tempArr as $val) {
|
||||
$pos = strpos($val, $inner_glue);
|
||||
$key = substr($val, 0, $pos);
|
||||
$array2[$key] = substr($val, $pos + 1, strlen($val));
|
||||
}
|
||||
return $array2;
|
||||
}
|
||||
|
||||
?>
|
|
@ -146,33 +146,6 @@ class MDB2_Schema_Parser extends XML_Parser
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 4 compatible constructor
|
||||
*
|
||||
* @param array $variables mixed array with user defined schema
|
||||
* variables
|
||||
* @param bool $fail_on_invalid_names array with reserved words per RDBMS
|
||||
* @param array $structure multi dimensional array with
|
||||
* database schema and data
|
||||
* @param array $valid_types information of all valid fields
|
||||
* types
|
||||
* @param bool $force_defaults if true sets a default value to
|
||||
* field when not explicit
|
||||
* @param int $max_identifiers_length maximum allowed size for entities
|
||||
* name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function MDB2_Schema_Parser($variables, $fail_on_invalid_names = true,
|
||||
$structure = false, $valid_types = array(), $force_defaults = true,
|
||||
$max_identifiers_length = null
|
||||
) {
|
||||
$this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when reading a XML open tag <element>
|
||||
*
|
||||
|
|
|
@ -143,33 +143,6 @@ class MDB2_Schema_Parser2 extends XML_Unserializer
|
|||
parent::XML_Unserializer($this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 4 compatible constructor
|
||||
*
|
||||
* @param array $variables mixed array with user defined schema
|
||||
* variables
|
||||
* @param bool $fail_on_invalid_names array with reserved words per RDBMS
|
||||
* @param array $structure multi dimensional array with
|
||||
* database schema and data
|
||||
* @param array $valid_types information of all valid fields
|
||||
* types
|
||||
* @param bool $force_defaults if true sets a default value to
|
||||
* field when not explicit
|
||||
* @param int $max_identifiers_length maximum allowed size for entities
|
||||
* name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function MDB2_Schema_Parser2($variables, $fail_on_invalid_names = true,
|
||||
$structure = false, $valid_types = array(), $force_defaults = true,
|
||||
$max_identifiers_length = null
|
||||
) {
|
||||
$this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method. Parses XML Schema File.
|
||||
*
|
||||
|
|
|
@ -108,28 +108,6 @@ class MDB2_Schema_Validate
|
|||
$this->max_identifiers_length = $max_identifiers_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 4 compatible constructor
|
||||
*
|
||||
* @param bool $fail_on_invalid_names array with reserved words per RDBMS
|
||||
* @param array $valid_types information of all valid fields
|
||||
* types
|
||||
* @param bool $force_defaults if true sets a default value to
|
||||
* field when not explicit
|
||||
* @param int $max_identifiers_length maximum allowed size for entities
|
||||
* name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function MDB2_Schema_Validate($fail_on_invalid_names = true, $valid_types = array(),
|
||||
$force_defaults = true, $max_identifiers_length = null
|
||||
) {
|
||||
$this->__construct($fail_on_invalid_names, $valid_types, $force_defaults);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ raiseError()
|
||||
|
||||
|
|
|
@ -82,22 +82,6 @@ class MDB2_Schema_Writer
|
|||
$this->valid_types = $valid_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP 4 compatible constructor
|
||||
*
|
||||
* @param array $valid_types information of all valid fields
|
||||
* types
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function MDB2_Schema_Writer($valid_types = array())
|
||||
{
|
||||
$this->__construct($valid_types);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ raiseError()
|
||||
|
||||
|
|
|
@ -294,6 +294,7 @@ class Sabre_CalDAV_CalendarQueryValidator {
|
|||
// in the VALARM component code, so this is a hack, and an
|
||||
// expensive one too.
|
||||
if ($component->parent->name === 'VEVENT' && $component->parent->RRULE) {
|
||||
|
||||
// Fire up the iterator!
|
||||
$it = new Sabre_VObject_RecurrenceIterator($component->parent->parent, (string)$component->parent->UID);
|
||||
while($it->valid()) {
|
||||
|
@ -303,15 +304,37 @@ class Sabre_CalDAV_CalendarQueryValidator {
|
|||
// one is the first to trigger. Based on this, we can
|
||||
// determine if we can 'give up' expanding events.
|
||||
$firstAlarm = null;
|
||||
foreach($expandedEvent->VALARM as $expandedAlarm) {
|
||||
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
||||
if (!$firstAlarm || $effectiveTrigger < $firstAlarm) {
|
||||
$firstAlarm = $effectiveTrigger;
|
||||
}
|
||||
if ($expandedAlarm->isInTimeRange($start, $end)) {
|
||||
return true;
|
||||
}
|
||||
if ($expandedEvent->VALARM !== null) {
|
||||
foreach($expandedEvent->VALARM as $expandedAlarm) {
|
||||
|
||||
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
||||
if ($expandedAlarm->isInTimeRange($start, $end)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((string)$expandedAlarm->TRIGGER['VALUE'] === 'DATE-TIME') {
|
||||
// This is an alarm with a non-relative trigger
|
||||
// time, likely created by a buggy client. The
|
||||
// implication is that every alarm in this
|
||||
// recurring event trigger at the exact same
|
||||
// time. It doesn't make sense to traverse
|
||||
// further.
|
||||
} else {
|
||||
// We store the first alarm as a means to
|
||||
// figure out when we can stop traversing.
|
||||
if (!$firstAlarm || $effectiveTrigger < $firstAlarm) {
|
||||
$firstAlarm = $effectiveTrigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_null($firstAlarm)) {
|
||||
// No alarm was found.
|
||||
//
|
||||
// Or technically: No alarm that will change for
|
||||
// every instance of the recurrence was found,
|
||||
// which means we can assume there was no match.
|
||||
return false;
|
||||
}
|
||||
if ($firstAlarm > $end) {
|
||||
return false;
|
||||
|
|
|
@ -49,23 +49,23 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
/**
|
||||
* The email handler for invites and other scheduling messages.
|
||||
*
|
||||
* @var Sabre_CalDAV_Schedule_IMip
|
||||
*
|
||||
* @var Sabre_CalDAV_Schedule_IMip
|
||||
*/
|
||||
protected $imipHandler;
|
||||
|
||||
/**
|
||||
* Sets the iMIP handler.
|
||||
*
|
||||
* iMIP = The email transport of iCalendar scheduling messages. Setting
|
||||
* this is optional, but if you want the server to allow invites to be sent
|
||||
* iMIP = The email transport of iCalendar scheduling messages. Setting
|
||||
* this is optional, but if you want the server to allow invites to be sent
|
||||
* out, you must set a handler.
|
||||
*
|
||||
* Specifically iCal will plain assume that the server supports this. If
|
||||
* the server doesn't, iCal will display errors when inviting people to
|
||||
* Specifically iCal will plain assume that the server supports this. If
|
||||
* the server doesn't, iCal will display errors when inviting people to
|
||||
* events.
|
||||
*
|
||||
* @param Sabre_CalDAV_Schedule_IMip $imipHandler
|
||||
* @param Sabre_CalDAV_Schedule_IMip $imipHandler
|
||||
* @return void
|
||||
*/
|
||||
public function setIMipHandler(Sabre_CalDAV_Schedule_IMip $imipHandler) {
|
||||
|
@ -672,6 +672,42 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
}
|
||||
|
||||
if ($vobj->name !== 'VCALENDAR') {
|
||||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support iCalendar objects.');
|
||||
}
|
||||
|
||||
$foundType = null;
|
||||
$foundUID = null;
|
||||
foreach($vobj->getComponents() as $component) {
|
||||
switch($component->name) {
|
||||
case 'VTIMEZONE' :
|
||||
continue 2;
|
||||
case 'VEVENT' :
|
||||
case 'VTODO' :
|
||||
case 'VJOURNAL' :
|
||||
if (is_null($foundType)) {
|
||||
$foundType = $component->name;
|
||||
if (!isset($component->UID)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Every ' . $component->name . ' component must have an UID');
|
||||
}
|
||||
$foundUID = (string)$component->UID;
|
||||
} else {
|
||||
if ($foundType !== $component->name) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('A calendar object must only contain 1 component. We found a ' . $component->name . ' as well as a ' . $foundType);
|
||||
}
|
||||
if ($foundUID !== (string)$component->UID) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Every ' . $component->name . ' in this object must have identical UIDs');
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
throw new Sabre_DAV_Exception_BadRequest('You are not allowed to create components of type: ' . $component->name . ' here');
|
||||
|
||||
}
|
||||
}
|
||||
if (!$foundType)
|
||||
throw new Sabre_DAV_Exception_BadRequest('iCalendar object must contain at least 1 of VEVENT, VTODO or VJOURNAL');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -687,12 +723,12 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
if (!$originator) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The Originator: header must be specified when making POST requests');
|
||||
}
|
||||
}
|
||||
if (!$recipients) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The Recipient: header must be specified when making POST requests');
|
||||
}
|
||||
}
|
||||
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/', $originator)) {
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/i', $originator)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Originator must start with mailto: and must be valid email address');
|
||||
}
|
||||
$originator = substr($originator,7);
|
||||
|
@ -701,14 +737,14 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
foreach($recipients as $k=>$recipient) {
|
||||
|
||||
$recipient = trim($recipient);
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/', $recipient)) {
|
||||
if (!preg_match('/^mailto:(.*)@(.*)$/i', $recipient)) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Recipients must start with mailto: and must be valid email address');
|
||||
}
|
||||
$recipient = substr($recipient, 7);
|
||||
$recipients[$k] = $recipient;
|
||||
}
|
||||
|
||||
// We need to make sure that 'originator' matches one of the email
|
||||
// We need to make sure that 'originator' matches one of the email
|
||||
// addresses of the selected principal.
|
||||
$principal = $outboxNode->getOwner();
|
||||
$props = $this->server->getProperties($principal,array(
|
||||
|
@ -724,7 +760,7 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
throw new Sabre_DAV_Exception_Forbidden('The addresses specified in the Originator header did not match any addresses in the owners calendar-user-address-set header');
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
$vObject = Sabre_VObject_Reader::read($this->server->httpRequest->getBody(true));
|
||||
} catch (Sabre_VObject_ParseException $e) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
|
||||
|
@ -749,9 +785,10 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
}
|
||||
|
||||
if (in_array($method, array('REQUEST','REPLY','ADD','CANCEL')) && $componentType==='VEVENT') {
|
||||
$this->iMIPMessage($originator, $recipients, $vObject);
|
||||
$result = $this->iMIPMessage($originator, $recipients, $vObject);
|
||||
$this->server->httpResponse->sendStatus(200);
|
||||
$this->server->httpResponse->sendBody('Messages sent');
|
||||
$this->server->httpResponse->setHeader('Content-Type','application/xml');
|
||||
$this->server->httpResponse->sendBody($this->generateScheduleResponse($result));
|
||||
} else {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('This iTIP method is currently not implemented');
|
||||
}
|
||||
|
@ -760,18 +797,83 @@ class Sabre_CalDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
/**
|
||||
* Sends an iMIP message by email.
|
||||
*
|
||||
* @param string $originator
|
||||
* @param array $recipients
|
||||
* @param Sabre_VObject_Component $vObject
|
||||
* @return void
|
||||
*
|
||||
* This method must return an array with status codes per recipient.
|
||||
* This should look something like:
|
||||
*
|
||||
* array(
|
||||
* 'user1@example.org' => '2.0;Success'
|
||||
* )
|
||||
*
|
||||
* Formatting for this status code can be found at:
|
||||
* https://tools.ietf.org/html/rfc5545#section-3.8.8.3
|
||||
*
|
||||
* A list of valid status codes can be found at:
|
||||
* https://tools.ietf.org/html/rfc5546#section-3.6
|
||||
*
|
||||
* @param string $originator
|
||||
* @param array $recipients
|
||||
* @param Sabre_VObject_Component $vObject
|
||||
* @return array
|
||||
*/
|
||||
protected function iMIPMessage($originator, array $recipients, Sabre_VObject_Component $vObject) {
|
||||
|
||||
if (!$this->imipHandler) {
|
||||
throw new Sabre_DAV_Exception_NotImplemented('No iMIP handler is setup on this server.');
|
||||
$resultStatus = '5.2;This server does not support this operation';
|
||||
} else {
|
||||
$this->imipHandler->sendMessage($originator, $recipients, $vObject);
|
||||
$resultStatus = '2.0;Success';
|
||||
}
|
||||
$this->imipHandler->sendMessage($originator, $recipients, $vObject);
|
||||
|
||||
$result = array();
|
||||
foreach($recipients as $recipient) {
|
||||
$result[$recipient] = $resultStatus;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a schedule-response XML body
|
||||
*
|
||||
* The recipients array is a key->value list, containing email addresses
|
||||
* and iTip status codes. See the iMIPMessage method for a description of
|
||||
* the value.
|
||||
*
|
||||
* @param array $recipients
|
||||
* @return string
|
||||
*/
|
||||
public function generateScheduleResponse(array $recipients) {
|
||||
|
||||
$dom = new DOMDocument('1.0','utf-8');
|
||||
$dom->formatOutput = true;
|
||||
$xscheduleResponse = $dom->createElement('cal:schedule-response');
|
||||
$dom->appendChild($xscheduleResponse);
|
||||
|
||||
foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
|
||||
|
||||
$xscheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
|
||||
|
||||
}
|
||||
|
||||
foreach($recipients as $recipient=>$status) {
|
||||
$xresponse = $dom->createElement('cal:response');
|
||||
|
||||
$xrecipient = $dom->createElement('cal:recipient');
|
||||
$xrecipient->appendChild($dom->createTextNode($recipient));
|
||||
$xresponse->appendChild($xrecipient);
|
||||
|
||||
$xrequestStatus = $dom->createElement('cal:request-status');
|
||||
$xrequestStatus->appendChild($dom->createTextNode($status));
|
||||
$xresponse->appendChild($xrequestStatus);
|
||||
|
||||
$xscheduleResponse->appendChild($xresponse);
|
||||
|
||||
}
|
||||
|
||||
return $dom->saveXML();
|
||||
|
||||
}
|
||||
|
||||
|
|
0
3rdparty/Sabre/CalDAV/Property/SupportedCalendarComponentSet.php
vendored
Normal file → Executable file
|
@ -14,7 +14,7 @@ class Sabre_CalDAV_Version {
|
|||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '1.6.2';
|
||||
const VERSION = '1.6.4';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
|
|
|
@ -108,7 +108,9 @@ class Sabre_CardDAV_AddressBook extends Sabre_DAV_Collection implements Sabre_Ca
|
|||
*/
|
||||
public function createFile($name,$vcardData = null) {
|
||||
|
||||
$vcardData = stream_get_contents($vcardData);
|
||||
if (is_resource($vcardData)) {
|
||||
$vcardData = stream_get_contents($vcardData);
|
||||
}
|
||||
// Converting to UTF-8, if needed
|
||||
$vcardData = Sabre_DAV_StringUtil::ensureUTF8($vcardData);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* @package Sabre
|
||||
* @subpackage CardDAV
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_CardDAV_AddressBookQueryParser {
|
||||
|
@ -88,12 +88,22 @@ class Sabre_CardDAV_AddressBookQueryParser {
|
|||
if (is_nan($limit)) $limit = null;
|
||||
|
||||
$filter = $this->xpath->query('/card:addressbook-query/card:filter');
|
||||
if ($filter->length !== 1) {
|
||||
|
||||
// According to the CardDAV spec there needs to be exactly 1 filter
|
||||
// element. However, KDE 4.8.2 contains a bug that will encode 0 filter
|
||||
// elements, so this is a workaround for that.
|
||||
//
|
||||
// See: https://bugs.kde.org/show_bug.cgi?id=300047
|
||||
if ($filter->length === 0) {
|
||||
$test = null;
|
||||
$filter = null;
|
||||
} elseif ($filter->length === 1) {
|
||||
$filter = $filter->item(0);
|
||||
$test = $this->xpath->evaluate('string(@test)', $filter);
|
||||
} else {
|
||||
throw new Sabre_DAV_Exception_BadRequest('Only one filter element is allowed');
|
||||
}
|
||||
|
||||
$filter = $filter->item(0);
|
||||
$test = $this->xpath->evaluate('string(@test)', $filter);
|
||||
if (!$test) $test = self::TEST_ANYOF;
|
||||
if ($test !== self::TEST_ANYOF && $test !== self::TEST_ALLOF) {
|
||||
throw new Sabre_DAV_Exception_BadRequest('The test attribute must either hold "anyof" or "allof"');
|
||||
|
|
|
@ -52,6 +52,8 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$server->subscribeEvent('report', array($this,'report'));
|
||||
$server->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel'));
|
||||
$server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
|
||||
$server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent'));
|
||||
$server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile'));
|
||||
|
||||
/* Namespaces */
|
||||
$server->xmlNamespaces[self::NS_CARDDAV] = 'card';
|
||||
|
@ -152,7 +154,7 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
$val = stream_get_contents($val);
|
||||
|
||||
// Taking out \r to not screw up the xml output
|
||||
$returnedProperties[200][$addressDataProp] = str_replace("\r","", $val);
|
||||
//$returnedProperties[200][$addressDataProp] = str_replace("\r","", $val);
|
||||
// The stripping of \r breaks the Mail App in OSX Mountain Lion
|
||||
// this is fixed in master, but not backported. /Tanghus
|
||||
$returnedProperties[200][$addressDataProp] = $val;
|
||||
|
@ -286,6 +288,81 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is triggered before a file gets updated with new content.
|
||||
*
|
||||
* This plugin uses this method to ensure that Card nodes receive valid
|
||||
* vcard data.
|
||||
*
|
||||
* @param string $path
|
||||
* @param Sabre_DAV_IFile $node
|
||||
* @param resource $data
|
||||
* @return void
|
||||
*/
|
||||
public function beforeWriteContent($path, Sabre_DAV_IFile $node, &$data) {
|
||||
|
||||
if (!$node instanceof Sabre_CardDAV_ICard)
|
||||
return;
|
||||
|
||||
$this->validateVCard($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is triggered before a new file is created.
|
||||
*
|
||||
* This plugin uses this method to ensure that Card nodes receive valid
|
||||
* vcard data.
|
||||
*
|
||||
* @param string $path
|
||||
* @param resource $data
|
||||
* @param Sabre_DAV_ICollection $parentNode
|
||||
* @return void
|
||||
*/
|
||||
public function beforeCreateFile($path, &$data, Sabre_DAV_ICollection $parentNode) {
|
||||
|
||||
if (!$parentNode instanceof Sabre_CardDAV_IAddressBook)
|
||||
return;
|
||||
|
||||
$this->validateVCard($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the submitted iCalendar data is in fact, valid.
|
||||
*
|
||||
* An exception is thrown if it's not.
|
||||
*
|
||||
* @param resource|string $data
|
||||
* @return void
|
||||
*/
|
||||
protected function validateVCard(&$data) {
|
||||
|
||||
// If it's a stream, we convert it to a string first.
|
||||
if (is_resource($data)) {
|
||||
$data = stream_get_contents($data);
|
||||
}
|
||||
|
||||
// Converting the data to unicode, if needed.
|
||||
$data = Sabre_DAV_StringUtil::ensureUTF8($data);
|
||||
|
||||
try {
|
||||
|
||||
$vobj = Sabre_VObject_Reader::read($data);
|
||||
|
||||
} catch (Sabre_VObject_ParseException $e) {
|
||||
|
||||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This resource only supports valid vcard data. Parse error: ' . $e->getMessage());
|
||||
|
||||
}
|
||||
|
||||
if ($vobj->name !== 'VCARD') {
|
||||
throw new Sabre_DAV_Exception_UnsupportedMediaType('This collection can only support vcard objects.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function handles the addressbook-query REPORT
|
||||
*
|
||||
|
@ -365,6 +442,8 @@ class Sabre_CardDAV_Plugin extends Sabre_DAV_ServerPlugin {
|
|||
|
||||
$vcard = Sabre_VObject_Reader::read($vcardData);
|
||||
|
||||
if (!$filters) return true;
|
||||
|
||||
foreach($filters as $filter) {
|
||||
|
||||
$isDefined = isset($vcard->{$filter['name']});
|
||||
|
|
|
@ -16,7 +16,7 @@ class Sabre_CardDAV_Version {
|
|||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '1.6.1';
|
||||
const VERSION = '1.6.3';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
|
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
@ -11,7 +11,7 @@
|
|||
* @package Sabre
|
||||
* @subpackage DAVClient
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class Sabre_DAV_Client {
|
||||
|
@ -23,6 +23,28 @@ class Sabre_DAV_Client {
|
|||
protected $password;
|
||||
protected $proxy;
|
||||
|
||||
/**
|
||||
* Basic authentication
|
||||
*/
|
||||
const AUTH_BASIC = 1;
|
||||
|
||||
/**
|
||||
* Digest authentication
|
||||
*/
|
||||
const AUTH_DIGEST = 2;
|
||||
|
||||
/**
|
||||
* The authentication type we're using.
|
||||
*
|
||||
* This is a bitmask of AUTH_BASIC and AUTH_DIGEST.
|
||||
*
|
||||
* If DIGEST is used, the client makes 1 extra request per request, to get
|
||||
* the authentication tokens.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $authType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -46,7 +68,7 @@ class Sabre_DAV_Client {
|
|||
'baseUri',
|
||||
'userName',
|
||||
'password',
|
||||
'proxy'
|
||||
'proxy',
|
||||
);
|
||||
|
||||
foreach($validSettings as $validSetting) {
|
||||
|
@ -55,6 +77,12 @@ class Sabre_DAV_Client {
|
|||
}
|
||||
}
|
||||
|
||||
if (isset($settings['authType'])) {
|
||||
$this->authType = $settings['authType'];
|
||||
} else {
|
||||
$this->authType = self::AUTH_BASIC | self::AUTH_DIGEST;
|
||||
}
|
||||
|
||||
$this->propertyMap['{DAV:}resourcetype'] = 'Sabre_DAV_Property_ResourceType';
|
||||
|
||||
}
|
||||
|
@ -252,9 +280,6 @@ class Sabre_DAV_Client {
|
|||
);
|
||||
|
||||
switch ($method) {
|
||||
case 'PUT':
|
||||
$curlSettings[CURLOPT_PUT] = true;
|
||||
break;
|
||||
case 'HEAD' :
|
||||
|
||||
// do not read body with HEAD requests (this is neccessary because cURL does not ignore the body with HEAD
|
||||
|
@ -285,8 +310,15 @@ class Sabre_DAV_Client {
|
|||
$curlSettings[CURLOPT_PROXY] = $this->proxy;
|
||||
}
|
||||
|
||||
if ($this->userName) {
|
||||
$curlSettings[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC | CURLAUTH_DIGEST;
|
||||
if ($this->userName && $this->authType) {
|
||||
$curlType = 0;
|
||||
if ($this->authType & self::AUTH_BASIC) {
|
||||
$curlType |= CURLAUTH_BASIC;
|
||||
}
|
||||
if ($this->authType & self::AUTH_DIGEST) {
|
||||
$curlType |= CURLAUTH_DIGEST;
|
||||
}
|
||||
$curlSettings[CURLOPT_HTTPAUTH] = $curlType;
|
||||
$curlSettings[CURLOPT_USERPWD] = $this->userName . ':' . $this->password;
|
||||
}
|
||||
|
||||
|
|