Initial, very basic, code for Service_Twitter
authorMichael J. Rubinsky <mrubinsk@horde.org>
Sat, 18 Jul 2009 22:49:25 +0000 (18:49 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Sat, 18 Jul 2009 22:50:51 +0000 (18:50 -0400)
The only functional part at this point it the OAuth authentication
and setting status. See the example file in doc/

framework/Service_Twitter/doc/twitter.php.example [new file with mode: 0644]
framework/Service_Twitter/lib/Horde/Service/Twitter.php [new file with mode: 0644]
framework/Service_Twitter/lib/Horde/Service/Twitter/Account.php [new file with mode: 0644]
framework/Service_Twitter/lib/Horde/Service/Twitter/Auth.php [new file with mode: 0644]
framework/Service_Twitter/lib/Horde/Service/Twitter/Exception.php [new file with mode: 0644]
framework/Service_Twitter/lib/Horde/Service/Twitter/Statuses.php [new file with mode: 0644]
framework/Service_Twitter/lib/Horde/Service/Twitter/Timeline.php [new file with mode: 0644]
framework/Service_Twitter/package.xml [new file with mode: 0644]

diff --git a/framework/Service_Twitter/doc/twitter.php.example b/framework/Service_Twitter/doc/twitter.php.example
new file mode 100644 (file)
index 0000000..4fa2d7f
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Callback page for Twitter integration.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ */
+
+require_once dirname(__FILE__) . '/../lib/base.php';
+
+if (!Horde_Auth::getAuth()) {
+    Horde::authenticationFailureRedirect();
+}
+
+/* Keys - these are obtained when registering for the service */
+$consumer_key = '********';
+$consumer_secret = '*********';
+
+/* Used to obtain an unprivileged request token */
+$token_url = 'http://twitter.com/oauth/request_token';
+
+/* Used for allowing the user to allow/deny access to the application */
+// (User is redirected to this URL if needed).
+$auth_url = 'http://twitter.com/oauth/authorize';
+
+// Used to obtain an access token after user authorizes the application
+$accessToken_url = 'http://twitter.com/oauth/access_token';
+
+/* Parameters required for the Horde_Oauth_Consumer */
+$params = array('key' => $consumer_key,
+                'secret' => $consumer_secret,
+                'requestTokenUrl' => $token_url,
+                'authorizeTokenUrl' => $auth_url,
+                'accessTokenUrl' => $accessToken_url,
+                'signatureMethod' => new Horde_Oauth_SignatureMethod_HmacSha1());
+
+/* Create the Consumer */
+$oauth = new Horde_Oauth_Consumer($params);
+
+/* Create the Twitter client */
+$twitter = new Horde_Service_Twitter(array('oauth' => $oauth,
+                                           'request' => new Horde_Controller_Request_Http()));
+/* At this point we would check for an existing, valid authorization token */
+// $auth_token should be a Horde_Oauth_Token object
+// $auth_token = getTokenFromStorage();
+
+// Do we have a good auth token? Keep in mind this is example code, and in a true
+// callback page we probably wouldn't be doing anything if we already have a token,
+// but for testing purposes....
+if (!empty($auth_token)) {
+    /* Have a token, tell the Twitter client about it */
+    $twitter->auth->setToken($auth_token);
+
+    // Do something cool....
+    // $twitter->statuses->update('Testing Horde/Twitter integration');
+
+} elseif (!empty($_SESSION['twitter_request_secret'])) {
+    /* No existing auth token, maybe we are in the process of getting it? */
+    $a_token = $twitter->auth->getAccessToken(new Horde_Controller_Request_Http(),
+                                              $_SESSION['twitter_request_secret']);
+
+    // Clear the request secret from the session now that we're done with it,
+    // again, using _SESSION for simplicity for this example
+    $_SESSION['twitter_request_secret'] = '';
+
+    if ($a_token === false || empty($a_token)) {
+        // We had a request secret, but something went wrong. maybe navigated
+        // back here between requests?
+        echo 'error';
+        die;
+    } else {
+        // We have a good token, save it to DB etc....
+        var_dump($a_token);
+        die;
+    }
+}
+
+// No auth token, not in the process of getting one...ask user to verify
+$results = $twitter->auth->getRequestToken();
+$_SESSION['twitter_request_secret'] = $results->secret;
+
+// Redirect to auth url
+header('Location:' . Horde::externalUrl($twitter->auth->getUserAuthorizationUrl($results), false));
diff --git a/framework/Service_Twitter/lib/Horde/Service/Twitter.php b/framework/Service_Twitter/lib/Horde/Service/Twitter.php
new file mode 100644 (file)
index 0000000..0a86214
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Horde_Service_Twitter class abstracts communication with Twitter's
+ * rest interface.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org)
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Service_Twitter
+ */
+class Horde_Service_Twitter
+{
+
+    /**
+     * Cache for the various objects we lazy load in __get()
+     *
+     * @var hash of Horde_Service_Twitter_* objects
+     */
+    protected $_objCache = array();
+
+    protected $_config;
+
+    /**
+     * Const'r
+     *
+     * @param array $config  Configuration parameters:
+     *   <pre>
+     *     'oauth'  - Horde_Oauth object
+     */
+    public function __construct($config)
+    {
+        // TODO: Check for req'd config
+        $this->_config = $config;
+
+    }
+
+    /**
+     * Lazy load the twitter classes.
+     *
+     * @param string $value  The lowercase representation of the subclass.
+     *
+     * @throws Horde_Service_Twitter_Exception
+     * @return Horde_Service_Twitter_* object.
+     */
+    public function __get($value)
+    {
+        // First, see if it's an allowed protected value.
+        switch ($value) {
+        case 'oauth':
+            return $this->_config['oauth'];
+
+        }
+
+        // If not, assume it's a method/action class...
+        $class = 'Horde_Service_Twitter_' . ucfirst($value);
+        if (!empty($this->_objCache[$class])) {
+            return $this->_objCache[$class];
+        }
+
+        if (!class_exists($class)) {
+            throw new Horde_Service_Twitter_Exception(sprintf("%s class not found", $class));
+        }
+
+
+        $this->_objCache[$class] = new $class($this, $this->oauth);
+        return $this->_objCache[$class];
+    }
+
+    /**
+     * Send a request to the Twitter api
+     *
+     * @param $url
+     * @param $params
+     * @return unknown_type
+     */
+    public function getRequest($url, $params = array())
+    {
+        $request = new Horde_Oauth_Request($url, $params);
+        $request->sign($this->oauth->signatureMethod, $this->oauth, $this->auth->getAccessToken());
+
+        $client = new Horde_Http_Client();
+        $response = $client->get($url, array('Authorization' => $request->buildAuthorizationHeader()));
+
+        return $response->getBody();
+    }
+
+    public function postRequest($url, $params = array())
+    {
+        $request = new Horde_Oauth_Request($url, $params);
+        $request->sign($this->oauth->signatureMethod, $this->oauth, $this->auth->getAccessToken());
+
+        $client = new Horde_Http_Client();
+        $response = $client->post($url, $params, array('Authorization' => $request->buildAuthorizationHeader()));
+
+        return $response->getBody();
+    }
+
+}
diff --git a/framework/Service_Twitter/lib/Horde/Service/Twitter/Account.php b/framework/Service_Twitter/lib/Horde/Service/Twitter/Account.php
new file mode 100644 (file)
index 0000000..b3d9bbc
--- /dev/null
@@ -0,0 +1 @@
+<?php
diff --git a/framework/Service_Twitter/lib/Horde/Service/Twitter/Auth.php b/framework/Service_Twitter/lib/Horde/Service/Twitter/Auth.php
new file mode 100644 (file)
index 0000000..bcf2f86
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Horde_Service_Twitter_Auth class to abstract all auth related tasks
+ *
+ * Basically implements Horde_Oauth_Client and passes the calls along to the
+ * protected oauth object.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org)
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Service_Twitter
+ */
+class Horde_Service_Twitter_Auth {
+
+    /**
+     *
+     * @var Horde_Service_Twitter
+     */
+    protected $_twitter;
+
+    /**
+     *
+     */
+    protected $_token;
+
+    /**
+     * Const'r
+     *
+     * @return Horde_Service_Twitter_Auth
+     */
+    public function __construct($twitter, $oauth)
+    {
+        $this->_twitter = $twitter;
+    }
+
+    /**
+     * Obtain the URL used to get an authorization token.
+     *
+     * @param Horde_Oauth_Token $requestToken The request token
+     *
+     * @return string  The Url
+     */
+    public function getUserAuthorizationUrl($requestToken)
+    {
+        return $this->_twitter->oauth->getUserAuthorizationUrl($requestToken);
+    }
+
+    /**
+     * Set the access token
+     *
+     * @param $token
+     * @return unknown_type
+     */
+    public function setToken($token)
+    {
+        // @TODO: sanity check this
+        $this->_token = $token;
+    }
+
+    /**
+     * Obtain the access token. This is the token that should be persisted to
+     * storage.
+     *
+     * @param Horde_Controller_Request_Http     Http request object
+     * @param Horde_Oauth_Token $requestSecret  The token secret returned by
+     *                                          Twitter after the user authorizes
+     *                                          the application.
+     * @return Horde_Oauth_Token
+     */
+    public function getAccessToken($request = null, $requestSecret = null)
+    {
+        if (!empty($this->_token)) {
+            return $this->_token;
+        }
+
+        //@TODO: Verify the existence of requestSecret...
+
+        $params = $request->getGetParams();
+        if (empty($params['oauth_token'])) {
+            return false;
+        }
+        $token = new Horde_Oauth_Token($params['oauth_token'], $requestSecret);
+
+        return $this->_twitter->oauth->getAccessToken($token);
+    }
+
+    public function getRequestToken($params = array())
+    {
+        return $this->_twitter->oauth->getRequestToken($params);
+    }
+
+}
diff --git a/framework/Service_Twitter/lib/Horde/Service/Twitter/Exception.php b/framework/Service_Twitter/lib/Horde/Service/Twitter/Exception.php
new file mode 100644 (file)
index 0000000..e9c2bd2
--- /dev/null
@@ -0,0 +1,4 @@
+<?php
+class Horde_Service_Twitter_Exception extends Exception {
+}
+?>
diff --git a/framework/Service_Twitter/lib/Horde/Service/Twitter/Statuses.php b/framework/Service_Twitter/lib/Horde/Service/Twitter/Statuses.php
new file mode 100644 (file)
index 0000000..234b45a
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Horde_Service_Twitter_Statuses class for updating user statuses.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org)
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Service_Twitter
+ */
+class Horde_Service_Twitter_Statuses
+{
+
+    public function __construct($twitter, $oauth)
+    {
+        $this->_twitter = $twitter;
+    }
+
+    /**
+     * Obtain the requested status
+     *
+     * @return unknown_type
+     */
+    public function show($id)
+    {
+
+    }
+
+    public function update($status)
+    {
+        $url = 'http://twitter.com/statuses/update.json';
+        return $this->_twitter->postRequest($url, array('status' => $status));
+    }
+}
diff --git a/framework/Service_Twitter/lib/Horde/Service/Twitter/Timeline.php b/framework/Service_Twitter/lib/Horde/Service/Twitter/Timeline.php
new file mode 100644 (file)
index 0000000..b3d9bbc
--- /dev/null
@@ -0,0 +1 @@
+<?php
diff --git a/framework/Service_Twitter/package.xml b/framework/Service_Twitter/package.xml
new file mode 100644 (file)
index 0000000..aff37cc
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Service_Twitter</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Twitter client</summary>
+ <description>This package provides client libraries for the Twitter REST API
+ </description>
+ <lead>
+  <name>Michael J. Rubinsky</name>
+  <user>mrubinsk</user>
+  <email>mrubinsk@horde.org</email>
+  <active>yes</active>
+ </lead>
+ <date>2009-07-18</date>
+ <version>
+  <release>0.1.0</release>
+  <api>0.1.0</api>
+ </version>
+ <stability>
+  <release>alpha</release>
+  <api>alpha</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
+ <notes>
+* Initial release
+ </notes>
+ <contents>
+  <dir name="/">
+   <dir name="lib">
+    <dir name="Horde">
+     <dir name="Service">
+      <dir name="Twitter">
+       <file name="Auth.php" role="php" />
+       <file name="Exception.php" role="php" />
+       <file name="Statuses.php" role="php" />
+      </dir> <!-- /lib/Horde/Service/Twitter-->
+      <file name="Twitter.php" role="php" />
+     </dir> <!-- /lib/Horde/Service -->
+    </dir> <!-- /lib/Horde -->
+   </dir> <!-- /lib -->
+  </dir> <!-- / -->
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.2.0</min>
+   </php>
+   <pearinstaller>
+    <min>1.5.0</min>
+   </pearinstaller>
+   <package>
+    <name>Http_Client</name>
+    <channel>pear.horde.org</channel>
+   </package>
+  </required>
+ </dependencies>
+ <phprelease>
+  <filelist>
+   <install name="lib/Horde/Service/Twitter/Auth.php" as="Horde/Service/Twitter/Auth.php" />
+   <install name="lib/Horde/Service/Twitter/Exception.php" as="Horde/Service/Twitter/Exception.php" />
+   <install name="lib/Horde/Service/Twitter/Statuses.php" as="Horde/Service/Twitter/Statuses.php" />
+   <install name="lib/Horde/Service/Twitter.php" as="Horde/Service/Twitter.php" />
+  </filelist>
+ </phprelease>
+</package>