fluent/fluent-logger-php — Issue #12: more specifically fwrite error handling for Fluent\Logger\FluentLogger::postImpl.
Author: chobie
Created: 2012-02-25 22:59:58+00:00
State: open

- fwrite returns:

````
FALSE => invalid parameters
integer => number of bytes written
````

why i misunderstood fwrite return null string. o.O

- fwrite outputs errors:

only 1. we should catch this as PHP is able to change errors to exception.

````
php_sockop_write:
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "send of %ld bytes failed with errno=%ld %s",(long)count, err, estr);
````
-

trace

````
fwrite -> php_stream_write -> _php_stream_write_buffer -> php_sockop_write

````

following lines are excerpted codes from PHP5_3.

````
/* {{{ proto int fwrite(resource fp, string str [, int length])
Binary-safe file write */
PHPAPI PHP_FUNCTION(fwrite)
{
zval *arg1;
char *arg2;
int arg2len;
int ret;
int num_bytes;
long arg3 = 0;
char *buffer = NULL;
php_stream *stream;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &arg1, &arg2, &arg2len, &arg3) == FAILURE) {
RETURN_FALSE;
}

if (ZEND_NUM_ARGS() == 2) {
num_bytes = arg2len;
} else {
num_bytes = MAX(0, MIN((int)arg3, arg2len));
}

if (!num_bytes) {
RETURN_LONG(0);
}

PHP_STREAM_TO_ZVAL(stream, &arg1);

if (PG(magic_quotes_runtime)) {
buffer = estrndup(arg2, num_bytes);
php_stripslashes(buffer, &num_bytes TSRMLS_CC);
}

ret = php_stream_write(stream, buffer ? buffer : arg2, num_bytes);
if (buffer) {
efree(buffer);
}

RETURN_LONG(ret);
}
/* }}} */

PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
{
if (buf == NULL || count == 0 || stream->ops->write == NULL) {
return 0;
}

if (stream->writefilters.head) {
return _php_stream_write_filtered(stream, buf, count, PSFS_FLAG_NORMAL TSRMLS_CC);
} else {
return _php_stream_write_buffer(stream, buf, count TSRMLS_CC);
}
}

/* Writes a buffer directly to a stream, using multiple of the chunk size */
static size_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
{
size_t didwrite = 0, towrite, justwrote;

/* if we have a seekable stream we need to ensure that data is written at the
* current stream->position. This means invalidating the read buffer and then
* performing a low-level seek */
if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && stream->readpos != stream->writepos) {
stream->readpos = stream->writepos = 0;

stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC);
}

while (count > 0) {
towrite = count;
if (towrite > stream->chunk_size)
towrite = stream->chunk_size;

justwrote = stream->ops->write(stream, buf, towrite TSRMLS_CC);

/* convert justwrote to an integer, since normally it is unsigned */
if ((int)justwrote > 0) {
buf += justwrote;
count -= justwrote;
didwrite += justwrote;

/* Only screw with the buffer if we can seek, otherwise we lose data
* buffered from fifos and sockets */
if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
stream->position += justwrote;
}
} else {
break;
}
}
return didwrite;

}

main/stream/xp_socket.c

php_sockop_write
/* {{{ Generic socket stream operations */
static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
{
php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
int didwrite;
struct timeval *ptimeout;

if (sock->socket == -1) {
return 0;
}

if (sock->timeout.tv_sec == -1)
ptimeout = NULL;
else
ptimeout = &sock->timeout;

retry:
didwrite = send(sock->socket, buf, count, (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);

if (didwrite <= 0) {
long err = php_socket_errno();
char *estr;

if (sock->is_blocked && err == EWOULDBLOCK) {
int retval;

sock->timeout_event = 0;

do {
retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);

if (retval == 0) {
sock->timeout_event = 1;
break;
}

if (retval > 0) {
/* writable now; retry */
goto retry;
}

err = php_socket_errno();
} while (err == EINTR);
}
estr = php_socket_strerror(err, NULL, 0);
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "send of %ld bytes failed with errno=%ld %s",
(long)count, err, estr);
efree(estr);
}

if (didwrite > 0) {
php_stream_notify_progress_increment(stream->context, didwrite, 0);
}

if (didwrite < 0) {
didwrite = 0;
}

return didwrite;
}

#define php_stream_notify_progress_increment(context, dsofar, dmax) do { if ((context) && (context)->notifier && (context)->notifier->mask & PHP_STREAM_NOTIFIER_PROGRESS) { \
(context)->notifier->progress += (dsofar); \
(context)->notifier->progress_max += (dmax); \
php_stream_notify_progress((context), (context)->notifier->progress, (context)->notifier->progress_max); } } while (0)

#define php_stream_notify_progress(context, bsofar, bmax) do { if ((context) && (context)->notifier) { \
php_stream_notification_notify((context), PHP_STREAM_NOTIFY_PROGRESS, PHP_STREAM_NOTIFY_SEVERITY_INFO, \
NULL, 0, (bsofar), (bmax), NULL TSRMLS_CC); } } while(0)

PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
{
if (context && context->notifier)
context->notifier->func(context, notifycode, severity, xmsg, xcode, bytes_sofar, bytes_max, ptr TSRMLS_CC);
}
````