PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

fpassthru> <fnmatch
Last updated: Fri, 05 Sep 2008

view this page in

fopen

(PHP 4, PHP 5)

fopenOuvre un fichier ou une URL

Description

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

fopen() crée une ressource nommée, spécifiée par le paramètre filename , sous la forme d'un flux.

Liste de paramètres

filename

Si filename est de la forme "protocole://", filename est supposé être une URL, et PHP va rechercher un gestionnaire de protocole adapté pour lire ce fichier. Si aucun gestionnaire pour ce protocole n'est disponible, PHP va émettre une alerte qui vous permettra de savoir que vous avez des problèmes dans votre script, et il tentera d'exploiter filename comme un fichier classique.

Si PHP décide que le fichier filename est un fichier local, il va essayer d'ouvrir un flux avec ce fichier. Le fichier doit être accessible à PHP. Il vous faut donc vous assurer que vous avez les droits d'accès à ce fichier. Si vous activez le safe mode, ou la directive open_basedir, d'autres conditions peuvent aussi s'appliquer.

Si PHP a décidé que filename spécifie un protocole enregistré, et que ce protocole est enregistré comme un protocole réseau, PHP s'assurera que la directive allow_url_fopen est activée. Si elle est inactive, PHP va émettre une alerte et l'ouverture va échouer.

