@@ -100,6 +100,8 @@ php_file_globals file_globals;
100100
101101#include "file_arginfo.h"
102102
103+ #include <sys/uio.h> // for writev()
104+
103105/* }}} */
104106
105107#define PHP_STREAM_FROM_ZVAL (stream , arg ) \
@@ -440,6 +442,17 @@ PHP_FUNCTION(file_get_contents)
440442}
441443/* }}} */
442444
445+ ZEND_ATTRIBUTE_PURE
446+ static bool is_string_array (HashTable * ht )
447+ {
448+ zval * tmp ;
449+ ZEND_HASH_FOREACH_VAL (ht , tmp ) {
450+ if (Z_TYPE_P (tmp ) != IS_STRING )
451+ return false;
452+ } ZEND_HASH_FOREACH_END ();
453+ return true;
454+ }
455+
443456/* {{{ Write/Create a file with contents data and return the number of bytes written */
444457PHP_FUNCTION (file_put_contents )
445458{
@@ -529,6 +542,41 @@ PHP_FUNCTION(file_put_contents)
529542 break ;
530543
531544 case IS_ARRAY :
545+ if (php_stream_is (stream , PHP_STREAM_IS_STDIO ) && zend_hash_num_elements (Z_ARRVAL_P (data )) <= IOV_MAX && is_string_array (Z_ARRVAL_P (data ))) {
546+ /* if we're writing a string array to
547+ a regular file, use one writev()
548+ system call instead of many
549+ write() calls */
550+
551+ int fd ;
552+ if (php_stream_cast (stream , PHP_STREAM_AS_FD , (void * )& fd , 0 ) == SUCCESS ) {
553+ struct iovec v [IOV_MAX ];
554+ size_t n = 0 , total = 0 ;
555+
556+ zval * tmp ;
557+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (data ), tmp ) {
558+ const size_t length = Z_STRLEN_P (tmp );
559+ if (length > 0 ) {
560+ total += length ;
561+ v [n ].iov_len = length ;
562+ v [n ].iov_base = Z_STRVAL_P (tmp );
563+ ++ n ;
564+ }
565+ } ZEND_HASH_FOREACH_END ();
566+
567+ if (n == 0 )
568+ break ;
569+
570+ numbytes = writev (fd , v , n );
571+ if (numbytes != -1 && (size_t )numbytes != total ) {
572+ php_error_docref (NULL , E_WARNING , "Failed to write %zu bytes to %s" , total , filename );
573+ numbytes = -1 ;
574+ }
575+
576+ break ;
577+ }
578+ }
579+
532580 if (zend_hash_num_elements (Z_ARRVAL_P (data ))) {
533581 ssize_t bytes_written ;
534582 zval * tmp ;
0 commit comments