├── src ├── config.php └── freshbooks.php ├── README └── index.php /src/config.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program. If not, see . 14 | */ 15 | 16 | /** 17 | * This is class written to work with Freshbooks OAuth methods. It 18 | * authorizes a user and will let you make requests to Freshbooks API 19 | * methods with OAuth headers. 20 | * 21 | * Last Edit: Oct. 1st, 2010 22 | * @author Mike Helmick (mikeh@ydekproductions.com) 23 | * @version 2.0 24 | * 25 | **/ 26 | 27 | For information on how to use this class, check out my blog post: 28 | http://blog.michaelhelmick.com/2010/07/30/freshbooks-api-using-oauth/ 29 | 30 | Also, if you're using Code Ignitor.. Spicer Matthews converted this lib to work easily in CI: 31 | http://github.com/cloudmanic/php-freshbooks-codeigniter -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | getAccessToken($_GET['oauth_token'], $_GET['oauth_verifier']); 15 | 16 | $_SESSION['oauth_token'] = $access_token['oauth_token']; 17 | $_SESSION['oauth_token_secret'] = $access_token['oauth_token_secret']; 18 | 19 | header("Location: index.php"); 20 | } 21 | else if(isset($_POST['subdomain'])) 22 | { 23 | $_SESSION['subdomain'] = $_POST['subdomain']; 24 | $c = new Freshbooks(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, OAUTH_CALLBACK, $_SESSION['subdomain']); 25 | 26 | echo 'Login with Freshbooks!'; 27 | } 28 | 29 | if(isset($_SESSION['oauth_token']) && isset($_SESSION['oauth_token_secret'])) 30 | { 31 | $request = '115'; 32 | try { 33 | $clients = $c->post($request); 34 | } 35 | catch(FreshbooksError $e) 36 | { 37 | $error = $e->getMessage(); 38 | } 39 | } 40 | 41 | 42 | ?> 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | Freshbooks 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 | http://.freshbooks.com 69 |
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/freshbooks.php: -------------------------------------------------------------------------------- 1 | . 15 | */ 16 | 17 | /** 18 | * This is class written to work with Freshbooks OAuth methods. It 19 | * authorizes a user and will let you make requests to Freshbooks API 20 | * methods with OAuth headers. 21 | * 22 | * Last Edit: Oct. 1st, 2010 23 | * @author Mike Helmick (mikeh@ydekproductions.com) 24 | * @version 2.0 25 | * 26 | **/ 27 | 28 | class Freshbooks 29 | { 30 | protected $oauth_consumer_key; 31 | protected $oauth_consumer_secret; 32 | protected $oauth_callback; 33 | protected $oauth_token; 34 | protected $oauth_token_secret; 35 | 36 | // $subdomain is the subdomain of the users Freshbooks account 37 | // (i.e. http://example.freshbooks.com; "example" being the subdomain). 38 | protected $subdomain; 39 | 40 | function __construct($oauth_consumer_key, $oauth_consumer_secret, $oauth_callback = NULL, $subdomain = NULL, $oauth_token = NULL, $oauth_token_secret = NULL) 41 | { 42 | $this->oauth_consumer_key = $oauth_consumer_key; 43 | $this->oauth_consumer_secret = $oauth_consumer_secret; 44 | 45 | // If a subdomain is not supplied, it will be set to the user who owns the application's subdomain, 46 | // This would be good if you are only authenticating yourself, and not other users. 47 | if($subdomain === NULL) 48 | $this->subdomain = $this->oauth_consumer_key; 49 | else 50 | $this->subdomain = $subdomain; 51 | 52 | if($oauth_callback) $this->oauth_callback = $oauth_callback; 53 | if($oauth_token) $this->oauth_token = $oauth_token; 54 | if($oauth_token_secret) $this->oauth_token_secret = $oauth_token_secret; 55 | } 56 | 57 | 58 | public function apiUrl() { return 'https://'.$this->subdomain.'.freshbooks.com/api/2.1/xml-in'; } 59 | public function accessTokenUrl() { return 'https://'.$this->subdomain.'.freshbooks.com/oauth/oauth_access.php'; } 60 | public function authorizeUrl() { return 'https://'.$this->subdomain.'.freshbooks.com/oauth/oauth_authorize.php'; } 61 | public function requestTokenUrl() { return 'https://'.$this->subdomain.'.freshbooks.com/oauth/oauth_request.php'; } 62 | 63 | 64 | public function createNonce($length) 65 | { 66 | $characters = '0123456789abcdefghijklmnopqrstuvwxyz'; 67 | $nonce = ''; 68 | for ($p = 0; $p < $length; $p++) { 69 | $nonce .= $characters[mt_rand(0, strlen($characters)-1)]; 70 | } 71 | return $nonce; 72 | } 73 | 74 | 75 | private function urlEncodeParams($params) 76 | { 77 | $postdata =''; 78 | foreach($params as $key => $value) 79 | { 80 | if(!empty($postdata)) $postdata .= '&'; 81 | $postdata .= $key.'='; 82 | $postdata .= urlencode($value); 83 | } 84 | return $postdata; 85 | } 86 | 87 | 88 | private function getRequestToken() 89 | { 90 | $params = array( 91 | 'oauth_consumer_key' => $this->oauth_consumer_key, 92 | 'oauth_callback' => $this->oauth_callback, 93 | 'oauth_signature' => $this->oauth_consumer_secret. '&', 94 | 'oauth_signature_method' => 'PLAINTEXT', 95 | 'oauth_version' => '1.0', 96 | 'oauth_timestamp' => time(), 97 | 'oauth_nonce' => $this->createNonce(20), 98 | ); 99 | 100 | return $this->OAuthRequest($this->requestTokenUrl(), $params); 101 | } 102 | 103 | 104 | public function getLoginUrl() 105 | { 106 | $token = $this->getRequestToken(); 107 | $loginUrl = $this->authorizeUrl().'?oauth_token='.$token['oauth_token']; 108 | return $loginUrl; 109 | } 110 | 111 | 112 | public function getAccessToken($token, $verifier) 113 | { 114 | $params = array( 115 | 'oauth_consumer_key' => $this->oauth_consumer_key, 116 | 'oauth_token' => $token, 117 | 'oauth_verifier' => $verifier, 118 | 'oauth_signature' => $this->oauth_consumer_secret. '&', 119 | 'oauth_signature_method' => 'PLAINTEXT', 120 | 'oauth_version' => '1.0', 121 | 'oauth_timestamp' => time(), 122 | 'oauth_nonce' => $this->createNonce(20), 123 | ); 124 | 125 | return $this->OAuthRequest($this->accessTokenUrl(), $params); 126 | } 127 | 128 | 129 | private function OAuthRequest($url, $params = array()) 130 | { 131 | // URL encode our params 132 | $params = $this->urlEncodeParams($params); 133 | 134 | // send the request to FreshBooks 135 | $ch = curl_init(); 136 | curl_setopt($ch, CURLOPT_URL, $url); 137 | curl_setopt($ch, CURLOPT_POST, 1); 138 | curl_setopt($ch, CURLOPT_POSTFIELDS, $params); 139 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 140 | $res= curl_exec($ch); 141 | 142 | // parse the request 143 | $r = array(); 144 | parse_str($res, $r); 145 | 146 | return $r; 147 | } 148 | 149 | 150 | private function buildAuthHeader() 151 | { 152 | $params = array( 153 | 'oauth_version' => '1.0', 154 | 'oauth_consumer_key' => $this->oauth_consumer_key, 155 | 'oauth_token' => $this->oauth_token, 156 | 'oauth_timestamp' => time(), 157 | 'oauth_nonce' => $this->createNonce(20), 158 | 'oauth_signature_method' => 'PLAINTEXT', 159 | 'oauth_signature' => $this->oauth_consumer_secret. '&' .$this->oauth_token_secret 160 | ); 161 | 162 | $auth = 'OAuth realm=""'; 163 | foreach($params as $kk => $vv) 164 | { 165 | $auth .= ','.$kk . '="' . urlencode($vv) . '"'; 166 | } 167 | 168 | return $auth; 169 | } 170 | 171 | 172 | public function post($request) 173 | { 174 | $headers = array( 175 | 'Authorization: '.$this->buildAuthHeader().'', 176 | 'Content-Type: application/xml; charset=UTF-8', 177 | 'Accept: application/xml; charset=UTF-8', 178 | 'User-Agent: My-Freshbooks-App-1.0'); 179 | 180 | $ch = curl_init(); 181 | curl_setopt($ch, CURLOPT_URL, $this->apiUrl()); 182 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 183 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 184 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); 185 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 186 | curl_setopt($ch, CURLOPT_POST, 1); 187 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 188 | 189 | $response = curl_exec($ch); 190 | curl_close($ch); 191 | $response = new SimpleXMLElement($response); 192 | 193 | if($response->attributes()->status == 'ok') 194 | return $response; 195 | elseif($response->attributes()->status == 'fail' || $response->error) 196 | throw new FreshbooksAPIError($response->error); 197 | else 198 | throw new FreshbooksError('Oops, something went wrong. :('); 199 | } 200 | 201 | } 202 | 203 | class FreshbooksError extends Exception {} 204 | class FreshbooksAPIError extends FreshbooksError {} --------------------------------------------------------------------------------