source: moodle/trunk/fuentes/lib/adodb/adodb-csvlib.inc.php @ 136

Last change on this file since 136 was 136, checked in by mabarracus, 3 years ago

Ported code to xenial

File size: 8.2 KB
Line 
1<?php
2
3// security - hide paths
4if (!defined('ADODB_DIR')) die();
5
6global $ADODB_INCLUDED_CSV;
7$ADODB_INCLUDED_CSV = 1;
8
9/*
10
11  V5.19  23-Apr-2014  (c) 2000-2014 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        }
Note: See TracBrowser for help on using the repository browser.