Note: La liste des protocoles supportés est disponible sur Liste des protocoles supportés. Certains protocoles (appelés aussi wrappers ou gestionnaires) supportent des context et/ou des options dans le fichier php.ini. Référez-vous aux pages du manuel traitant le protocole, pour connaître la liste des options qui sont disponibles. ( e.g. l'option de php.ini user_agent est utilisée par le gestionnaire http).

Sous Windows, assurez-vous de bien protéger les antislash utilisés dans le chemin du fichier, ou bien utilisez des slashs.

<?php
$handle 
fopen("c:\\data\\info.txt""r");
?>

mode

Le paramètre mode spécifie le type d'accès désiré au flux. Il peut prendre les valeurs suivantes :

Liste des modes possibles pour la fonction fopen() en utilisant le paramètre mode
mode Description
'r' Ouvre en lecture seule, et place le pointeur de fichier au début du fichier.
'r+' Ouvre en lecture et écriture, et place le pointeur de fichier au début du fichier.
'w' Ouvre en écriture seule ; place le pointeur de fichier au début du fichier et réduit la taille du fichier à 0. Si le fichier n'existe pas, on tente de le créer.
'w+' Ouvre en lecture et écriture ; place le pointeur de fichier au début du fichier et réduit la taille du fichier à 0. Si le fichier n'existe pas, on tente de le créer.
'a' Ouvre en écriture seule ; place le pointeur de fichier à la fin du fichier. Si le fichier n'existe pas, on tente de le créer.
'a+' Ouvre en lecture et écriture ; place le pointeur de fichier à la fin du fichier. Si le fichier n'existe pas, on tente de le créer.
'x' Crée et ouvre le fichier en lecture seule ; place le pointeur de fichier au début du fichier. Si le fichier existe déjà, fopen() va échouer, en retournant FALSE et en générant une erreur de niveau E_WARNING. Si le fichier n'existe pas, fopen() tente de le créer. Ce mode est l'équivalent des options O_EXCL|O_CREAT pour l'appel système open(2) sous-jacent. Cette option est supportée à partir de PHP 4.3.2 et fonctionne uniquement avec des fichiers locaux.
'x+' Crée et ouvre le fichier en lecture et écriture ; place le pointeur de fichier au début du fichier. Si le fichier existe déjà, fopen() va échouer, en retournant FALSE et en générant une erreur de niveau E_WARNING. Si le fichier n'existe pas, fopen() tente de le créer. Ce mode est l'équivalent des options O_EXCL|O_CREAT pour l'appel système open(2) sous-jacent. Cette option est supportée à partir de PHP 4.3.2, et fonctionne uniquement avec des fichiers locaux.

Note: Les systèmes d'exploitation utilisent différents caractères pour les nouvelles lignes. Lorsque vous écrivez un fichier texte, et insérez une nouvelle ligne, vous devez utiliser le bon caractère pour votre système d'exploitation. Les systèmes Unix utilisent \n comme nouvelle ligne, les systèmes Windows utilisent \r\n, et les systèmes Macintosh utilisent \r.
Si vous n'utilisez pas le bon caractère de nouvelle ligne lors de l'écriture de vos fichiers, vous risquez d'ouvrir vos fichiers avec des applications qui donneront un aspect 'bizarre' au texte.
Windows propose un mode de traduction ('t'), qui va traduire automatiquement les caractères \n en \r\n lorsque vous travaillez sur le fichier. À l'inverse, vous pouvez utiliser l'option 'b' pour forcer le fichier a être écrit en mode binaire, sans traduction des données. Pour utiliser ces options, ajoutez 'b' ou 't' comme dernier caractère du paramètre mode .
Le mode de traduction par défaut dépend de l'interface SAPI et de la version de PHP que vous utilisez. Nous vous recommandons de toujours spécifier les options de traductions pour des raisons de portabilité. Vous devriez utiliser 't' lorsque vous écrivez des fichiers de texte, et le caractère \n pour définir vos fin de ligne, dans les scripts, mais que vous vous attendez à ce que le fichier soit relu par une application comme Notepad. Vous devriez toujours utiliser l'option 'b' dans les autres cas.
Si vous ne précisez pas 'b' lorsque vous travaillez avec des fichiers binaires, vous pourriez rencontrer des problèmes avec vos données, comme des images corrompues ou des caractères \r\n inopinés.

Note: Pour des raisons de portabilité, il est recommandé de toujours utiliser l'option 'b' lorsque vous ouvrez des fichiers avec fopen().

Note: À nouveau, pour des raisons de portabilité, il est fortement recommandé de réécrire les scripts qui utilisent l'option 't', pour qu'ils utilisent le bon caractère de nouvelle ligne, et le mode 'b'.

use_include_path

Le troisième paramètre optionnel use_include_path peut être défini à 1 ou à TRUE pour chercher le fichier dans l'include_path.

context

Note: Le support de contexte a été ajouté en PHP 5.0.0. Pour une description des contexts, référez-vous à Fonctions sur les flux.

Valeurs de retour

Retourne une ressource représentant le pointeur de fichier, ou FALSE si une erreur survient.

Erreurs / Exceptions

Si l'ouverture échoue, la fonction retourne FALSE et une alerte E_WARNING sera générée. Vous pouvez utiliser le caractère @ pour supprimer cette alerte.

Historique

Version Description
4.3.2 Depuis PHP 4.3.2, le mode par défaut est le mode binaire pour toutes les plates-formes qui font la distinction entre les modes binaire et texte. Si vous rencontrez des problèmes dans vos scripts après une mise à jour, essayez d'utiliser le flag 't' en attendant que vous rendiez votre script plus portable comme mentionné ci-dessous.
4.3.2 Les options 'x' et 'x+'ont été ajoutés.

Exemples

Exemple #1 Exemple avec fopen()

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

Notes

Avertissement

Lorsque vous utilisez SSL, le serveur IIS de Microsoft violera le protocole en fermant la connexion sans envoyer l'indicateur close_notify. PHP le reportera en tant que "SSL: Fatal Protocol Error" quand vous arrivez à la fin des données. L'astuce est de baisser le niveau de la directive error_reporting pour ne pas inclure les warnings. À partir de PHP 4.3.7, le bogue est détecté automatiquement lors de l'ouverture du flux en utilisant https:// et supprimera cet avertissement pour vous. Si vous utilisez fsockopen() pour créer une socket ssl://, vous devez vous occuper vous-même de supprimer l'erreur.

Note: Lorsque le safe-mode est activé, PHP vérifie si le fichier/dossier que vous allez utiliser a le même UID que le script qui est actuellement exécuté.

Si vous rencontrez des problèmes en lecture ou écriture de fichier et que vous utilisez PHP en version module de serveur, n'oubliez pas que les fichiers auxquels vous accédez ne sont pas nécessairement accessibles au processus serveur.



fpassthru> <fnmatch
Last updated: Fri, 05 Sep 2008
 
add a note add a note User Contributed Notes
fopen
Luc
27-Aug-2008 09:58
If your connection goes through a proxy, you may also
try using CURL:

curl_setopt($CurlHandler, $CURLOPT_PROXY, "192.168.0.2");
curl_setopt($CurlHandler, CURLOPT_PROXYUSERPWD, "login:password");
php at delhelsa dot com
24-Jun-2008 09:27
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 townsville and you're trying to access it with user blossom and password buttercup, the url would be:

ftp://blossom:buttercup@townsville//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.
erk_3 at hotmail dot com
12-May-2008 05:48
If you are getting permission denied trying to write/read to a network resource, you have to change the system account that the apache service is runnning on.
However if you are on a domain, you will need to use the user name as:
user@domain.com

If you user the format: domain\username  the service will successfully start, but you will still receive errors trying to access the network resource.
webmaster at myeshop dot fr
26-Apr-2008 04:40
Also a small function useful for backup for example. It's a mixed between the fopen() and the mkdir() functions.

This function opens a file but also make the path recursively where the file is contained. This is helpful for ending to finish with "No such file or directory in" errors

function fopen_recursive($path, $mode, $chmod=0755){
  preg_match('`^(.+)/([a-zA-Z0-9]+\.[a-z]+)$`i', $path, $matches);
  $directory = $matches[1];
  $file = $matches[2];

  if (!is_dir($directory)){
    if (!mkdir($directory, $chmod, 1)){
    return FALSE;
    }
  }
 return fopen ($path, $mode);
}
jabeba at web dot de
17-Apr-2008 03:21
If you have to use a proxy to make requests outside of your local network, you may use this class:

/*
 *
 * No Proxy Authentification Implemented; PHP 5
 *
 */

class RemoteFopenViaProxy {

    private $result;
    private $proxy_name;
    private $proxy_port;
    private $request_url;

    public function get_proxy_name() {
        return $this->proxy_name;
    }

    public function set_proxy_name($n) {
        $this->proxy_name = $n;
    }

    public function get_proxy_port() {
        return $this->proxy_port;
    }

    public function set_proxy_port($p) {
        $this->proxy_port = $p;
    }

    public function get_request_url() {
        return $this->request_url;
    }

    public function set_request_url($u) {
        $this->request_url = $u;
    }

    public function get_result() {
        return $this->result;
    }

    public function set_result($r) {
        $this->result = $r;
    }

    private function get_url_via_proxy() {

        $proxy_fp = fsockopen($this->get_proxy_name(), $this->get_proxy_port());

        if (!$proxy_fp) {
            return false;
        }
        fputs($proxy_fp, "GET " . $this->get_request_url() . " HTTP/1.0\r\nHost: " . $this->get_proxy_name() . "\r\n\r\n");
        while (!feof($proxy_fp)) {
            $proxy_cont .= fread($proxy_fp, 4096);
        }
        fclose($proxy_fp);
        $proxy_cont = substr($proxy_cont, strpos($proxy_cont, "\r\n\r\n") + 4);
        return $proxy_cont;

    }

    private function get_url($url) {
        $fd = @ file($url);
        if ($fd) {
            return $fd;
        } else {
            return false;
        }
    }

    private function logger($line, $file) {
        $fd = fopen($file . ".log", "a+");
        fwrite($fd, date("Ymd G:i:s") . " - " . $file . " - " . $line . "\n");
        fclose($fd);
    }

    function __construct($url, $proxy_name = "", $proxy_port = "") {

        $this->set_request_url($url);
        $this->set_proxy_name($proxy_name);
        $this->set_proxy_port($proxy_port);

    }

    public function request_via_proxy() {

        $this->set_result($this->get_url_via_proxy());
        if (!$this->get_result()) {
            $this->logger("FAILED: get_url_via_proxy(" . $this->get_proxy_name() . "," . $this->get_proxy_port() . "," . $this->get_request_url() . ")", "RemoteFopenViaProxyClass.log");
        }
    }

    public function request_without_proxy() {

        $this->set_result($this->get_url($this->get_request_url()));
        if (!$this->get_result()) {
            $this->logger("FAILED: get_url(" . $url . ")", "RemoteFopenViaProxyClass.log");
        }
    }
}

Use it this way:
// call constructor
$obj = new RemoteFopenViaProxy($insert_request_url, $insert_proxy_name, $insert_proxy_port);
// change settings after object generation
$obj->set_proxy_name($insert_proxy_name);
$obj->set_proxy_port($insert_proxy_port);
$obj->set_request_url($insert_request_url);
$obj->request_via_proxy();
echo $obj->get_result();

If there are errors during execution, the script tries to write some useful information into a log file.
jphansen at uga dot edu
22-Feb-2008 04:04
If you open a file with r+ and execute an fwrite(), writing less to the file than what it originally was, it will result in the difference being padded with the end of the file from the previous end of the file. Example:

<?
// Open file for read and string modification
$file = "/test";
$fh = fopen($file, 'r+');
$contents = fread($fh, filesize($file));
$new_contents = str_replace("hello world", "hello", $contents);
fclose($fh);

// Open file to write
$fh = fopen($file, 'r+');
fwrite($fh, $new_contents);
fclose($fh);
?>

If the end of the file was "abcdefghij", you will notice that the difference in "hello world" and "hello", 6 characters, will be appended to the file, resulting in the new ending: "efghij". To obviate this, fopen() with +w instead, which truncates the file to zero length.
sean downey
09-Feb-2008 09:23
when using ssl / https on windows i would get the error:
"Warning: fopen(https://cia.gov): 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 :)
richard dot thomas at psysolutions dot com
28-Nov-2007 08:22
fopen appears to choke on some redirects which do not give problems to browsers or wget

Example: this redirect

Location: /NetPerfMon/NetworkMap.asp?Map=Network Overview&Scale=50

Causes this request:

GET /NetPerfMon/NetworkMap.asp?Map=Network Overview&Scale=50 HTTP/1.0

Which is an invalid request due to the space. I don't recall if this is correct behavior according to the RFC or not (I'm 100% sure that fopen shouldn't be sending requests with spaces in but it may be that the Location: redirect shouldn't have spaces either) but the the big two browsers and wget handle it gracefully

