/[drupal]/contributions/modules/stockapi/stockapi.inc
ViewVC logotype

Contents of /contributions/modules/stockapi/stockapi.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Mon Jul 21 05:25:56 2008 UTC (16 months ago) by mathias
Branch: MAIN
CVS Tags: HEAD
File MIME type: text/x-php
Big performance updates. Additionally, we can now store 40 additional fields for ticker symbols.
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * A wrapper API for the retreiving stock quotes from Yahoo! Finance.
7 */
8
9 /**
10 * Implement a HTTP request to Yahoo Finance to retrieve stock quotes.
11 *
12 * @param $symbols array
13 * An array of ticker symbols to send to Yahoo!. There is not limit on the
14 * number of symbols. Yahoo! limits 200 symbols per request, so we queue up
15 * the request into batches.
16 *
17 * @return
18 * An array of stocks with stock information fromm Yahoo!. False on failure.
19 */
20 function stockapi_fetch($symbols) {
21
22 // Step 1: Yahoo! limits stock updates to 200 or less per request. Split up larger arrays.
23 $l = 199;
24 if (count($symbols) <= $l) {
25 $s = array_map('urlencode', $symbols); $s = implode('+', $s);
26 $fields = stockapi_get_quotetype(variable_get('stockapi_quotetype', 'basic'));
27
28 $url = "http://download.finance.yahoo.com/d/quotes.csvr?s=$s&f=$fields&e=.csv";
29 $results = drupal_http_request($url);
30 if (_stockapi_request_failure($results)) return FALSE;
31
32 // Symbols are returned in CSV format.
33 return _stockapi_parse_csv($results->data);
34 }
35 else {
36 $batches = array_chunk($symbols, $l);
37 $stocks = array();
38 foreach ($batches as $key => $batch) {
39 $stocks = array_merge(stockapi_fetch($batch), $stocks);
40 }
41 return $stocks;
42 }
43 }
44
45 /**
46 * Save a single stock quote to the database.
47 *
48 * @param $stock object
49 * The stock object keys' must match the field names of the database table.
50 * The stock object values' are the data to insert.
51 *
52 * @return
53 * TRUE on success, FALSE on failure
54 */
55 function stockapi_save($stock) {
56 if (db_result(db_query("SELECT symbol FROM {stockapi} WHERE symbol = '%s'", $stock->symbol))) {
57 // Update
58 $fields = $values = array();
59 foreach ($stock as $field => $value) {
60 if ($field != 'symbol') { // It's redundant to update the stock symbol
61 $fields[] = $field .'='. _stockapi_sprintf($field);
62 $values[] = $value;
63 }
64 }
65 $values[] = $stock->symbol;
66 return db_query("UPDATE {stockapi} SET ". implode(',', $fields). " WHERE symbol = '%s'", $values);
67 }
68 else {
69 //Insert
70 $fields = $values = array();
71 foreach ($stock as $field => $value) {
72 $fields[] = $field;
73 $sprintf[] = _stockapi_sprintf($field);
74 $values[] = $value;
75 }
76 return db_query("INSERT INTO {stockapi} (". implode(', ', $fields) .") VALUES (". implode(', ', $sprintf) .")", $values);
77 }
78 }
79
80 /**
81 * Return ticker information for a single symbol from our database, not Yahoo!
82 *
83 * @param $symbol string
84 * The ticker symbol to retrieve information for.
85 * @param $q string
86 * The type of information to retrieve. Can be either: basic, extended,
87 * or realtime. The default is the site-wide setting, which is usually the
88 * best bet here.
89 * @return object
90 */
91 function stockapi_load($symbol, $q = NULL) {
92 static $stocks = array();
93
94 if (!isset($stocks[$symbol])) {
95 $fields = _stockapi_get_fields($q);
96 $stocks[$symbol] = db_fetch_object(db_query('SELECT '. implode(', ', $fields) ." FROM {stockapi} WHERE symbol = '%s'", $symbol));
97 }
98
99 return $stocks[$symbol];
100 }
101
102 /**
103 * Return ticker information for a batch of symbols from our database, not Yahoo!
104 *
105 * @param $symbol array
106 * An array of ticker symbols to retrieve information for.
107 * @param $q string
108 * The type of information to retrieve. Can be either: basic, extended,
109 * or realtime. The default is the site-wide setting, which is usually the
110 * best bet here.
111 * @return array
112 * An array of stocks, keyed by their ticker symbol. Each stock is an object within the array.
113 */
114 function stockapi_multiload($symbol, $q = NULL) {
115 $stocks = array();
116
117 $fields = _stockapi_get_fields($q);
118 $result = db_query('SELECT '. implode(', ', $fields) .' FROM {stockapi} WHERE symbol IN ('. implode(', ', array_map('_stockapi_quote_it', $symbol)) .')');
119 while ($stock = db_fetch_object($result)) {
120 $stocks[$stock->symbol] = $stock;
121 }
122
123 return $stocks;
124 }
125
126 /**
127 * Wrap a string in quotes. Usually used with array_map().
128 */
129 function _stockapi_quote_it($string, $style = 'single') {
130 return ($style != 'single') ? '"'. $string. '"' : "'". $string. "'";
131 }
132
133 /**
134 * Return the field parameter string to pull the correct columns from Yahoo!
135 */
136 function stockapi_get_quotetype($q = NULL) {
137 $quotetype['basic'] = 'snl1d1t1c1p2va2bapomwerr1dyj1x';
138 $quotetype['extended'] = $quotetype['basic']. 's7t8e7e8e9r6r7r5b4p6p5j4m3m4';
139 $quotetype['realtime'] = $quotetype['basic']. 'b2b3k2k1c6m2j3';
140
141 if ($quotetype[$q]) {
142 return $quotetype[$q];
143 }
144 // Always return the basic set as a fall through.
145 return $quotetype['basic'];
146 }
147
148 /**
149 * Return the sprintf syntax of a database field based on the stockapi schema.
150 */
151 function _stockapi_sprintf($dbname) {
152 static $sprintf = array();
153
154 if(!isset($sprintf[$dbname])) {
155 $schema = drupal_get_schema('stockapi');
156 foreach ($schema['fields'] as $name => $field) {
157 switch ($field['type']) {
158 case 'int': $sprintf[$name] = '%d'; break;
159 case 'float': $sprintf[$name] = '%f'; break;
160 default: $sprintf[$name] = '"%s"';
161 }
162 }
163 }
164
165 return $sprintf[$dbname];
166 }
167
168 /**
169 * Convert a stock from Yahoo! to its obect oriented counterpart.
170 *
171 * @return object
172 **/
173 function _stockapi_to_object($stock, $q = NULL) {
174 $fields = _stockapi_get_fields($q);
175
176 $ns = count($fields);
177 for ($i=0; $i<$ns ; $i++) {
178 $s->$fields[$i] = $stock[$i];
179 }
180 $s->updated = time();
181
182 return $s;
183 }
184
185 /**
186 * Given the current site-wide quotetype, generate the actual database fields
187 * names currently active. These field names usually double as the keys for the
188 * stock object.
189 */
190 function _stockapi_get_fields($q = NULL) {
191 if (!$q) $q = variable_get('stockapi_quotetype', 'basic');
192 preg_match_all('/[a-z][0-9]?/', stockapi_get_quotetype($q), $yfields);
193 $yfields = $yfields[0];
194
195 $schema = drupal_get_schema('stockapi');
196 $map = _stockapi_yahoo_map();
197
198 $ns = count($yfields);
199 $s = array();
200 for ($i=0; $i<$ns ; $i++) {
201 $dbname = $map[$yfields[$i]];
202 $s[] = $dbname;
203 }
204 $s[] = 'updated';
205
206 return $s;
207 }
208
209 /**
210 * Return an array of Yahoo! fields keys mapped to the database field names.
211 *
212 * Note: Check out stockapi.install. We added a special key to the database
213 * install schema to map the Yahoo! field name to our database field names. The
214 * new key is named 'yahoo'.
215 */
216 function _stockapi_yahoo_map() {
217 static $map = NULL;
218
219 if (!isset($map)) {
220 $schema = drupal_get_schema('stockapi');
221 foreach ($schema['fields'] as $name => $field) {
222 if (isset($field['yahoo'])) {
223 $y = $field['yahoo'];
224 $map[$y] = $name;
225 }
226 }
227 }
228 return $map;
229 }
230
231 /**
232 * Helper function to convert a feed from Yahoo! to an array.
233 */
234 function _stockapi_parse_csv($data) {
235 $stocks = array();
236 $lines = explode("\r\n", trim($data));
237 // Clean up the data.
238 foreach ($lines as $key => $symbol) {
239 $stock = explode(',', $symbol);
240 foreach ($stock as $key => $value) {
241 // Clean up and normalize the data
242 $value = trim($value, '"');
243 if ($value == '0.00') $value = 0;
244 elseif ($value == '0.00%') $value = 0;
245 $stock[$key] = $value;
246 }
247 $stocks[] = $stock;
248 }
249 return $stocks;
250 }
251
252 /**
253 * Internal helper function to deal cleanly with various HTTP response codes.
254 */
255 function _stockapi_request_failure($results) {
256 switch ($results->code) {
257 case '200': // Success!
258 case '304': // Not modified, nothing to do.
259 return FALSE;
260 default:
261 watchdog('stockapi', 'Failed to retrieve stock quotes with error: %error', array('%error' => $results->error));
262 return TRUE;
263 }
264 return FALSE;
265 }

  ViewVC Help
Powered by ViewVC 1.1.2