Hướng dẫn write file php

Trong bài này, chúng ta sẽ tìm hiểu về cách create và write file trong PHP. Để học tốt bài này, các bạn cần đọc lại bài Cài đặt môi trường lập trình Web PHP với XAMPP để biết cách chạy ứng dụng web PHP với XAMPP.

1. Tạo file với hàm fopen() trong PHP

Hàm fopen() giúp mở một file và đưa file đó vào stream để chuẩn bị đọc/ghi dữ liệu. Cú pháp:

fopen(
  string $filename,
  string $mode,
  bool $use_include_path = false,
  ?resource $context = null
): resource|false

Với các $mode‘w’, ‘w+’, ‘a’, ‘a+’, ‘x’, ‘x+’ thì hàm fopen() giúp tạo một file mới khi file chưa tồn tại. Các bạn có thể tìm hiểu kỹ hơn cách sử dụng hàm fopen() tại Mở file với hàm fopen() trong PHP.

2. Ghi file với hàm fwrite() trong PHP

Hàm fwrite() được sử dụng để ghi dữ liệu vào file khi đã mở file với hàm fopen(). Cú pháp:

fwrite(resource $stream, string $data, ?int $length = null): int|false

Trong đó,

$stream là stream đọc file được mở bởi hàm fopen().

$data là chuỗi (string) dữ liệu được ghi vào file.

$length là số byte muốn ghi vào file.

Kết quả trả về của hàm fwrite() là số byte ghi được hoặc false nếu ghi file bị lỗi.

<?php
$myfile = fopen("gochocit.txt", "w") or die("Unable to open file!");
$txt = "Hello all, welcome to gochocit.com!\n";
fwrite($myfile, $txt);
$txt = "Very happy to see you visit gochocit.com.\n";
fwrite($myfile, $txt);
$txt = "Hope it might be useful for you!\n";
fwrite($myfile, $txt);
fclose($myfile);
?>

Khi mở file bằng hàm fopen() với chế độ “w” thì dữ liệu ghi vào file sẽ ghi đè (overwriting) lên dữ liệu cũ nếu file đã tồn tại. Nếu sử dụng chế độ “a” thì dữ liệu ghi vào file sẽ được ghi nối tiếp vào file.

3. Tạo và ghi file với hàm file_put_contents() trong PHP

Hàm file_put_contents() giúp ghi dữ liệu vào file. Nếu file không tồn tại thì file mới sẽ được tạo. Nếu file tồn tại thì dữ liệu trong file sẽ bị sẽ bị ghi đè. Nếu muốn ghi nối tiếp vào file thì sử dụng $flag = FILE_APPEND.

Hàm này có chức năng giống với việc gọi hàm fopen(), fwrite()fclose() liên tiếp để ghi dữ liệu vào một file. Cú pháp:

file_put_contents(
    string $filename,
    mixed $data,
    int $flags = 0,
    ?resource $context = null
): int|false

Trong đó,

$filename là đường dẫn của file cần ghi dữ liệu.

$data là dữ liệu cần ghi vào file. $data có thể là string, array hoặc stream resource.

$flag là các cờ thể hiện chế độ ghi dữ liệu của hàm file_put_contents(). Có thể kết hợp các flag với nhau bằng toán tử OR ( | ).

Flag Mô tả
FILE_USE_INCLUDE_PATH Có thể tìm file trong include_path.
FILE_APPEND Nếu file đã tồn tại, nối tiếp dữ liệu vào file thay vì phải ghi đè file.
LOCK_EX Khóa file nếu đang ghi dữ liệu.

$context là resource được tạo bởi hàm stream_context_create().

Kết quả trả về của hàm file_put_contents() là số byte được ghi vào file hoặc false nếu ghi file bị lỗi.

Ví dụ ghi đè dữ liệu vào file gochocit.txt

<?php
$file = 'gochocit.txt';
$data = "Hello all!";
file_put_contents($file, $data);
?>

Ví dụ nối dữ liệu vào file gochocit.txt

<?php
$file = 'gochocit.txt';
$data = "Hello all!";
file_put_contents($file, $data, FILE_APPEND | LOCK_EX);
?>