I'll also add a note that fopen does no cookie handling. The above is part of two redirects. The first redirects to a page which issues cookies, the second redirects to the original page. If there was not a problem with the space above, this would have led to a loop broken only by any redirect limit rules coded into fopen. Handling cookies may be outside the scope of fopen but I think it is worth noting in case anyone else would run into it.

PHP 5.2.0
info at NOSPAMPLEASE dot c-eagle dot com
09-Oct-2007 03:14
If there is a file that´s excessively being rewritten by many different users, you´ll note that two almost-simultaneously accesses on that file could interfere with each other. For example if there´s a chat history containing only the last 25 chat lines. Now adding a line also means deleting the very first one. So while that whole writing is happening, another user might also add a line, reading the file, which, at this point, is incomplete, because it´s just being rewritten. The second user would then rewrite an incomplete file and add its line to it, meaning: you just got yourself some data loss!

If flock() was working at all, that might be the key to not let those interferences happen - but flock() mostly won´t work as expected (at least that´s my experience on any linux webserver I´ve tried), and writing own file-locking-functions comes with a lot of possible issues that would finally result in corrupted files. Even though it´s very unlikely, it´s not impossible and has happened to me already.

So I came up with another solution for the file-interference-problem:

1. A file that´s to be accessed will first be copied to a temp-file directory and its last filemtime() is being stored in a PHP-variable. The temp-file gets a random filename, ensuring no other process is able to interfere with this particular temp-file.
2. When the temp-file has been changed/rewritten/whatever, there´ll be a check whether the filemtime() of the original file has been changed since we copied it into our temp-directory.
2.1. If filemtime() is still the same, the temp-file will just be renamed/moved to the original filename, ensuring the original file is never in a temporary state - only the complete previous state or the complete new state.
2.2. But if filemtime() has been changed while our PHP-process wanted to change its file, the temp-file will just be deleted and our new PHP-fileclose-function will return a FALSE, enabling whatever called that function to do it again (ie. upto 5 times, until it returns TRUE).

