PHP Conference China 2020

fopen

(PHP 4, PHP 5, PHP 7)

fopenAbre un fichero o un URL

Descripción

fopen ( string $filename , string $mode [, bool $use_include_path = FALSE [, resource $context ]] ) : resource

fopen() asocia un recurso con nombre, especificado por filename, a un flujo.

Parámetros

filename

Si filename está en la forma "esquema://...", se asume que será un URL y PHP buscará un gestor de protocolos (también conocido como envoltura) para ese protocolo. Si no está registrada ninguna envoltura para ese protocolo, PHP emitirá un aviso para ayudar a rastrear problemas potenciales en el script y continuará como si filename especificara un fichero normal.

Si PHP ha decidido que filename especifica un fichero local, intentará abrir un flujo para ese fichero. El fichero debe ser accesible para PHP, por lo que es necesario asegurarse de que los permisos de acceso del fichero permiten este acceso. Si está habilitado el modo seguro o open_basedir se pueden aplicar más restricciones.

Si PHP ha decidido que filename especifica un protocolo registrado, y ese protocolo está registrado como un URL de red, PHP se asegurará de que allow_url_fopen está habilitado. Si es desactivado, PHP emitirá un aviso y la llamada a fopen fallará.

Nota:

La lista de protocolos soportados se puede encontrar en Protocolos y Envolturas soportados. Algunos protocolos (también descritos como envolturas) soportan contexto y/u opciones de php.ini. Consulte la página específica del protocolo en uso para una lista de opciones que se pueden establecer. (p.ej. el valor user_agent en php.ini usado por la envoltura http).

En la plataforma Windows, asegúrese de escapar cualquier barra invertida usada en la ruta de fichero, o use barras hacia delante.

<?php
$gestor 
fopen("c:\\folder\\resource.txt""r");
?>

mode

El parámetro mode especifica el tipo de acceso que se necesita para el flujo. Puede ser cualquiera de los siguientes:

Una lista de los modos posibles de fopen() usando mode
mode Descripción
'r' Apertura para sólo lectura; coloca el puntero al fichero al principio del fichero.
'r+' Apertura para lectura y escritura; coloca el puntero al fichero al principio del fichero.
'w' Apertura para sólo escritura; coloca el puntero al fichero al principio del fichero y trunca el fichero a longitud cero. Si el fichero no existe se intenta crear.
'w+' Apertura para lectura y escritura; coloca el puntero al fichero al principio del fichero y trunca el fichero a longitud cero. Si el fichero no existe se intenta crear.
'a' Apertura para sólo escritura; coloca el puntero del fichero al final del mismo. Si el fichero no existe, se intenta crear. En este modo, fseek() solamente afecta a la posición de lectura; las lecturas siempre son pospuestas.
'a+' Apertura para lectura y escritura; coloca el puntero del fichero al final del mismo. Si el fichero no existe, se intenta crear. En este modo, fseek() no tiene efecto, las escrituras siempre son pospuestas.
'x' Creación y apertura para sólo escritura; coloca el puntero del fichero al principio del mismo. Si el fichero ya existe, la llamada a fopen() fallará devolviendo FALSE y generando un error de nivel E_WARNING. Si el fichero no existe se intenta crear. Esto es equivalente a especificar las banderas O_EXCL|O_CREAT para la llamada al sistema de open(2) subyacente.
'x+' Creación y apertura para lectura y escritura; de otro modo tiene el mismo comportamiento que 'x'.
'c' Abrir el fichero para sólo escritura. Si el fichero no existe, se crea. Si existe no es truncado (a diferencia de 'w'), ni la llamada a esta función falla (como en el caso con 'x'). El puntero al fichero se posiciona en el principio del fichero. Esto puede ser útil si se desea obtener un bloqueo asistido (véase flock()) antes de intentar modificar el fichero, ya que al usar 'w' se podría truncar el fichero antes de haber obtenido el bloqueo (si se desea truncar el fichero, se puede usar ftruncate() después de solicitar el bloqueo).
'c+' Abrir el fichero para lectura y escritura; de otro modo tiene el mismo comportamiento que 'c'.
'e' Establecer la bandera 'close-on-exec' en el descriptor de fichero abierto. Disponible solamente en PHP compilado en sistemas que se ajustan a POSIX.1-2008.

Nota:

Diferentes familias de sistemas operativos tienen diferentes convenciones para el final de línea. Cuando escribe un fichero de texto y quiere insertar un salto de línea, necesita usar el carácter o caracteres correctos de final de línea para su sistema operativo. Los sistemas basados en Unix usan \n como el carácter de final de línea, los sistemas basados en Windows usan \r\n como caracteres de final de línea y los sistemas basados en Macintosh usan \r como carácter de final de línea.

