2010-02-16 7 views
9

Estoy en un servidor donde estoy limitado a PHP 5.2.6 lo que significa que str_getcsv no está disponible para mí. Estoy usando, en cambio, fgetcsv, que requiere "Un puntero de archivo válido para un archivo abierto con éxito por fopen(), popen() o fsockopen()". para operar¿Hay alguna manera de acceder a una cadena como manejador de archivos en php?

Mi pregunta es esta: ¿hay alguna manera de acceder a una cadena como manejador de archivo?

Mi otra opción es escribir la cadena en un archivo de texto y luego acceder a ella a través del fopen() y luego usar fgetcsv, pero espero que haya una manera de hacerlo directamente, como en perl.

Respuesta

20

Si se echa un vistazo en las notas de usuario en la página del manual para str_getcsv, encontrará this note from daniel, que propone esta función (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; 
    } 
} 
?> 

Parece estar haciendo exactamente lo que solicitó: utiliza una secuencia, que apunta a un identificador de archivo temporal en la memoria, para usar fgetcsv en él.


Ver PHP input/output streams para la documentación acerca de, entre otros, la envoltura php://temp corriente.


Por supuesto, usted debe comprobar que funciona bien para usted - pero, al menos, esto debe darle una idea de cómo lograr esto ;-)

+1

Ya lo hubiera votado dos veces si pudiera, siempre parece tener un lugar en las respuestas. Necesito leer las notas del usuario con más frecuencia. – Erik

+0

Gracias :-) ;;; Las notas de los usuarios muy a menudo traen alguna información interesante :-) * (Bueno, si uno de los usuarios tiene un problema, es probable que otra persona ya haya tenido el mismo problema antes ^^) * –

+0

Es interesante observar, después de leer un poco , puede usar 'php: // memory' - la única ventaja de' php: // temp' es que el archivo exceda el tamaño designado, se escribirá en el disco; si estás por debajo de ese tamaño de archivo, permanece completamente en la memoria. – Erik

-3

Desafortunadamente, eso no es posible. No puede tratar una cadena como si fuera una secuencia de un archivo. De hecho, primero debe escribir la cadena en un archivo y luego abrir dicho archivo usando fopen.

Y ahora, por la parte obvia, ¿ha considerado la actualización?

+0

Servidor del cliente, no es mi servidor. Entorno de alojamiento compartido, yadda yadda yadda ... Estoy ejecutando la última versión en MY box, ofc. – Erik

+1

¿Ni siquiera con transmisiones? http: //www.php.net/streams – Franz

+0

:) No sabía nada de eso, ¡gracias por el enlace! Supongo que aprendes algo nuevo todos los días. Obviamente, la actualización sería la mejor solución. – Aistina

0

Puede utilizar asas corriente como php://memory para lograr lo que buscas. Solo abre, escribe, rebobina y deberías poder usar fgetcsv.

6

Para responder a su pregunta general, sí puede tratar una variable como una secuencia de archivos.

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

La siguiente es una copia y pegar de algunos comentarios diferentes en el manual de PHP (por lo que no puedo responder por la forma en la producción de preparados es):

<?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); 
} 
?> 

Por supuesto, para su ejemplo particular, hay métodos de transmisión más simples que se pueden usar.

+0

Buena respuesta, y técnicamente la solución más limpia. ¡Escribir primero en un archivo simplemente parece incorrecto! –

+0

Lamentablemente tendrá que usar una variable global. ¿Por qué no usas el contexto para agregar la habilidad de usar cualquier variable no solo globales? – mAsT3RpEE

6

Estoy horrorizado de que nadie ha respondido a esta solución:

<?php 

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

echo stream_get_contents($fp); 

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

?> 

Y la memoria hambre solución perfecta:?

<?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, .......); 

>

Cuestiones relacionadas