These are the functions I´ve written for that purpose:

<?php
$dir_fileopen
= "../AN/INTERNAL/DIRECTORY/fileopen";

function
randomid() {
    return
time().substr(md5(microtime()), 0, rand(5, 12));
}

function
cfopen($filename, $mode, $overwriteanyway = false) {
    global
$dir_fileopen;
   
clearstatcache();
    do {
       
$id = md5(randomid(rand(), TRUE));
       
$tempfilename = $dir_fileopen."/".$id.md5($filename);
    } while(
file_exists($tempfilename));
    if (
file_exists($filename)) {
       
$newfile = false;
       
copy($filename, $tempfilename);
    }else{
       
$newfile = true;
    }
   
$fp = fopen($tempfilename, $mode);
    return
$fp ? array($fp, $filename, $id, @filemtime($filename), $newfile, $overwriteanyway) : false;
}

function
cfwrite($fp,$string) { return fwrite($fp[0], $string); }

function
cfclose($fp, $debug = "off") {
    global
$dir_fileopen;
   
$success = fclose($fp[0]);
   
clearstatcache();
   
$tempfilename = $dir_fileopen."/".$fp[2].md5($fp[1]);
    if ((@
filemtime($fp[1]) == $fp[3]) or ($fp[4]==true and !file_exists($fp[1])) or $fp[5]==true) {
       
rename($tempfilename, $fp[1]);
    }else{
       
unlink($tempfilename);
        if (
$debug != "off") echo "While writing, another process accessed $fp[1]. To ensure file-integrity, your changes were rejected.";
       
$success = false;
    }
    return
$success;
}
?>

$overwriteanyway, one of the parameters for cfopen(), means: If cfclose() is used and the original file has changed, this script won´t care and still overwrite the original file with the new temp file. Anyway there won´t be any writing-interference between two PHP processes, assuming there can be no absolute simultaneousness between two (or more) processes.
misc at n4te dot com
06-Oct-2007 03:21
The UTF-8 BOM is optional. PHP does not ignore it if it is present when reading UTF-8 encoded data. Here is a function that skips the BOM, if it exists.

// Reads past the UTF-8 bom if it is there.
function fopen_utf8 ($filename, $mode) {
    $file = @fopen($filename, $mode);
    $bom = fread($file, 3);
    if ($bom != b"\xEF\xBB\xBF")
        rewind($file, 0);
    else
        echo "bom found!\n";
    return $file;
}
bluej100@gmail
21-Aug-2007 12:28
@ericw at w3consultant dot net:

It's a resource, not an object. var_dump meant what it said. ;)

http://us.php.net/manual/en/language.types.resource.php