Si usa los caracteres de final de línea erróneos cuando escribe sus ficheros, se podrá encontrar con que otras aplicaciones que abran esos ficheros "parecerán raras".

Windows ofrece una bandera de traducción en modo texto ('t') que traducirá de manera transparente \n a \r\n cuando se trabaja con el fichero. En contraste, puede usar 'b' para forzar el modo binario, lo cual no traducirá su información. Para usar estas banderas, especifique 'b' o 't' como el último carácter del parámetro mode.

El modo de traducción predeterminado depende de la SAPI y de la versión de PHP que esté usando, por lo que se le anima a especificar siempre la bandera apropiada por razones de portabilidad. Debería usar el modo 't' si está trabajando con ficheros de texto plano y usa \n para delimitar los finales de línea es su script, pero confíe que sus ficheros serán legibles por aplicaciones tales como notepad. Debería usar 'b' en los demás casos.

Si no especifica la bandera 'b' cuando está trabajando con ficheros binarios, puede experimentar problemas extraños con su información, incluidos ficheros imagen rotos o problemas extraños con los caracteres \r\n.

Nota:

Por portabilidad, se recomienda encarecidamente que siempre use la bandera 'b' cuando se abran ficheros con fopen().

Nota:

De nuevo, por portabilidad, también se recomienda encarecidamente que reescriba el código que usa o depende del modo 't' por lo que use los finales de línea correctos y el modo 'b' en su lugar.

use_include_path

El tercer parámetro opcional use_include_path puede ser establecido a '1' o TRUE si se desea buscar un fichero en include_path también.

context

Nota: Soporte para context fue añadido en PHP 5.0.0. Para una descripción de contexts, refiérase a Flujos.

Valores devueltos

Devuelve un recurso de puntero a fichero si tiene éxito, o FALSE si se produjo un error.

Errores/Excepciones

Si la apertura falla, se generea un error de nivel E_WARNING. Se puede usar @ para suprimir esta advertencia.

Historial de cambios

Versión Descripción
7.0.16, 7.1.2 Se añadió la opción 'e'.
5.2.6 Se añadieron las opciones 'c' y 'c+'

Ejemplos

Ejemplo #1 Ejemplos de fopen()

<?php
$gestor 
fopen("/home/rasmus/fichero.txt""r");
$gestor fopen("/home/rasmus/fichero.gif""wb");
$gestor fopen("http://www.example.com/""r");
$gestor fopen("ftp://user:password@example.com/fichero.txt""w");
?>

Notas

Advertencia

Cuando se usa SSL, Microsoft IIS violará el protocolo, cerrando la conexión sin mandar un indicador close_notify. PHP avisará de esto con este mensaje "SSL: Fatal Protocol Error", cuando llegue al final de los datos. Una solución a este problema es bajar el nivel de aviso de errores del sistema para que no incluya advertencias. PHP pueden detectar servidores IIS con este problema cuando se abre un flujo usando https:// y suprime la advertencia. Si usáis la función fsockopen() para crear un socket ssl://, tendréis que suprimir la advertencia explicitamente.

Nota: Cuando el modo seguro está habilitado, PHP comprueba si el directorio en el cual el script está operando tiene el mismo UID (propietario) que el script que está siendo ejecutado.

Nota:

Si está experimentando problemas al leer y escribir ficheros y está usando la versión de módulo de servidor de PHP, asegúrese de que los ficheros y directorios que está usando sean accesibles por el proceso del servidor.

Nota:

Esta función también podría tener éxito cuando filename es un directorio. Si no se está seguro de que filename sea un fichero o un directorio, podría ser necesario utilzar la función is_dir() antes de llamar a fopen().

Ver también

add a note add a note

User Contributed Notes 19 notes

up
96
chapman at worldtakeoverindustries dot com
8 years ago
Note - using fopen in 'w' mode will NOT update the modification time (filemtime) of a file like you may expect. You may want to issue a touch() after writing and closing the file which update its modification time. This may become critical in a caching situation, if you intend to keep your hair.
up
17
php at delhelsa dot com
12 years ago
With php 5.2.5 on Apache 2.2.4, accessing files on an ftp server with fopen() or readfile() requires an extra forwardslash if an absolute path is needed.

i.e., if a file called bullbes.txt is stored under /var/school/ on ftp server example.com and you're trying to access it with user blossom and password buttercup, the url would be:

ftp://blossom:buttercup@example.com//var/school/bubbles.txt

Note the two forwardslashes. It looks like the second one is needed so the server won't interpret the path as relative to blossom's home on townsville.
up
3
petepostma-deletethis at gmail dot com
3 years ago
The verbal descriptions take a while to read through to get a feel for the expected results for fopen modes. This csv table can help break it down for quicker understanding to find which mode you are looking for:

Mode,Creates,Reads,Writes,Pointer Starts,Truncates File,Notes,Purpose
r,,y,,beginning,,fails if file doesn't exist,basic read existing file
r+,,y,y,beginning,,fails if file doesn't exist,basic r/w existing file
w,y,,y,beginning+end,y,,"create, erase, write file"
w+,y,y,y,beginning+end,y,,"create, erase, write file with read option"
a,y,,y,end,,,"write from end of file, create if needed"
a+,y,y,y,end,,,"write from end of file, create if needed, with read options"
x,y,,y,beginning,,fails if file exists,"like w, but prevents over-writing an existing file"
x+,y,y,y,beginning,,fails if file exists,"like w+, but prevents over writing an existing file"
c,y,,y,beginning,,,open/create a file for writing without deleting current content
c+,y,y,y,beginning,,,"open/create a file that is read, and then written back down"
up
10
info at b1g dot de
14 years ago
Simple class to fetch a HTTP URL. Supports "Location:"-redirections. Useful for servers with allow_url_fopen=false. Works with SSL-secured hosts.

<?php
#usage:
$r = new HTTPRequest('http://www.example.com');
echo
$r->DownloadToString();

class
HTTPRequest
{
    var
$_fp;        // HTTP socket
   
var $_url;        // full URL
   
var $_host;        // HTTP host
   
var $_protocol;    // protocol (HTTP/HTTPS)
   
var $_uri;        // request URI
   
var $_port;        // port
   
    // scan url
   
function _scan_url()
    {
       
$req = $this->_url;
       
       
$pos = strpos($req, '://');
       
$this->_protocol = strtolower(substr($req, 0, $pos));
       
       
$req = substr($req, $pos+3);
       
$pos = strpos($req, '/');
        if(
$pos === false)
           
$pos = strlen($req);
       
$host = substr($req, 0, $pos);
       
        if(
strpos($host, ':') !== false)
        {
            list(
$this->_host, $this->_port) = explode(':', $host);
        }
        else
        {
           
$this->_host = $host;
           
$this->_port = ($this->_protocol == 'https') ? 443 : 80;
        }
       
       
$this->_uri = substr($req, $pos);
        if(
$this->_uri == '')
           
$this->_uri = '/';
    }
   
   
// constructor
   
function HTTPRequest($url)
    {
       
$this->_url = $url;
       
$this->_scan_url();
    }
   
   
// download URL to string
   
function DownloadToString()
    {
       
$crlf = "\r\n";
       
       
// generate request
       
$req = 'GET ' . $this->_uri . ' HTTP/1.0' . $crlf
           
.    'Host: ' . $this->_host . $crlf
           
.    $crlf;
       
       
// fetch
       
$this->_fp = fsockopen(($this->_protocol == 'https' ? 'ssl://' : '') . $this->_host, $this->_port);
       
fwrite($this->_fp, $req);
        while(
is_resource($this->_fp) && $this->_fp && !feof($this->_fp))
           
$response .= fread($this->_fp, 1024);
       
fclose($this->_fp);
       
       
// split header and body
       
$pos = strpos($response, $crlf . $crlf);
        if(
$pos === false)
            return(
$response);
       
$header = substr($response, 0, $pos);
       
$body = substr($response, $pos + 2 * strlen($crlf));
       
       
// parse headers
       
$headers = array();
       
$lines = explode($crlf, $header);
        foreach(
$lines as $line)
            if((
$pos = strpos($line, ':')) !== false)
               
$headers[strtolower(trim(substr($line, 0, $pos)))] = trim(substr($line, $pos+1));
       
       
// redirection?
       
if(isset($headers['location']))
        {
           
$http = new HTTPRequest($headers['location']);
            return(
$http->DownloadToString($http));
        }
        else
        {
            return(
$body);
        }
    }
}
?>
up
5
ideacode
15 years ago
Note that whether you may open directories is operating system dependent. The following lines:

<?php
// Windows ($fh === false)
$fh = fopen('c:\\Temp', 'r');

// UNIX (is_resource($fh) === true)
$fh = fopen('/tmp', 'r');
?>