Trong ví dụ trên, $flagFILE_APPEND | LOCK_EX. $flag này có nghĩa là nối dữ liệu vào file gochocit.txt và khóa file trong khi ghi dữ liệu.

  • Lớp string trong C++ và các hàm thường dùng của lớp string
  • Cấu trúc điều khiển vòng lặp for trong Python
  • Nạp chồng toán tử (operator overloading) trong C++
  • Dẫn xuất public, protected, private trong kế thừa và minh họa với C++
  • Lỗi (error) và ngoại lệ (exception) trong Python

(PHP 4, PHP 5, PHP 7, PHP 8)

fwriteBinary-safe file write

Description

fwrite(resource $stream, string $data, ?int $length = null): int|false

fwrite() writes the contents of data to the file stream pointed to by stream.

Parameters

stream

A file system pointer resource that is typically created using fopen().

data

The string that is to be written.

length

If length is an int, writing will stop after length bytes have been written or the end of data is reached, whichever comes first.

Return Values

fwrite() returns the number of bytes written, or false on failure.

Errors/Exceptions

fwrite() raises E_WARNING on failure.

Changelog

VersionDescription
8.0.0 length is nullable now.

Examples

Example #1 A simple fwrite() example

<?php
$filename 
'test.txt';
$somecontent "Add this to the file\n";// Let's make sure the file exists and is writable first.
if (is_writable($filename)) {// In our example we're opening $filename in append mode.
    // The file pointer is at the bottom of the file hence
    // that's where $somecontent will go when we fwrite() it.
    
if (!$fp fopen($filename'a')) {
         echo 
"Cannot open file ($filename)";
         exit;
    }
// Write $somecontent to our opened file.
    
if (fwrite($fp$somecontent) === FALSE) {
        echo 
"Cannot write to file ($filename)";
        exit;
    }

    echo

"Success, wrote ($somecontent) to file ($filename)";fclose($fp);

} else {
    echo

"The file $filename is not writable";
}
?>

Notes

Note:

Writing to a network stream may end before the whole string is written. Return value of fwrite() may be checked:

<?php
function fwrite_stream($fp$string) {
    for (
$written 0$written strlen($string); $written += $fwrite) {
        
$fwrite fwrite($fpsubstr($string$written));
        if (
$fwrite === false) {
            return 
$written;
        }
    }
    return 
$written;
}
?>

Note:

On systems which differentiate between binary and text files (i.e. Windows) the file must be opened with 'b' included in fopen() mode parameter.

Note:

If stream was fopen()ed in append mode, fwrite()s are atomic (unless the size of data exceeds the filesystem's block size, on some platforms, and as long as the file is on a local filesystem). That is, there is no need to flock() a resource before calling fwrite(); all of the data will be written without interruption.

Note:

If writing twice to the file pointer, then the data will be appended to the end of the file content:

<?php
$fp 
fopen('data.txt''w');
fwrite($fp'1');
fwrite($fp'23');
fclose($fp);// the content of 'data.txt' is now 123 and not 23!
?>

See Also

  • fread() - Binary-safe file read
  • fopen() - Opens file or URL
  • fsockopen() - Open Internet or Unix domain socket connection
  • popen() - Opens process file pointer
  • file_get_contents() - Reads entire file into a string
  • pack() - Pack data into binary string

nate at frickenate dot com

12 years ago

After having problems with fwrite() returning 0 in cases where one would fully expect a return value of false, I took a look at the source code for php's fwrite() itself. The function will only return false if you pass in invalid arguments. Any other error, just as a broken pipe or closed connection, will result in a return value of less than strlen($string), in most cases 0.

Therefore, looping with repeated calls to fwrite() until the sum of number of bytes written equals the strlen() of the full value or expecting false on error will result in an infinite loop if the connection is lost.

This means the example fwrite_stream() code from the docs, as well as all the "helper" functions posted by others in the comments are all broken. You *must* check for a return value of 0 and either abort immediately or track a maximum number of retries.

Below is the example from the docs. This code is BAD, as a broken pipe will result in fwrite() infinitely looping with a return value of 0. Since the loop only breaks if fwrite() returns false or successfully writes all bytes, an infinite loop will occur on failure.

<?php
// BROKEN function - infinite loop when fwrite() returns 0s
function fwrite_stream($fp, $string) {
    for (
$written = 0; $written < strlen($string); $written += $fwrite) {
       
$fwrite = fwrite($fp, substr($string, $written));
        if (
$fwrite === false) {
            return
$written;
        }
    }
    return
$written;
}
?>

niklesh at example dot com

2 years ago

$handles can also be used to output in console like below example

fwrite(STDOUT, "Console Output");

divinity76 at gmail dot com

1 year ago

if you need a function that writes all data, maybe try

<?php/**
     * writes all data or throws
     *
     * @param mixed $handle
     * @param string $data
     * @throws \RuntimeException when fwrite returned <1 but still more data to write
     * @return void
     */
    /*private static*/
function fwrite_all($handle, string $data): void
   
{
       
$original_len = strlen($data);
        if (
$original_len > 0) {
           
$len = $original_len;
           
$written_total = 0;
            for (;;) {
               
$written_now = fwrite($handle, $data);
                if (
$written_now === $len) {
                    return;
                }
                if (
$written_now < 1) {
                    throw new \
RuntimeException("could only write {$written_total}/{$original_len} bytes!");
                }
               
$written_total += $written_now;
               
$data = substr($data, $written_now);
               
$len -= $written_now;
               
// assert($len > 0);
                // assert($len === strlen($data));
           
}
        }
    }

Anonymous

6 years ago

// you want copy dummy file or send dummy file
// it is possible to send a file larger than 4GB and write without FSEEK used is limited by PHP_INT_MAX. it works on a system 32-bit or 64-bit
// fwrite and fread non pas de limite de position du pointeur

<?php

$gfz

filesize_dir("d:\\starwars.mkv"); // 11,5GB
echo 'Z:',$gfz,PHP_EOL;$fz = fopen('d:\\test2.mkv', 'wb');
$fp = fopen('d:\\starwars.mkv', 'rb');
echo
PHP_EOL;
$a = (float) 0;
while((
$l=fread($fp, 65536))) {
   
fwrite($fz, $l);
    if((
$a+=65536)%5) echo "\r", '>', $a, ' : ' , $gfz;
}
fclose($fp);
fclose($fz);// test2.mkv' is 11,5GBfunction filesize_dir($file) {
       
exec('dir ' . $file, $inf);
       
$size_raw = $inf[6];
       
$size_exp = explode(" ",$size_raw);
       
$size_ext = $size_exp[19];
       
$size_int = (float) str_replace(chr(255), '', $size_ext);
        return
$size_int;
    }
?>

Chris Blown

19 years ago

Don't forget to check fwrite returns for errors! Just because you successfully opened a file for write, doesn't always mean you can write to it. 

On some systems this can occur if the filesystem is full, you can still open the file and create the filesystem inode, but the fwrite will fail, resulting in a zero byte file.

dharris dot nospam at removethispart dot drh dot net

14 years ago

Some people say that when writing to a socket not all of the bytes requested to be written may be written. You may have to call fwrite again to write bytes that were not written the first time. (At least this is how the write() system call in UNIX works.)

This is helpful code (warning: not tested with multi-byte character sets)

function fwrite_with_retry($sock, &$data)
{
    $bytes_to_write = strlen($data);
    $bytes_written = 0;

    while ( $bytes_written < $bytes_to_write )
    {
        if ( $bytes_written == 0 ) {
            $rv = fwrite($sock, $data);
        } else {
            $rv = fwrite($sock, substr($data, $bytes_written));
        }

        if ( $rv === false || $rv == 0 )
            return( $bytes_written == 0 ? false : $bytes_written );

        $bytes_written += $rv;
    }

    return $bytes_written;
}

Call this like so:

    $rv = fwrite_with_retry($sock, $request_string);

    if ( ! $rv )
        die("unable to write request_string to socket");
    if ( $rv != strlen($request_string) )
        die("sort write to socket on writing request_string");

chedong at hotmail dot com

19 years ago

the fwrite output striped the slashes if without length argument given, example:

<?php
$str
= "c:\\01.txt";
$out = fopen("out.txt", "w");
fwrite($out, $str);
fclose($out);
?>

the out.txt will be:
c:^@1.txt
the '\\0' without escape will be '\0' ==> 0x00.

the correct one is change fwrite to:
fwrite($out, $str, strlen($str));

synnus at gmail dot com

6 years ago