http://us.php.net/manual/en/function.is-resource.php
Adlez
04-Aug-2007 10:32
For those of you who do not have cURL, you might want to try this.
It doesn't have all the functions that cURL has, but it has the basics.
Please let me know of any bugs or problems.

<?php
function open_page($url,$f=1,$c=2,$r=0,$a=0,$cf=0,$pd=""){
 global
$oldheader;
 
$url = str_replace("http://","",$url);
 if (
preg_match("#/#","$url")){
 
$page = $url;
 
$url = @explode("/",$url);
 
$url = $url[0];
 
$page = str_replace($url,"",$page);
  if (!
$page || $page == ""){
  
$page = "/";
  }
 
$ip = gethostbyname($url);
 }else{
 
$ip = gethostbyname($url);
 
$page = "/";
 }
 
$open = fsockopen($ip, 80, $errno, $errstr, 60);
 if (
$pd){
 
$send = "POST $page HTTP/1.0\r\n";
 }else{
 
$send = "GET $page HTTP/1.0\r\n";
 }
 
$send .= "Host: $url\r\n";
 if (
$r){
 
$send .= "Referer: $r\r\n";
 }else{
  if (
$_SERVER['HTTP_REFERER']){
  
$send .= "Referer: {$_SERVER['HTTP_REFERER']}\r\n";
  }
 }
 if (
$cf){
  if (@
file_exists($cf)){
  
$cookie = urldecode(@file_get_contents($cf));
   if (
$cookie){
   
$send .= "Cookie: $cookie\r\n";
   
$add = @fopen($cf,'w');
   
fwrite($add,"");
   
fclose($add);
   }
  }
 }
 
$send .= "Accept-Language: en-us, en;q=0.50\r\n";
 if (
$a){
 
$send .= "User-Agent: $a\r\n";
 }else{
 
$send .= "User-Agent: {$_SERVER['HTTP_USER_AGENT']}\r\n";
 }
 if (
$pd){
 
$send .= "Content-Type: application/x-www-form-urlencoded\r\n"
 
$send .= "Content-Length: " .strlen($pd) ."\r\n\r\n";
 
$send .= $pd;
 }else{
 
$send .= "Connection: Close\r\n\r\n";
 }
 
fputs($open, $send);
 while (!
feof($open)) {
 
$return .= fgets($open, 4096);
 }
 
fclose($open);
 
$return = @explode("\r\n\r\n",$return,2);
 
$header = $return[0];
 if (
$cf){
  if (
preg_match("/Set\-Cookie\: /i","$header")){
  
$cookie = @explode("Set-Cookie: ",$header,2);
  
$cookie = $cookie[1];
  
$cookie = explode("\r",$cookie);
  
$cookie = $cookie[0];
  
$cookie = str_replace("path=/","",$cookie[0]);
  
$add = @fopen($cf,'a');
  
fwrite($add,$cookie,strlen($read));
  
fclose($add);
  }
 }
 if (
$oldheader){
 
$header = "$oldheader<br /><br />\n$header";
 }
 
$header = str_replace("\n","<br />",$header);
 if (
$return[1]){
 
$body = $return[1];
 }else{
 
$body = "";
 }
 if (
$c === 2){
  if (
$body){
  
$return = $body;
  }else{
  
$return = $header;
  }
 }
 if (
$c === 1){
 
$return = $header;
 }
 if (
$c === 3){
 
$return = "$header$body";
 }
 if (
$f){
  if (
preg_match("/Location\:/","$header")){
  
$url = @explode("Location: ",$header);
  
$url = $url[1];
  
$url = @explode("\r",$url);
  
$url = $url[0];
  
$oldheader = str_replace("\r\n\r\n","",$header);
  
$l = "&#76&#111&#99&#97&#116&#105&#111&#110&#58";
  
$oldheader = str_replace("Location:",$l,$oldheader);
   return
open_page($url,$f,$c,$r,$a,$cf,$pd);
  }else{
   return
$return;
  }
 }else{
  return
$return;
 }
}
/////////////
////Usage////
/////////////
$url = "http://www.php.net";
$f = 1;
$c = 2;//1 for header, 2 for body, 3 for both
$r = NULL;
$a = NULL;
$cf = NULL;
$pd = NULL;
$page = open_page($url,$f,$c,$r,$a,$cf,$pd);
print
$page;
?>
Elliott Brueggeman
02-Jul-2007 08:43
I did some basic performance testing of fopen() + fread() versus file_get_contents() when opening a remote file for reading, and it looks like fread() is actually a little bit faster than fopen(). While it may be because of my GoDaddy hosting server’s configuration, it makes me favor using fopen() over file_get_contents(). Fopen() also has the added benefit of greater PHP version compatibility.