demonstrate that on Windows (2000, probably XP) you may not open a directory (the error is "Permission Denied"), regardless of the security permissions on that directory.

On UNIX, you may happily read the directory format for the native filesystem.
up
2
keithm at aoeex dot NOSPAM dot com
19 years ago
I was working on a consol script for win32 and noticed a few things about it.  On win32 it appears that you can't re-open the input stream for reading, but rather you have to open it once, and read from there on.  Also, i don't know if this is a bug or what but it appears that fgets() reads until the new line anyway.  The number of characters returned is ok, but it will not halt reading and return to the script.  I don't know of a work around for this right now, but i'll keep working on it.

This is some code to work around the close and re-open of stdin.

<?php
function read($length='255'){
    if (!isset(
$GLOBALS['StdinPointer'])){
       
$GLOBALS['StdinPointer']=fopen("php://stdin","r");
    }
   
$line=fgets($GLOBALS['StdinPointer'],$length);
    return
trim($line);
}
echo
"Enter your name: ";
$name=read();
echo
"Enter your age: ";
$age=read();
echo
"Hi $name, Isn't it Great to be $age years old?";
@
fclose($StdinPointer);
?>
up
1
php at richardneill dot org
9 years ago
fopen() will block if the file to be opened is a fifo. This is true whether it's opened in "r" or "w" mode.  (See man 7 fifo: this is the correct, default behaviour; although Linux supports non-blocking fopen() of a fifo, PHP doesn't).
The consequence of this is that you can't discover whether an initial fifo read/write would block because to do that you need stream_select(), which in turn requires that fopen() has happened!
up
0
php-manual at merlindynamics dot com
4 months ago
There is an undocumented mode for making fopen non-blocking (not working on windows). By adding 'n' to the mode parameter, fopen will not block, however if the pipe does not exist an error will be raised.

$fp = fopen("/tmp/debug", "a"); //blocks if pipe does not exist

$fp = fopen("/tmp/debug", "an"); //raises error on pipe not exist
up
2
flobee
14 years ago
download: i need a function to simulate a "wget url" and do not buffer the data in the memory to avoid thouse problems on large files:
<?php
function download($file_source, $file_target) {
       
$rh = fopen($file_source, 'rb');
       
$wh = fopen($file_target, 'wb');
        if (
$rh===false || $wh===false) {
// error reading or opening file
          
return true;
        }
        while (!
feof($rh)) {
            if (
fwrite($wh, fread($rh, 1024)) === FALSE) {
                  
// 'Download error: Cannot write to file ('.$file_target.')';
                  
return true;
               }
        }
       
fclose($rh);
       
fclose($wh);
       
// No error
       
return false;
    }
?>
up
0
etters dot ayoub at gmail dot com
2 years ago
This functions check recursive permissions and recursive existence parent folders, before creating a folder. To avoid the generation of errors/warnings.

/**
* This functions check recursive permissions and recursive existence parent folders,
* before creating a folder. To avoid the generation of errors/warnings.
*
* @return bool
*     true folder has been created or exist and writable.
*     False folder not exist and cannot be created.
*/
function createWritableFolder($folder)
{
    if (file_exists($folder)) {
        // Folder exist.
        return is_writable($folder);
    }
    // Folder not exit, check parent folder.
    $folderParent = dirname($folder);
    if($folderParent != '.' && $folderParent != '/' ) {
        if(!createWritableFolder(dirname($folder))) {
            // Failed to create folder parent.
            return false;
        }
        // Folder parent created.
    }

    if ( is_writable($folderParent) ) {
        // Folder parent is writable.
        if ( mkdir($folder, 0777, true) ) {
            // Folder created.
            return true;
        }
        // Failed to create folder.
    }
    // Folder parent is not writable.
    return false;
}

/**
* This functions check recursive permissions and recursive existence parent folders,
* before creating a file/folder. To avoid the generation of errors/warnings.
*
* @return bool
*     true has been created or file exist and writable.
*     False file not exist and cannot be created.
*/
function createWritableFile($file)
{
    // Check if conf file exist.
    if (file_exists($file)) {
        // check if conf file is writable.
        return is_writable($file);
    }

    // Check if conf folder exist and try to create conf file.
    if(createWritableFolder(dirname($file)) && ($handle = fopen($file, 'a'))) {
        fclose($handle);
        return true; // File conf created.
    }
    // Inaccessible conf file.
    return false;
}
up
1
durwood at speakeasy dot NOSPAM dot net
15 years ago
I couldn't for the life of me get a certain php script working when i moved my server to a new Fedora 4 installation. The problem was that fopen() was failing when trying to access a file as a URL through apache -- even though it worked fine when run from the shell and even though the file was readily readable from any browser.  After trying to place blame on Apache, RedHat, and even my cat and dog, I finally ran across this bug report on Redhat's website:

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=164700

