@@ -112,6 +112,8 @@ php_file_globals file_globals;
112112
113113#include "file_arginfo.h"
114114
115+ #include <sys/uio.h> // for writev()
116+
115117/* }}} */
116118
117119#define PHP_STREAM_FROM_ZVAL (stream , arg ) \
@@ -452,6 +454,17 @@ PHP_FUNCTION(file_get_contents)
452454}
453455/* }}} */
454456
457+ ZEND_ATTRIBUTE_PURE
458+ static bool is_string_array (HashTable * ht )
459+ {
460+ zval * tmp ;
461+ ZEND_HASH_FOREACH_VAL (ht , tmp ) {
462+ if (Z_TYPE_P (tmp ) != IS_STRING )
463+ return false;
464+ } ZEND_HASH_FOREACH_END ();
465+ return true;
466+ }
467+
455468/* {{{ Write/Create a file with contents data and return the number of bytes written */
456469PHP_FUNCTION (file_put_contents )
457470{
@@ -541,6 +554,41 @@ PHP_FUNCTION(file_put_contents)
541554 break ;
542555
543556 case IS_ARRAY :
557+ 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 ))) {
558+ /* if we're writing a string array to
559+ a regular file, use one writev()
560+ system call instead of many
561+ write() calls */
562+
563+ int fd ;
564+ if (php_stream_cast (stream , PHP_STREAM_AS_FD , (void * )& fd , 0 ) == SUCCESS ) {
565+ struct iovec v [IOV_MAX ];
566+ size_t n = 0 , total = 0 ;
567+
568+ zval * tmp ;
569+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (data ), tmp ) {
570+ const size_t length = Z_STRLEN_P (tmp );
571+ if (length > 0 ) {
572+ total += length ;
573+ v [n ].iov_len = length ;
574+ v [n ].iov_base = Z_STRVAL_P (tmp );
575+ ++ n ;
576+ }
577+ } ZEND_HASH_FOREACH_END ();
578+
579+ if (n == 0 )
580+ break ;
581+
582+ numbytes = writev (fd , v , n );
583+ if (numbytes != -1 && (size_t )numbytes != total ) {
584+ php_error_docref (NULL , E_WARNING , "Failed to write %zu bytes to %s" , total , filename );
585+ numbytes = -1 ;
586+ }
587+
588+ break ;
589+ }
590+ }
591+
544592 if (zend_hash_num_elements (Z_ARRVAL_P (data ))) {
545593 ssize_t bytes_written ;
546594 zval * tmp ;
0 commit comments