Test results: http://www.ebrueggeman.com/php_benchmarking_fopen.php
JB
07-Jun-2007 12:30
A note on pflaume dot NOSPAM at NOSPAM dot gmx dot de's proxy application for fopen, which was very handy.
I found with Tor on OSX that the Host request header to the proxy (set to the Proxy IP) was not necessary, and was passed on to the target site causing most to return a 404 Error.
simon dot allen at swerve dot co dot nz
10-Apr-2007 04:56
using fopen to upload a file through ftp cannot overwrite that file - use curl instead
naidim at gmail dot com
29-Mar-2007 12:54
While PHP does not have a function to insert text into the middle of a file, it is not that complicated to do.

<?php
function addRSSItem($rssFile, $firstItem, $item){
   
// Backup file
   
if(!copy($rssFile, 'backup.rss')) die('Backup failed!');
   
// Store file contents in array
   
$arrFile = file($rssFile);
   
// Open file for output
   
if(($fh = fopen($rssFile,'w')) === FALSE){
        die(
'Failed to open file for writing!');
    }
   
// Set counters
   
$currentLine = 0;
   
$cntFile = count($arrFile);
   
// Write contents, inserting $item as first item
   
while( $currentLine <= $cntFile ){
        if(
$currentLine == $firstItem) fwrite($fh, $item);
       
fwrite($fh, $arrFile[$currentLine]);
       
$currentLine++;
    }
   
// Delete backup
   
unlink('backup.rss');
}

$data = "    <item>\n<title>$_POST['title]</title>\n".
 
"        <description>$_POST['description']</description>\n".
 
"        <pubDate>$_POST['date']</pubDate>\n".
 
"        <link>http://www.site.com/mp3s/".
 
basename($_FILES['fullPath']['name'])."</link>".
 
"        <enclosure url=\"http://www.site.com/mp3s/".
 
basename($_FILES['fullPath']['name']).
 
"\" length=\"$_FILES[fullPath][size]\" type=\"audio/mpeg\" />".
 
"    </item>\n";
addRSSItem('/var/www/html/rss/podcast.rss',20,$data);
?>
21-Mar-2007 01:45
If you want to download a file from a URL to a local file, you could just as well use copy() :)
andrew at NOSPAM dot neonsurge dot com
10-Feb-2007 03:22
My recent findings on high-performance fopen/fsockopen usage.

Note #1: The performance comparison below regarding curl is obsolete when utilizing certain things in this comment.  My performance tests download and upload about 97% as fast as curl with a custom non-socket blocking HTTP Transport class written for a high performance system in PHP5.

Note #2: fopen and fsockopen have a "feature' that always forces DNS resolution.  Check this code...

<?php for ($i = 0; $i < 50; $i++) {
   
$errno = $errstr = "";
   
//$ip = gethostbyname("php.net");  $a = fsockopen($ip,22,$errno,$errstr,10);  //FAST way
   
$a = fsockopen("php.net",22,$errno,$errstr,10); //SLOW way
   
$ab = fread($a,4096); unset($a, $ab);
}
?>

fsockopen() and fopen() always force php.net to be resolved every time and in this example above it resolves the name 50 seperate times and does not use the local cache.  To get around this, gethostbyname() does use your local DNS cache properly, it will not try to get the IP from your DNS server 50 times.  The above code for me to a personal server took 87 seconds the fast way, and 5.74 seconds the slow way, a 650% increase.  And this is single-threaded!  ;)

Note #3: I see a lot of notes and people mentioning non-blocking sockets, especially for HTTP transport.  I thought I would share a little from my experience.  First, the above command fsockopen() allows you to specify a timeout, after you check if it's  opened properly (as you should _always_) you just need to...

<?php stream_set_blocking($a,0);?>

From this point on certain considerations must be taken.  Remember you are not blocking anymore, so when you want to write or read a lot of data it will always return to you instantly.  Which is important since you need to check the return value of your writes and reads against how much you expect to read/write.  For reading if you do not know how long it is, checking for EOF works also.

This is in fact a neat feature and state, since you can now make a read/write loop to send/receive a lot of data and check the time/timeout value(s) constantly.  If that timeout is hit you can throw back errors properly to whatever function/method/code called your transport function/class.  The graceful failure with custom shorter failure times allows your application to continue, especially web-based applications where fopen alone and even curl under certain circumstances does not follow your requested timeouts, it will wait a full 60-90 seconds, depending on your OS.

Good ways to test a custom non-blocking timeout supported transport method described above is to make one first, and then transfer a large file with it, and halfway through unplug your network cable.  Curl or fopen/fread/fwrite alone will croak and make your applications wait a full 60-90 seconds, whereas a nice custom class will check if no data has been transferred for 15 seconds (or less!) and will fail gracefully with a error.