Basically the problem was SELinux (which I knew nothing about) -- you have to run the following command in order for SELinux to allow php to open a web file:

/usr/sbin/setsebool httpd_can_network_connect=1

To make the change permanent, run it with the -P option:

/usr/sbin/setsebool -P httpd_can_network_connect=1

Hope this helps others out -- it sure took me a long time to track down the problem.
up
0
kasper at webmasteren dot eu
8 years ago
"Do not use the following reserved device names for the name of a file:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1,
LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names
followed immediately by an extension; for example, NUL.txt is not recommended.
For more information, see Namespaces"
it is a windows limitation.
see:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
up
0
sean downey
12 years ago
when using ssl / https on windows i would get the error:
"Warning: fopen(https://example.com): failed to open stream: Invalid argument in someSpecialFile.php on line 4344534"

This was because I did not have the extension "php_openssl.dll" enabled.

So if you have the same problem, goto your php.ini file and enable it :)
up
0
ceo at l-i-e dot com
14 years ago
If you need fopen() on a URL to timeout, you can do like:
<?php
  $timeout
= 3;
 
$old = ini_set('default_socket_timeout', $timeout);
 
$file = fopen('http://example.com', 'r');
 
ini_set('default_socket_timeout', $old);
 
stream_set_timeout($file, $timeout);
 
stream_set_blocking($file, 0);
 
//the rest is standard
?>
up
-1
apathetic012 at gmail dot com
8 years ago
a variable $http_response_header is available when doing the fopen(). Which contains an array of the response header.
up
-1
splogamurugan at gmail dot com
9 years ago
While opening a file with multibyte data (Ex: données multi-octets), faced some issues with the encoding. Got to know that it uses  windows-1250. Used iconv to convert it to UTF-8 and it resolved the issue. 

<?php
function utf8_fopen_read($fileName) {
   
$fc = iconv('windows-1250', 'utf-8', file_get_contents($fileName));
   
$handle=fopen("php://memory", "rw");
   
fwrite($handle, $fc);
   
fseek($handle, 0);
    return
$handle;
}
?>

Example usage:

<?php
$fh
= utf8_fopen_read("./tpKpiBundle.csv");
while ((
$data = fgetcsv($fh, 1000, ",")) !== false) {
    foreach (
$data as $value) {
        echo
$value . "<br />\n";
    }
}
?>

Hope it helps.
up
0
ken dot gregg at rwre dot com
16 years ago
PHP will open a directory if a path with no file name is supplied. This just bit me. I was not checking the filename part of a concatenated string.

For example:

<?php
$fd
= fopen('/home/mydir/' . $somefile, 'r');
?>

Will open the directory if $somefile = ''

If you attempt to read using the file handle you will get the binary directory contents. I tried append mode and it errors out so does not seem to be dangerous.

This is with FreeBSD 4.5 and PHP 4.3.1. Behaves the same on 4.1.1 and PHP 4.1.2. I have not tested other version/os combinations.
up
0
dan at cleandns dot com
16 years ago
<?php
#going to update last users counter script since
#aborting a write because a file is locked is not correct.

$counter_file = '/tmp/counter.txt';
clearstatcache();
ignore_user_abort(true);     ## prevent refresh from aborting file operations and hosing file
if (file_exists($counter_file)) {
  
$fh = fopen($counter_file, 'r+');
    while(
1) {
      if (
flock($fh, LOCK_EX)) {
        
#$buffer = chop(fgets($fh, 2));
        
$buffer = chop(fread($fh, filesize($counter_file)));
        
$buffer++;
        
rewind($fh);
        
fwrite($fh, $buffer);
        
fflush($fh);
        
ftruncate($fh, ftell($fh));    
        
flock($fh, LOCK_UN);
         break;
      }
   }
}
else {
  
$fh = fopen($counter_file, 'w+');
  
fwrite($fh, "1");
  
$buffer="1";
}
fclose($fh);

print
"Count is $buffer";

?>
up
-1
k-gun at git dot io
10 months ago
Seems not documented here but keep in mind, when $filename contains null byte (\0) then a TypeError will be thrown with message such;

TypeError: fopen() expects parameter 1 to be a valid path, string given in ...
To Top