2d2449deb6d32b38d0fd4bbed0a7f54f96bb62c1
[Packages/TYPO3.CMS.git] / typo3 / sysext / adodb / adodb / adodb-csvlib.inc.php
1 <?php
2
3 // security - hide paths
4 if (!defined('ADODB_DIR')) die();
5
6 global $ADODB_INCLUDED_CSV;
7 $ADODB_INCLUDED_CSV = 1;
8
9 /*
10
11 V5.14 8 Sept 2011 (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved.
12 Released under both BSD license and Lesser GPL library license.
13 Whenever there is any discrepancy between the two licenses,
14 the BSD license will take precedence. See License.txt.
15 Set tabs to 4 for best viewing.
16
17 Latest version is available at http://adodb.sourceforge.net
18
19 Library for CSV serialization. This is used by the csv/proxy driver and is the
20 CacheExecute() serialization format.
21
22 ==== NOTE ====
23 Format documented at http://php.weblogs.com/ADODB_CSV
24 ==============
25 */
26
27 /**
28 * convert a recordset into special format
29 *
30 * @param rs the recordset
31 *
32 * @return the CSV formated data
33 */
34 function _rs2serialize(&$rs,$conn=false,$sql='')
35 {
36 $max = ($rs) ? $rs->FieldCount() : 0;
37
38 if ($sql) $sql = urlencode($sql);
39 // metadata setup
40
41 if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
42 if (is_object($conn)) {
43 $sql .= ','.$conn->Affected_Rows();
44 $sql .= ','.$conn->Insert_ID();
45 } else
46 $sql .= ',,';
47
48 $text = "====-1,0,$sql\n";
49 return $text;
50 }
51 $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
52
53 ## changed format from ====0 to ====1
54 $line = "====1,$tt,$sql\n";
55
56 if ($rs->databaseType == 'array') {
57 $rows = $rs->_array;
58 } else {
59 $rows = array();
60 while (!$rs->EOF) {
61 $rows[] = $rs->fields;
62 $rs->MoveNext();
63 }
64 }
65
66 for($i=0; $i < $max; $i++) {
67 $o = $rs->FetchField($i);
68 $flds[] = $o;
69 }
70
71 $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
72 $class = $rs->connection->arrayClass;
73 $rs2 = new $class();
74 $rs2->timeCreated = $rs->timeCreated; # memcache fix
75 $rs2->sql = $rs->sql;
76 $rs2->oldProvider = $rs->dataProvider;
77 $rs2->InitArrayFields($rows,$flds);
78 $rs2->fetchMode = $savefetch;
79 return $line.serialize($rs2);
80 }
81
82
83 /**
84 * Open CSV file and convert it into Data.
85 *
86 * @param url file/ftp/http url
87 * @param err returns the error message
88 * @param timeout dispose if recordset has been alive for $timeout secs
89 *
90 * @return recordset, or false if error occured. If no
91 * error occurred in sql INSERT/UPDATE/DELETE,
92 * empty recordset is returned
93 */
94 function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
95 {
96 $false = false;
97 $err = false;
98 $fp = @fopen($url,'rb');
99 if (!$fp) {
100 $err = $url.' file/URL not found';
101 return $false;
102 }
103 @flock($fp, LOCK_SH);
104 $arr = array();
105 $ttl = 0;
106
107 if ($meta = fgetcsv($fp, 32000, ",")) {
108 // check if error message
109 if (strncmp($meta[0],'****',4) === 0) {
110 $err = trim(substr($meta[0],4,1024));
111 fclose($fp);
112 return $false;
113 }
114 // check for meta data
115 // $meta[0] is -1 means return an empty recordset
116 // $meta[1] contains a time
117
118 if (strncmp($meta[0], '====',4) === 0) {
119
120 if ($meta[0] == "====-1") {
121 if (sizeof($meta) < 5) {
122 $err = "Corrupt first line for format -1";
123 fclose($fp);
124 return $false;
125 }
126 fclose($fp);
127
128 if ($timeout > 0) {
129 $err = " Illegal Timeout $timeout ";
130 return $false;
131 }
132
133 $rs = new $rsclass($val=true);
134 $rs->fields = array();
135 $rs->timeCreated = $meta[1];
136 $rs->EOF = true;
137 $rs->_numOfFields = 0;
138 $rs->sql = urldecode($meta[2]);
139 $rs->affectedrows = (integer)$meta[3];
140 $rs->insertid = $meta[4];
141 return $rs;
142 }
143 # Under high volume loads, we want only 1 thread/process to _write_file
144 # so that we don't have 50 processes queueing to write the same data.
145 # We use probabilistic timeout, ahead of time.
146 #
147 # -4 sec before timeout, give processes 1/32 chance of timing out
148 # -2 sec before timeout, give processes 1/16 chance of timing out
149 # -1 sec after timeout give processes 1/4 chance of timing out
150 # +0 sec after timeout, give processes 100% chance of timing out
151 if (sizeof($meta) > 1) {
152 if($timeout >0){
153 $tdiff = (integer)( $meta[1]+$timeout - time());
154 if ($tdiff <= 2) {
155 switch($tdiff) {
156 case 4:
157 case 3:
158 if ((rand() & 31) == 0) {
159 fclose($fp);
160 $err = "Timeout 3";
161 return $false;
162 }
163 break;
164 case 2:
165 if ((rand() & 15) == 0) {
166 fclose($fp);
167 $err = "Timeout 2";
168 return $false;
169 }
170 break;
171 case 1:
172 if ((rand() & 3) == 0) {
173 fclose($fp);
174 $err = "Timeout 1";
175 return $false;
176 }
177 break;
178 default:
179 fclose($fp);
180 $err = "Timeout 0";
181 return $false;
182 } // switch
183
184 } // if check flush cache
185 }// (timeout>0)
186 $ttl = $meta[1];
187 }
188 //================================================
189 // new cache format - use serialize extensively...
190 if ($meta[0] === '====1') {
191 // slurp in the data
192 $MAXSIZE = 128000;
193
194 $text = fread($fp,$MAXSIZE);
195 if (strlen($text)) {
196 while ($txt = fread($fp,$MAXSIZE)) {
197 $text .= $txt;
198 }
199 }
200 fclose($fp);
201 $rs = unserialize($text);
202 if (is_object($rs)) $rs->timeCreated = $ttl;
203 else {
204 $err = "Unable to unserialize recordset";
205 //echo htmlspecialchars($text),' !--END--!<p>';
206 }
207 return $rs;
208 }
209
210 $meta = false;
211 $meta = fgetcsv($fp, 32000, ",");
212 if (!$meta) {
213 fclose($fp);
214 $err = "Unexpected EOF 1";
215 return $false;
216 }
217 }
218
219 // Get Column definitions
220 $flds = array();
221 foreach($meta as $o) {
222 $o2 = explode(':',$o);
223 if (sizeof($o2)!=3) {
224 $arr[] = $meta;
225 $flds = false;
226 break;
227 }
228 $fld = new ADOFieldObject();
229 $fld->name = urldecode($o2[0]);
230 $fld->type = $o2[1];
231 $fld->max_length = $o2[2];
232 $flds[] = $fld;
233 }
234 } else {
235 fclose($fp);
236 $err = "Recordset had unexpected EOF 2";
237 return $false;
238 }
239
240 // slurp in the data
241 $MAXSIZE = 128000;
242
243 $text = '';
244 while ($txt = fread($fp,$MAXSIZE)) {
245 $text .= $txt;
246 }
247
248 fclose($fp);
249 @$arr = unserialize($text);
250 //var_dump($arr);
251 if (!is_array($arr)) {
252 $err = "Recordset had unexpected EOF (in serialized recordset)";
253 if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
254 return $false;
255 }
256 $rs = new $rsclass();
257 $rs->timeCreated = $ttl;
258 $rs->InitArrayFields($arr,$flds);
259 return $rs;
260 }
261
262
263 /**
264 * Save a file $filename and its $contents (normally for caching) with file locking
265 * Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
266 */
267 function adodb_write_file($filename, $contents,$debug=false)
268 {
269 # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
270 # So to simulate locking, we assume that rename is an atomic operation.
271 # First we delete $filename, then we create a $tempfile write to it and
272 # rename to the desired $filename. If the rename works, then we successfully
273 # modified the file exclusively.
274 # What a stupid need - having to simulate locking.
275 # Risks:
276 # 1. $tempfile name is not unique -- very very low
277 # 2. unlink($filename) fails -- ok, rename will fail
278 # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
279 # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
280 if (strncmp(PHP_OS,'WIN',3) === 0) {
281 // skip the decimal place
282 $mtime = substr(str_replace(' ','_',microtime()),2);
283 // getmypid() actually returns 0 on Win98 - never mind!
284 $tmpname = $filename.uniqid($mtime).getmypid();
285 if (!($fd = @fopen($tmpname,'w'))) return false;
286 if (fwrite($fd,$contents)) $ok = true;
287 else $ok = false;
288 fclose($fd);
289
290 if ($ok) {
291 @chmod($tmpname,0644);
292 // the tricky moment
293 @unlink($filename);
294 if (!@rename($tmpname,$filename)) {
295 unlink($tmpname);
296 $ok = 0;
297 }
298 if (!$ok) {
299 if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
300 }
301 }
302 return $ok;
303 }
304 if (!($fd = @fopen($filename, 'a'))) return false;
305 if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
306 if (fwrite( $fd, $contents )) $ok = true;
307 else $ok = false;
308 fclose($fd);
309 @chmod($filename,0644);
310 }else {
311 fclose($fd);
312 if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
313 $ok = false;
314 }
315
316 return $ok;
317 }
318 ?>