If anyone is interested in chatting about this feel free to contact me or add to this comment.
download dot function at nospam dot com
22-Jan-2007 11:34
Thanks very much to flobee (15-Jan-2006) who provided a download() function with realtime writing instead of buffering the result, very clever. However, your function is too basic, it has almost zero error checking, and also forgets to close file handles in one case(!). Not only that, but you have mixed up the meaning of return values, where you have made false = no errors and true = error occured. I've added full error checking, optimized the code, and of course corrected the return values. True = Success. Here are the changes:

1. If the file that we are saving to already exists it removes any read-only flag so that it can be overwritten.
2. Correctly formats the URL we are downloading from so that fopen() understands it. For instance, if you pass a URL with spaces, those have to be encoded to %20, and any html entities such as &amp; have to be decoded to & or the fopen() call fails, I've added these transformations so that the user does not have to pre-format the URL before passing it to download().
3. I've added the closing of file handles at a point where you forgot to.
4. The error messages are all handled by fopen/fwrite, so if the function has returned false for an error, you need to enable "Display_Errors" in the INI to see what happened, or alternatively use "ini_set('display_errors', 1);" at the top of your PHP file.

I don't think there is _anything_ else that can be improved, but if you can think of something then you are welcome to submit your version.

function download ($file_source, $file_target)
{
  // Preparations
  $file_source = str_replace(' ', '%20', html_entity_decode($file_source)); // fix url format
  if (file_exists($file_target)) { chmod($file_target, 0777); } // add write permission

  // Begin transfer
  if (($rh = fopen($file_source, 'rb')) === FALSE) { return false; } // fopen() handles
  if (($wh = fopen($file_target, 'wb')) === FALSE) { return false; } // error messages.
  while (!feof($rh))
  {
    // unable to write to file, possibly because the harddrive has filled up
    if (fwrite($wh, fread($rh, 1024)) === FALSE) { fclose($rh); fclose($wh); return false; }
  }

  // Finished without errors
  fclose($rh);
  fclose($wh);
  return true;
}
perrog at gmail dot com
21-Jan-2007 01:05
Note: If you have opened the file in append mode ("a" or "a+"), any data you write to the file will always be appended, regardless of the file position. But PHP distinguish between read and write position, and you may freely read at any position, but when you write it will always append at the end.

If you don't want that write restriction, open the file in read-write mode ("r+") and then start by moving the file pointer to the end.

if (($fp = fopen($filename, "r+") === FALSE) {
  // handle error
  exit;
}

if (fseek($fp, 0, SEEK_END) === -1) {
  // handle error
  exit;
}
patryk dot szczyglowski at gmail dot com
20-Sep-2006 04:02
Watch out not to specify empty string as filename. It seems PHP is trying to get data from stdin which may end up in script timeout. It may not be trivial to find.

<?php
$fp
= fopen('', 'r'); // wrong
?>
roman dot nastenko at gmail dot com
19-May-2006 05:09
php 4.4.2 realy introduced a blocker problem with fopen() (http://bugs.php.net/bug.php?id=36017)

In that case you can use sockets for file open.

Example. Not

   $viart_xml = fopen("http://www.viart.com/viart_shop.xml", "r");

But

   $viart_xml = fsockopen("www.viart.com", 80, $errno, $errstr, 12);

   fputs($viart_xml, "GET /viart_shop.xml HTTP/1.0\r\n");
   fputs($viart_xml, "Host: www.viart.com\r\n");
   fputs($viart_xml, "Referer: http://www.viart.com\r\n");
   fputs($viart_xml, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n\r\n");

After that you can use $viart_xml as a simple file :)
puneet at puneetarora dot com
03-May-2006 12:25
Refering to the note by [info at b1g dot de]
on (24-Oct-2005 11:54)

sometimes you may also want HTTP error code returned from the server. The code of the HTTPRequest class can be modified as followed to do so ..

1. Add another member variable to the class

var $_error;       // HTTP Error code

2. After  the lines
.
.
       // parse headers
       $headers = array();
       $lines = explode($crlf, $header);
.
.

add

list($proto, $this->_error, $reply) = explode(" ", $lines[0]);

$proto and $reply can be treated as junk variables.

once DownloadToString() is called, the HTTP error code will be contained in the _error property of the object.
ceo at l-i-e dot com
11-Apr-2006 05:13
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
?>
zerkella at mi6 dot com dot ua
05-Apr-2006 04:02
During development of a set of non-blocking functions for downloading files from http-servers I've discovered that it's not possible to set timeout for fopen('http://somesite.com/somefile', 'rb').

All functions for controlling non-blocking mode (stream_set_blocking, stream_set_timeout, stream_context_set_option) use resource handle that is created via fopen(). But fopen() for HTTP connections internally makes quite a big set of actions: it creates socket, resolves webserver name, establishes actual connection. So hanging can occur anywhere in resolving and creating tcp-connection but you cannot control it.

Solutions:
1) Use socket functions. Set socket in non-blocking mode just after creation. Implement HTTP-protocol yourself. In source code use these manually created functions.
2) Write a wrapper for myprotocol://, which internally will use first solution, but in source code you'll use fopen('myprotocol://somesite.com/somefile', 'rb') with some way to set timeout before calling it.
Jeff McKenna
28-Feb-2006 10:26
It seems php 4.4.2 introduced a blocker problem with fopen() (http://bugs.php.net/bug.php?id=36017).
Paul Yanchenko
22-Jan-2006 02:16
I found a strange behaviour of PHP when several scripts trying to fopen a file for writing access simultaneously. I expect that this will result file sharing violation, but it's not and all scripts can open and write that file. I'd like to use sharing violation to control uniqueness of script instance, but now I even do know how to do this. The only idea is to use "x" flag in fopen(), but if that lock-file somehow will not be deleted - script will never run.

PHP 5.0.5, Windows XP Pro SP2
flobee
15-Jan-2006 04:58
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;
    }
