2010-02-16 2 views
9

Sono su un server in cui sono limitato a PHP 5.2.6 che significa che str_getcsv non è disponibile per me. Sto usando, invece, fgetcsv che richiede "Un puntatore di file valido su un file aperto con successo da fopen(), popen() o fsockopen()." operare.C'è un modo per accedere a una stringa come filehandle in php?

La mia domanda è questa: c'è un modo per accedere a una stringa come un handle di file?

La mia altra opzione è scrivere la stringa in un file di testo e quindi accedervi tramite fopen() e quindi utilizzare fgetcsv, ma spero che ci sia un modo per farlo direttamente, come in perl.

risposta

20

Se si dà un'occhiata nelle note utente sulla pagina di manuale per str_getcsv, troverete this note from daniel, che propone questa funzione (citando):

<?php 
if (!function_exists('str_getcsv')) { 
    function str_getcsv($input, $delimiter = ",", $enclosure = '"', $escape = "\\") { 
     $fiveMBs = 5 * 1024 * 1024; 
     $fp = fopen("php://temp/maxmemory:$fiveMBs", 'r+'); 
     fputs($fp, $input); 
     rewind($fp); 

     $data = fgetcsv($fp, 1000, $delimiter, $enclosure); // $escape only got added in 5.3.0 

     fclose($fp); 
     return $data; 
    } 
} 
?> 

E sembra fare esattamente ciò che hai chiesto: utilizza uno stream, che punta a un filehandle temporaneo in memoria, per utilizzare fgetcsv su di esso.


Vedere PHP input/output streams per la documentazione relativa, tra gli altri, l'involucro php://temp flusso.


Naturalmente, è necessario verificare che funziona bene per voi - ma, almeno, questo dovrebbe darvi un'idea di come raggiungere questo ;-)

+1

Avrei votato per due volte se potessi - sembra che tu abbia sempre delle risposte chiare. Ho bisogno di leggere le note dell'utente più spesso. – Erik

+0

Grazie :-) ;;; Le note degli utenti portano abbastanza spesso alcune informazioni interessanti :-) * (Beh, se uno dei due ha un problema, è probabile che qualcun altro abbia già avuto lo stesso problema prima di ^^) * –

+0

È interessante notare, dopo aver fatto qualche lettura , puoi semplicemente usare 'php: // memory' - l'unico vantaggio di' php: // temp' è dopo che il file supera la dimensione designata, scriverà sul disco; se sei sotto la dimensione del file, rimane interamente in memoria. – Erik

-3

Sfortunatamente, questo non è possibile. Non è possibile trattare una stringa come se si trattasse di un flusso da un file. Dovresti in effetti scrivere prima la stringa su un file, quindi aprire il file usando fopen.

E ora, per la parte ovvia, avete considerato l'aggiornamento?

+0

del server del Cliente, non è il mio server. Ambiente di hosting condiviso, yadda yadda yadda ... Sto eseguendo l'ultima versione su MY box, ofc. – Erik

+1

Neanche con i flussi? http: //www.php.net/stream – Franz

+0

:) Non sapevo di quelli, grazie per il link! Suppongo che impari qualcosa di nuovo ogni giorno. Ovviamente, sebbene l'aggiornamento sarebbe ancora la soluzione migliore. – Aistina

0

È possibile utilizzare le maniglie di flusso come ad esempio php://memory per ottenere ciò che cerchi. Apri, fwrite, rewind e dovresti essere in grado di usare fgetcsv.

6

Per rispondere alla domanda generale, sì, è possibile trattare una variabile come flusso di file.

http://www.php.net/manual/en/function.stream-context-create.php

La seguente è una copia e incolla da un paio di osservazioni differenti sul manuale di PHP (quindi non posso garantire per quanto pronto per la produzione è):

