add php extension function: fastcommon_file_put_contents

pull/37/head
yuqing 2017-02-15 15:38:47 +08:00
parent c78f6b17ee
commit df428e6a2d
9 changed files with 382 additions and 14 deletions

View File

@ -1,6 +1,7 @@
Version 1.35 2017-02-09
Version 1.35 2017-02-15
* logger judge log_level in function log_it_ex and log_it_ex1
* add php extension function: fastcommon_file_put_contents
Version 1.34 2017-02-06
* ini_file_reader: LOCAL_IP support CIDR addresses

View File

@ -1,5 +1,7 @@
#include "php7_ext_wrapper.h"
#include "ext/standard/info.h"
#include "ext/standard/file.h"
#include "ext/standard/flock_compat.h"
#include <zend_extensions.h>
#include <zend_exceptions.h>
#include <string.h>
@ -36,11 +38,25 @@ typedef struct {
int alloc;
int count;
LogContext *contexts;
} LoggerArray;
} PHPLoggerArray;
static LoggerArray logger_array = {0, 0, NULL};
typedef struct {
char *filename;
int fd;
} PHPFileContext;
typedef struct {
int alloc;
int count;
PHPFileContext *contexts;
} PHPFileArray;
static PHPLoggerArray logger_array = {0, 0, NULL};
static PHPFileArray file_array = {0, 0, NULL};
static zval php_error_log;
static zval php_file_put_contents;
static zval *error_log_func = NULL;
static zval *file_put_contents_func = NULL;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3)
const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 };
@ -69,6 +85,7 @@ const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, N
ZEND_FE(fastcommon_get_cpu_count, NULL)
ZEND_FE(fastcommon_get_sysinfo, NULL)
ZEND_FE(fastcommon_error_log, NULL)
ZEND_FE(fastcommon_file_put_contents, NULL)
{NULL, NULL, NULL} /* Must be the last line */
};
@ -147,11 +164,23 @@ PHP_MINIT_FUNCTION(fastcommon)
PHP_MSHUTDOWN_FUNCTION(fastcommon)
{
if (logger_array.count > 0) {
LogContext *ctx;
LogContext *end;
end = logger_array.contexts + logger_array.count;
for (ctx=logger_array.contexts; ctx<end; ctx++) {
log_destroy_ex(ctx);
LogContext *lctx;
LogContext *lend;
lend = logger_array.contexts + logger_array.count;
for (lctx=logger_array.contexts; lctx<lend; lctx++) {
log_destroy_ex(lctx);
}
}
if (file_array.count > 0) {
PHPFileContext *fctx;
PHPFileContext *fend;
fend = file_array.contexts + file_array.count;
for (fctx=file_array.contexts; fctx<fend; fctx++) {
if (fctx->fd >= 0) {
close(fctx->fd);
fctx->fd = -1;
}
}
}
@ -1042,6 +1071,214 @@ ZEND_FUNCTION(fastcommon_error_log)
Z_STRVAL_P(error_log_func));
RETURN_BOOL(false);
}
RETURN_BOOL(true);
}
}
static PHPFileContext *fetch_file_context(const char *filename)
{
PHPFileContext *ctx;
PHPFileContext *end;
if (file_array.count == 0) {
return NULL;
}
end = file_array.contexts + file_array.count;
for (ctx=file_array.contexts; ctx<end; ctx++) {
if (strcmp(ctx->filename, filename) == 0) {
return ctx;
}
}
return NULL;
}
static int fc_open_file(PHPFileContext *ctx)
{
if ((ctx->fd = open(ctx->filename, O_WRONLY |
O_CREAT | O_APPEND, 0644)) < 0)
{
logError("file: "__FILE__", line: %d, "
"open file \"%s\" to write fail, "
"errno: %d, error info: %s", __LINE__,
ctx->filename, errno, strerror(errno));
return errno != 0 ? errno : EACCES;
}
return 0;
}
static PHPFileContext *alloc_file_context(const char *filename)
{
PHPFileContext *ctx;
if (file_array.alloc <= file_array.count) {
int alloc;
int bytes;
PHPFileContext *contexts;
alloc = file_array.alloc == 0 ? 4 : 2 * file_array.alloc;
bytes = sizeof(PHPFileContext) * alloc;
contexts = (PHPFileContext *)malloc(bytes);
if (contexts == NULL) {
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, bytes);
return NULL;
}
if (file_array.count > 0) {
memcpy(contexts, file_array.contexts,
sizeof(PHPFileContext) * file_array.count);
free(file_array.contexts);
}
file_array.contexts = contexts;
file_array.alloc = alloc;
}
ctx = file_array.contexts + file_array.count;
ctx->filename = strdup(filename);
if (ctx->filename == NULL) {
logError("file: "__FILE__", line: %d, "
"strdup %d bytes fail",
__LINE__, (int)strlen(filename));
return NULL;
}
file_array.count++;
if (fc_open_file(ctx) != 0) {
return NULL;
}
return ctx;
}
static PHPFileContext *fc_get_file_context(const char *filename)
{
PHPFileContext *ctx;
if ((ctx=fetch_file_context(filename)) != NULL) {
if (ctx->fd < 0) {
if (fc_open_file(ctx) != 0) {
return NULL;
}
}
return ctx;
}
return alloc_file_context(filename);
}
static int fc_file_put_contents(const char *filename,
const char *data, const int data_len, const long flags)
{
PHPFileContext *ctx;
int bytes;
ctx = fc_get_file_context(filename);
if (ctx == NULL) {
return -1;
}
if ((flags & PHP_LOCK_EX) != 0) {
bytes = fc_lock_write(ctx->fd, data, data_len);
} else {
bytes = fc_safe_write(ctx->fd, data, data_len);
}
if (bytes < 0) {
logError("file: "__FILE__", line: %d, "
"write to file %s fail, errno: %d, error info: %s",
__LINE__, filename, errno, strerror(errno));
close(ctx->fd);
ctx->fd = -1;
}
return bytes;
}
/*
int fastcommon_file_put_contents(string $filename , mixed $data
[, int $flags = 0, resource $context])
return the number of bytes that were written to the file, or FALSE on failure
*/
ZEND_FUNCTION(fastcommon_file_put_contents)
{
int argc;
long flags;
zval *zdata;
char *filename;
zval *zcontext;
zend_size_t filename_len;
argc = ZEND_NUM_ARGS();
if (argc < 2) {
logError("file: "__FILE__", line: %d, "
"fastcommon_file_put_contents parameters count: %d is invalid",
__LINE__, argc);
RETURN_BOOL(false);
}
flags = 0;
zcontext = NULL;
if (zend_parse_parameters(argc TSRMLS_CC, "sz|lz",
&filename, &filename_len, &zdata,
&flags, &zcontext) == FAILURE)
{
logError("file: "__FILE__", line: %d, "
"zend_parse_parameters fail!", __LINE__);
RETURN_BOOL(false);
}
if ((flags == PHP_FILE_APPEND || flags == (PHP_FILE_APPEND | PHP_LOCK_EX))
&& (Z_TYPE_P(zdata) == IS_STRING) && (zcontext == NULL))
{
int bytes;
if ((bytes=fc_file_put_contents(filename, Z_STRVAL_P(zdata),
Z_STRLEN_P(zdata), flags)) >= 0)
{
RETURN_LONG(bytes);
} else {
RETURN_BOOL(false);
}
}
{
int result;
zval *args[4];
zval zflags;
zval zfilename;
#if PHP_MAJOR_VERSION >= 7
zend_string *sz_filename = NULL;
bool use_heap_filename = false;
#endif
if (file_put_contents_func == NULL) {
file_put_contents_func = &php_file_put_contents;
INIT_ZVAL(php_file_put_contents);
ZEND_ZVAL_STRINGL(&php_file_put_contents, "file_put_contents",
sizeof("file_put_contents") - 1, 1);
}
FASTCOMMON_INIT_ZSTRING(zfilename, filename, filename_len);
INIT_ZVAL(zflags);
ZVAL_LONG(&zflags, flags);
if (zcontext == NULL) {
zval ctx;
zcontext = &ctx;
INIT_ZVAL(*zcontext);
ZVAL_NULL(zcontext);
}
args[0] = &zfilename;
args[1] = zdata;
args[1] = &zflags;
args[3] = zcontext;
result = zend_call_user_function_wrapper(EG(function_table), NULL,
file_put_contents_func, return_value, 4, args TSRMLS_CC);
#if PHP_MAJOR_VERSION >= 7
FASTCOMMON_ALLOCA_FREE(filename);
#endif
if (result == FAILURE) {
logError("file: "__FILE__", line: %d, "
"call function: %s fail", __LINE__,
Z_STRVAL_P(file_put_contents_func));
RETURN_BOOL(false);
}
}
}