?>
anonymous at anonymous dot com
27-Dec-2005 12:11
Contrary to a note below the concept of what the preferred line ending is on mac os x is a little bit fuzzy.  I'm pretty sure all the bsd utils installed by default are going to use \n but that is not necessarily the norm.  Some apps will use that while others will use \r.

You should be prepared to deal with either.
Camillo
19-Dec-2005 06:58
Contrary to what this page says, the preferred line ending on Macintosh systems is \n (LF). \r was used on legacy versions of the Mac OS (pre-OS X), and I don't think PHP even runs on those.
151408626 dot unique at servux dot org
19-Dec-2005 01:05
I found a nice trick how to work around the issue (mentioned here: http://www.php.net/manual/en/function.fopen.php#41243) that the PHP  process will block on opening a FIFO until data is sent to it:

Simply do send some data to the FIFO, using an echo command started in background (and ignoring that spedific data, when parsing whatever read from the FIFO).

A very simple example of that:
<?

// path & name of your FIFO-file
$someFIFO = "path/to/your/fifo"

// some string, that won't be found in your regular input data
$uniqueData = "some specific data";

// this statement actually does the trick providing some data waiting in the FIFO:
//   start echo to send data to the FIFO in the background!!
//   NOTE: parenthesis & second redirection (to /dev/null) are
//   important to keep PHP from waiting for echo to terminate! 
system("(echo -n '$uniqueData' >$someFIFO) >/dev/null &");

// now you can safely open the FIFO, without the PHP-process being blocked
$handle = fopen($someFIFO, 'r');

// loop reading data from the FIFO
while (TRUE) {
   
$data = fread($handle, 8192);

   
// eliminate the initially sent data from our read input
    //   NOTE: this is done only in a very simplyfied way in this example,
    //   that will break if that data-string might also be part of your regular input!!
   
if (!(strpos($inp, $uniqueData) === FALSE))    $data = str_replace($uniqueData, '', $data);

// here comes your processing of the read data...
}

?>
info at b1g dot de
24-Oct-2005 01:54
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.php.net');
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);
        }
    }
}
?>
admin at sellchain dot com
17-Oct-2005 04:34
TIP: If you are using fopen and fread to read HTTP or FTP or Remote Files, and experiencing some performance issues such as stalling, slowing down and otherwise, then it's time you learned a thing called cURL.

Performance Comparison:

10 per minute for fopen/fread for 100 HTTP files
2000 per minute for cURL for 2000 HTTP files

cURL should be used for opening HTTP and FTP files, it is EXTREMELY reliable, even when it comes to performance.

I noticed when using too many scripts at the same time to download the data from the site I was harvesting from, fopen and fread would go into deadlock. When using cURL i can open 50 windows, running 10 URL's from each window, and getting the best performance possible.

Just a Tip :)
nefertari at nefertari dot be
20-Sep-2005 02:47
Important note:

You have always to use the real path name for a file with the command fopen [for example: fopen($filename, 'w')], never use a symbolic link, it will not work (unable to open $filename).
francis dot fish at gmail dot com
10-Sep-2005 05:10
None of the examples on the page test to see if the file has been opened successfully. Fopen will return false if it failed. To quickly extend one of the examples in the manual:

  $filename = "some.dat" ;
  $dataFile = fopen( $filename, "r" ) ;

  if ( $dataFile )
  {
    while (!feof($dataFile))
    {
       $buffer = fgets($dataFile, 4096);
       echo $buffer;
    }

    fclose($dataFile);
  }
  else
  {
    die( "fopen failed for $filename" ) ;
  }

Hope this is some use.
durwood at speakeasy dot NOSPAM dot net
07-Sep-2005 08:43
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.
ericw at w3consultant dot net
02-Sep-2005 08:49
RE: using