<?php 
class VariableStream { 
    private $position; 
    private $varname; 
    public function stream_open($path, $mode, $options, &$opened_path) { 
     $url = parse_url($path); 
     $this->varname = $url["host"]; 
     $this->position = 0; 
     return true; 
    } 
    public function stream_read($count) { 
     $p=&$this->position; 
     $ret = substr($GLOBALS[$this->varname], $p, $count); 
     $p += strlen($ret); 
     return $ret; 
    } 
    public function stream_write($data){ 
     $v=&$GLOBALS[$this->varname]; 
     $l=strlen($data); 
     $p=&$this->position; 
     $v = substr($v, 0, $p) . $data . substr($v, $p += $l); 
     return $l; 
    } 
    public function stream_tell() { 
     return $this->position; 
    } 
    public function stream_eof() { 
     return $this->position >= strlen($GLOBALS[$this->varname]); 
    } 
    public function stream_seek($offset, $whence) { 
     $l=strlen(&$GLOBALS[$this->varname]); 
     $p=&$this->position; 
     switch ($whence) { 
      case SEEK_SET: $newPos = $offset; break; 
      case SEEK_CUR: $newPos = $p + $offset; break; 
      case SEEK_END: $newPos = $l + $offset; break; 
      default: return false; 
     } 
     $ret = ($newPos >=0 && $newPos <=$l); 
     if ($ret) $p=$newPos; 
     return $ret; 
    } 
} 

stream_wrapper_register("var", "VariableStream"); 
$csv = "foo,bar\ntest,1,2,3\n"; 

$row = 1; 
if (($handle = fopen("var://csv", "r")) !== FALSE) { 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 
     $num = count($data); 
     echo "<p> $num fields in line $row: <br /></p>\n"; 
     $row++; 
     for ($c=0; $c < $num; $c++) { 
      echo $data[$c] . "<br />\n"; 
     } 
    } 
    fclose($handle); 
} 
?> 

Naturalmente, per la vostra In particolare, esistono metodi di flusso più semplici che possono essere utilizzati.

+0

Bella risposta e tecnicamente la soluzione più pulita. Scrivere su un file prima sembra solo sbagliato! –

+0

Sfortunatamente dovrai usare una variabile globale. perché non usi il contesto per aggiungere la possibilità di usare qualsiasi variabile non solo globale. – mAsT3RpEE

6

Sono inorridito che nessuno ha risposto a questa soluzione:

<?php 

$string = "I tried, honestly!"; 
$fp  = fopen('data://text/plain,' . $string,'r'); 

echo stream_get_contents($fp); 

#fputcsv($fp, .......); 

?> 

E la memoria fame soluzione perfetta:?

<?php 

class StringStream 
{ 
    private $Variable = NULL; 
    protected $fp  = 0; 

    final public function __construct(&$String, $Mode = 'r') 
    { 
     $this->$Variable = &$String; 

     switch($Mode) 
     { 
      case 'r': 
      case 'r+': 
       $this->fp = fopen('php://memory','r+'); 
       fwrite($this->fp, @strval($String)); 
       rewind($this->fp); 
       break; 

      case 'a': 
      case 'a+': 
       $this->fp = fopen('php://memory','r+'); 
       fwrite($this->fp, @strval($String)); 
       break; 

      default: 
       $this->fp = fopen('php://memory',$Mode); 
     } 
    } 

    final public function flush() 
    { 
     # Update variable 
     $this->Variable = stream_get_contents($this->fp); 
    } 

    final public function __destruct() 
    { 
     # Update variable on destruction; 
     $this->Variable = stream_get_contents($this->fp); 
    } 

    public function __get($name) 
    { 
     switch($name) 
     { 
      case 'fp': return $fp; 
      default: trigger error('Undefined property: ('.$name.').'); 
     } 

     return NULL; 
    } 
} 

$string = 'Some bad-ass string'; 
$stream = new StringStream($string); 

echo stream_get_contents($stream->fp); 
#fputcsv($stream->fp, .......); 

>