View File

@ -37,6 +37,7 @@ ZEND_FUNCTION(fastcommon_get_cpu_count);
ZEND_FUNCTION(fastcommon_get_sysinfo);
ZEND_FUNCTION(fastcommon_error_log);
ZEND_FUNCTION(fastcommon_file_put_contents);
#ifdef __cplusplus
}

View File

@ -3,7 +3,7 @@
function test_fastcommon_error_log()
{
$start = microtime(true);
for ($i=0; $i<10240; $i++)
for ($i=0; $i<102400; $i++)
{
fastcommon_error_log("this is a test\n", 3, "/tmp/test.log");
fastcommon_error_log("this is a test11\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
@ -24,7 +24,7 @@ function test_fastcommon_error_log()
function test_error_log()
{
$start = microtime(true);
for ($i=0; $i<10240; $i++)
for ($i=0; $i<102400; $i++)
{
error_log("this is a test\n", 3, "/tmp/test.log");
error_log("this is a test11\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
@ -43,5 +43,8 @@ function test_error_log()
}
test_fastcommon_error_log();
echo "sleep ...\n";
sleep(2);
echo "sleep done.\n";
test_error_log();

View File

@ -0,0 +1,50 @@
<?php
function test_fastcommon_file_put_contents()
{
$start = microtime(true);
for ($i=0; $i<102400; $i++)
{
fastcommon_file_put_contents("/tmp/test.log", "this is a test\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test1.log", "this is a test11\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test1.log", "this is a test12\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test2.log", "this is a test21\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test2.log", "this is a test22\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test2.log", "this is a test23\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test3.log", "this is a test31\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test3.log", "this is a test32\n", FILE_APPEND);
fastcommon_file_put_contents("/tmp/test3.log", "this is a test33\n", FILE_APPEND);
}
$end = microtime(true);
$timeUsed = round($end - $start, 3);
echo "fastcommon_file_put_contents time used: $timeUsed\n";
}
function test_file_put_contents()
{
$start = microtime(true);
for ($i=0; $i<102400; $i++)
{
file_put_contents("/tmp/test.log", "this is a test\n", FILE_APPEND);
file_put_contents("/tmp/test1.log", "this is a test11\n", FILE_APPEND);
file_put_contents("/tmp/test1.log", "this is a test12\n", FILE_APPEND);
file_put_contents("/tmp/test2.log", "this is a test21\n", FILE_APPEND);
file_put_contents("/tmp/test2.log", "this is a test22\n", FILE_APPEND);
file_put_contents("/tmp/test2.log", "this is a test23\n", FILE_APPEND);
file_put_contents("/tmp/test3.log", "this is a test31\n", FILE_APPEND);
file_put_contents("/tmp/test3.log", "this is a test32\n", FILE_APPEND);
file_put_contents("/tmp/test3.log", "this is a test33\n", FILE_APPEND);
}
$end = microtime(true);
$timeUsed = round($end - $start, 3);
echo "file_put_contents time used: $timeUsed\n";
}
test_file_put_contents();
echo "sleep ...\n";
sleep(2);
echo "sleep done.\n";
test_fastcommon_file_put_contents();

View File

@ -15,7 +15,7 @@
#include "io_opt.h"
int mkdir_by_cascading(const char *path,mode_t mode)
int mkdir_by_cascading(const char *path, mode_t mode)
{
int length,pointer_postion = 0;
char *postion;

View File

@ -25,7 +25,7 @@
* -3 : malloc memory to subfolder is error
* -4 : create dir is error;
*/
int mkdir_by_cascading(const char *path,mode_t mode);
int mkdir_by_cascading(const char *path, mode_t mode);
/*
* check the first parameter is the dir

View File

@ -2446,3 +2446,62 @@ bool isTrailingSpacesLine(const char *tail, const char *end)
}
return (p == end || *p == '\n');
}
ssize_t fc_safe_write(int fd, const char *buf, const size_t nbyte)
{
int n;
int remain;
const char *p;
n = write(fd, buf, nbyte);
if (n < 0)
{
if (errno != EINTR)
{
return -1;
}
n = 0;
}
else if (n == nbyte)
{
return nbyte;
}
p = buf + n;
remain = nbyte - n;
while (remain > 0)
{
n = write(fd, p, remain);
if (n < 0)
{
int written;
if (errno == EINTR)
{
continue;
}
written = nbyte - remain;
return written > 0 ? written : -1;
}
p += n;
remain -= n;
}
return nbyte;
}
ssize_t fc_lock_write(int fd, const char *buf, const size_t nbyte)
{
int lock_result;
int result;
lock_result = file_write_lock(fd);
result = fc_safe_write(fd, buf, nbyte);
if (lock_result == 0)
{
file_unlock(fd);
}
return result;
}

View File

@ -624,9 +624,26 @@ bool isLeadingSpacesLine(const char *content, const char *current);
*/
bool isTrailingSpacesLine(const char *tail, const char *end);
/** write to file
* parameters:
* fd: the fd to write
* buf: the buffer
* nbyte: the buffer length
* return: written bytes for success, -1 when fail
*/
ssize_t fc_safe_write(int fd, const char *buf, const size_t nbyte);
/** lock and write to file
* parameters:
* fd: the fd to write
* buf: the buffer
* nbyte: the buffer length
* return: written bytes for success, -1 when fail
*/
ssize_t fc_lock_write(int fd, const char *buf, const size_t nbyte);
#ifdef __cplusplus
}
#endif
#endif