// you want copy dummy file or send dummy file
// it is possible to send a file larger than 4GB and write without FSEEK used is limited by PHP_INT_MAX. it works on a system 32-bit or 64-bit
// fwrite and fread non pas de limite de position du pointeur

<?php

$gfz

filesize_dir("d:\\starwars.mkv"); // 11,5GB
echo 'Z:',$gfz,PHP_EOL;$fz = fopen('d:\\test2.mkv', 'wb');
$fp = fopen('d:\\starwars.mkv', 'rb');
echo
PHP_EOL;
$a = (float) 0;
while((
$l=fread($fp, 65536))) {
   
fwrite($fz, $l);
    if((
$a+=65536)%5) echo "\r", '>', $a, ' : ' , $gfz;
}
fclose($fp);
fclose($fz);// test2.mkv' is 11,5GBfunction filesize_dir($file) {
       
exec('dir ' . $file, $inf);
       
$size_raw = $inf[6];
       
$size_exp = explode(" ",$size_raw);
       
$size_ext = $size_exp[19];
       
$size_int = (float) str_replace(chr(255), '', $size_ext);
        return
$size_int;
    }
?>

Anonymous

13 years ago

If you write with the pointer in the middle of a file, it overwrites what's there rather than shifting the rest of the file along.

php at biggerthanthebeatles dot com

19 years ago

Hope this helps other newbies.

If you are writing data to a txt file on a windows system and need a line break. use \r\n . This will write hex OD OA.

i.e.
$batch_data= "some data... \r\n";
fwrite($fbatch,$batch_data);

The is the equivalent of opening a txt file in notepad pressing enter and the end of the line and saving it.

synnus at gmail dot com

1 year ago

<?php
/*
Write to offset with positive offset

PHP_INT_MIN / PHP_INT_MAX 32-bit PHP: -2,147,483,648 to +2,147,483,647
PHP_INT_MIN / PHP_INT_MAX 64-bit PHP: -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807

File_writing 32bit 0 -> 4 294 967 295
File_writing 64bit 0 -> 18 446 744 073 709 551 615

$handel =     fopen( myfilname );
$t_f_max      is max file size in BYTE ex: 19998
$offset        is position in offset BYTE ex : 19995
$bin         your binary data you want write

Work in 32bit and 64bit
*/

function File_writing($handel,$t_f_max,$offset,$bin) {
                (
$offset > PHP_INT_MAX) ? fseek($handel,-($t_f_max-$offset),SEEK_END) : fseek($handel,$offset,SEEK_SET);
               
fwrite($handel,$bin);
                return
$offset;
        }
?>

2184364 at gmail dot com

2 years ago

//fwrite writes over, i.e. this example (win) may be misleading:

$file = 'e:/1.txt';

file_put_contents($file, 'hello'.chr(1).'0df6ac'.chr(0));

$fp = fopen($file, 'r+b');

$str = fread($fp, filesize($file));

$str = strtr($str, [chr(0)=>'']);
echo $str.PHP_EOL;//hello0df6ac

fseek($fp, 0);//указатель в начало
fwrite($fp, $str);

fclose($fp);

//add ftruncate ($ fp, 0);
//this will overwrite the file:

file_put_contents($file, 'hello'.chr(1).'0df6ac'.chr(0));

$fp = fopen($file, 'r+b');

$str = fread($fp, filesize($file));

$str = strtr($str, [chr(0)=>'']);
echo $str.PHP_EOL;//hello0df6ac

ftruncate ($ fp, 0);
fseek($fp, 0);//указатель в начало
fwrite($fp, $str);

fclose($fp);

Jon Haynes

11 years ago

Be careful of using reserved Windows filenames in fwrite operations.

<?php
$fh
= fopen('prn.txt', 'w');
fwrite($fh, 'wtf?');
echo
'done' . PHP_EOL;
?>

The above script will hang (tested on Windows 7) before it can echo 'done'.

This is due to another 'feature' of our favourite operating system where filenames like prn.xxx, con.xxx, com1.xxx and aux.xxx (with xxx being any filename extension) are Windows reserved device names. Attempts to create/read/write to these files hangs the interpreter.

Anonymous

8 years ago

Bad example!

The result of fwrite could be either FALSE or 0.

So it should be correctly:

if (false === fwrite($handle, $somecontent)) { ....

chill at cuna dot org

17 years ago

In PHP 4.3.7 fwrite returns 0 rather than false on failure.
The following example will output "SUCCESS: 0 bytes written" for existing file test.txt:

$fp = fopen("test.txt", "rw");
if (($bytes_written = fwrite($fp, "This is a test")) === false) {
  echo "Unable to write to test.txt\n\n";
} else {
  echo "SUCCESS: $bytes_written bytes written\n\n";
}

dominic at varspool dot com

8 years ago

Note that the optional $length argument is expected to be an int, and cannot be skipped by passing null.

That is, `fwrite($handle, $string, null)` is treated as `fwrite($handle, $string, 0)`, and will write zero bytes, not the whole string.

Jake Roberts

19 years ago

Use caution when using:

$content = fread($fh, filesize($fh)) or die "Error Reading";

This will cause an error if the file you are reading is zero length.

Intead use:

if ( false === fread($fh, filesize($fh)) ) die "Error Reading";

Thus it will be successful on reading zero bytes but detect and error returned as FALSE.

james at facepwn dot com

13 years ago

if (is_writable($filename)) {

Could also be

if (is_writable($filename) or die ("Can not write to ".$filename)) {

zaccraven at junk.com

16 years ago

Use this to get a UTF-8 Unicode CSV file that opens properly in Excel:

$tmp = chr(255).chr(254).mb_convert_encoding( $tmp, 'UTF-16LE', 'UTF-8');
$write = fwrite( $filepath, $tmp );

Use a tab character, not comma, to seperate the fields in  the $tmp.

Credit for this goes to someone called Eugene Murai, I found this solution by him after searching for several hours.

oktavianus dot programmer at gmail dot com

13 years ago

this the another sample to use fwrite with create a folder and create the txt file.

<?php
$mypath
="testdir\\subdir\\test";
mkdir($mypath,0777,TRUE);
$filename = $mypath.'\test.txt';
$handle = fopen($filename,"x+");
$somecontent = "Add this to the file Oktavianus";
fwrite($handle,$somecontent);
echo
"Success";
fclose($handle);
?>

please try...
Oktavianus

qrworld.net

7 years ago

Here you have a function found on the website http://softontherocks.blogspot.com/2014/11/funcion-para-escribir-en-un-fichero-log.html with an example of how to make a log file.

The function is this:

function writeLog($data) {
list($usec, $sec) = explode(' ', microtime());
$datetime = strftime("%Y%m%d %H:%M:%S",time());
$msg = "$datetime'". sprintf("%06s",intval($usec*1000000)).": $data";
$save_path = 'foo.txt';
$fp = @fopen($save_path, 'a'); // open or create the file for writing and append info
fputs($fp, "$msg\n"); // write the data in the opened file
fclose($fp); // close the file
}

Will at EnigmaChannel dot com

17 years ago

Using fwrite to write to a file in your include folder...

PHP does not recognise the permissions setting for the file until you restart the server... this script works fine. (still have to create the blank text file first though...it is not created automatically) On OS X Server..
Using the 1 in fopen tells php to look for the file in your include folder. Change your include folder by altering include_path in php.ini
On OS X Server, php.ini is in private/etc/php.ini.default
copy the file and call it php.ini

the default include path is usr/lib/php
(All these folders are hidden - use TinkerTool to reveal them)

<?php
$file
= fopen('textfile.txt', 'a', 1);
$text="\n Your text to write \n ".date('d')."-".date('m')."-".date('Y')."\n\n";
fwrite($file, $text);
fclose($file);
?>

kzevian at cybercable dot net dot mx

17 years ago

I needed to append, but I needed to write on the file's beginning, and after some hours of effort this worked for me:

$file = "file.txt";
if (!file_exists("file.txt")) touch("file.txt");
$fh = fopen("file.txt", "r");
$fcontent = fread($fh, filesize("file.txt"));

$towrite = "$newcontent $fcontent";

$fh22 = fopen('file.txt', 'w+');
fwrite($fh2, $towrite);
fclose($fh);
fclose($fh2);

sheyh

17 years ago

if you want to create quickly and without fopen use system, exec

system('echo "blahblah" > /path/file');

chad 0x40 herballure 0x2e com

15 years ago

Remember to check the return value of fwrite(). In particular, writing into a socket can return fewer bytes than requested, and you'll have to try again with the remainder of your data.

james at nicolson dot biz

17 years ago

I could'nt quite get MKP Dev hit counter to work.... this is how I modified it
<?
function hitcount()
{
$file = "counter.txt";
if ( !file_exists($file)){
        touch ($file);
        $handle = fopen ($file, 'r+'); // Let's open for read and write
        $count = 0;

}
else{
        $handle = fopen ($file, 'r+'); // Let's open for read and write
        $count = fread ($handle, filesize ($file));
        settype ($count,"integer");
}
rewind ($handle); // Go back to the beginning
/*
* Note that we don't have problems with 9 being fewer characters than
  * 10 because we are always incrementing, so we will always write at
   * least as many characters as we read
    **/
fwrite ($handle, ++$count); // Don't forget to increment the counter
fclose ($handle); // Done

return $count;
}     
?>

Andi

19 years ago

[Ed. Note:
The runtime configuration setting auto_detect_line_endings should solve this problem when set to On.]

I figured out problems when writing to a file using \r as linebreak, after that file() wasn't able to read the data from that file.
Using \n solved the problem.

bluevd at gmail dot com

17 years ago

Watch out for mistakes in writting a simple code for a hit counter:
<?php
$cont
=fopen('cont.txt','r');
$incr=fgets($cont);
//echo $incr;
$incr++;
fclose($cont);
$cont=fopen('cont.txt','a');
fwrite($cont,$incr);
fclose($cont);
?>

Why? notice the second fopen -> $cont=fopen('cont.txt','a');
it opens the file in writting mode (a). And when it ads the incremented
value ( $incr ) it ads it ALONG the old value... so opening the counter
page about 5 times will make your hits number look like this
012131214121312151.21312141213E+ .... you get the piont.
nasty, isn't it? REMEMBER to open the file with the 'w' mode (truncate
the file to 0). Doing this will clear the file content and it will make sure that
your counter works nice. This is the final code

<?php
$cont
=fopen('cont.txt','r');
$incr=fgets($cont);
//echo $incr;
$incr++;
fclose($cont);
$cont=fopen('cont.txt','w');
fwrite($cont,$incr);
fclose($cont);
?>

Notice that this work fine =)
XU (alias Iscu Andrei)

MKP Dev

17 years ago

bluevd at gmail dot com mentioned a hit counter. In his/her implementation, the file is first opened, read, closed, then opened +truncated, then written, and closed again. An alternative to this is:
<?php
$file
= 'counter.txt or whatever';
$handle = fopen ($file, 'r+'); // Let's open for read and write
$count = int (fread ($handle, filesize ($file)));
// We don't want to think it's a string and try appending
echo "Number of hits $count";
rewind ($handle); // Go back to the beginning
/*
* Note that we don't have problems with 9 being fewer characters than
* 10 because we are always incrementing, so we will always write at
* least as many characters as we read
**/
fwrite ($handle, ++$count); // Don't forget to increment the counter
fclose ($handle); // Done
?>

David Spector

6 years ago

This may save you time: note that neither "binary-safe file write" nor the use of b mode in fopen mean that fwrite can write binary. It can only write strings (or a single character). For example,  attempting to write the byte 0x1 using fwrite results in writing the byte value 0x31.

If you wish to write binary values (bits, bytes, integers, etc.), use a statement like fprintf($Res, "%c", 0x1); . This statement will write a byte to the current offset in the file without converting it to a character (in this case, it will write 0x1).

cutmaster at fearlesss dot com

15 years ago

For those who, like me, lost a lot of minutes (hours) to understand why fwrite doesn't create a real utf-8 file, here's the explanation I've found :

I tried to do something like this :
<?php
$myString
= utf8_encode("Test with accents éèàç");
$fh=fopen('test.xml',"w");
fwrite($fh,$myString);
fclose($fh);
?>

For a mysterious reason, the resulted file shows the accent without the utf-8 conversion.

I tried the binary, mode, etc. etc. And finally I've found it :
It seems that fwrite NEEDS to have the utf8_encode function INSIDE its parameters like this, to understand it must create a non-text only file :
<?php
$myString
= "Test with accents éèàç";
$fh=fopen('test.xml',"w");
fwrite($fh,utf8_encode($myString));
fclose($fh);
?>
Hope this will help