├── 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 |
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 {}
--------------------------------------------------------------------------------