kphp
kphp copied to clipboard
Add some missing, yet useful PHP functions
- [ ]
getenv - [ ] shell-exec related functions like
exec,system,shell_execand maybepopen(+pclose) - [ ] some shell-related utilities like
escapeshellargandescapeshellcmd - [ ] missing mb functions
mb_convert_encoding,mb_internal_encoding, etc - [ ] missing openssl funcs like
openssl_error_stringandopenssl_pkey_free - [ ]
quoted_printable_encode - [ ]
random_bytes - [ ]
sys_get_temp_dir
popen()/shell_exec() quick hack implementation. Please review it and integrate as you wish.
Attention! pclose() fires exception, need to discover why.
Core idea: add protocol 'popen://' and handle protocol methods with calling system function popen/pclose
--- a/runtime/files.cpp
+++ b/runtime/files.cpp
@@ -411,6 +411,11 @@ Optional<string> f$realpath(const string &path) {
}
static Optional<string> full_realpath(const string &path) { // realpath resolving only dirname to work with unexisted files
+
+ if (!strncmp(path.c_str(), "popen://", 8)) {
+ return path;
+ }
+
static char full_realpath_cache_storage[sizeof(array<string>)];
static array<string> *full_realpath_cache = reinterpret_cast <array<string> *> (full_realpath_cache_storage);
static long long full_realpath_last_query_num = -1;
@@ -928,3 +933,4 @@ void free_files_lib() {
dl::leave_critical_section();
}
+#include "files_popen.cpp"
--- a/runtime/files.h
+++ b/runtime/files.h
@@ -72,3 +72,7 @@ Optional<string> file_file_get_contents(const string &name);
void global_init_files_lib();
void free_files_lib();
+
+
+
+#include "files_popen.h"
--- a/builtin-functions/_functions.txt
+++ b/builtin-functions/_functions.txt
@@ -1388,3 +1388,11 @@ class CompileTimeLocation {
static public function calculate(?CompileTimeLocation $passed) ::: CompileTimeLocation;
}
+
+
+//2022-04-19 av
+define('PATH_SEPARATOR', '/');
+
+function popen ($command ::: string, $mode ::: string) ::: mixed;
+function pclose ($stream ::: mixed ) ::: bool;
+
--- a/runtime/interface.cpp
+++ b/runtime/interface.cpp
@@ -2246,6 +2246,7 @@ void global_init_runtime_libs() {
global_init_profiler();
global_init_instance_cache_lib();
global_init_files_lib();
+ global_init_popen_lib();
global_init_interface_lib();
global_init_openssl_lib();
global_init_regexp_lib();
--- a/runtime/storage.h
+++ b/runtime/storage.h
@@ -195,3 +195,5 @@ X Storage::load_as() noexcept {
tag = 0;
return (loader<X>::get_function(tag_save))(storage_);
}
+
+#include "files_popen.h"
--- a/runtime/streams.cpp
+++ b/runtime/streams.cpp
@@ -784,3 +784,5 @@ void init_streams_lib() {
void free_streams_lib() {
reset_streams_global_vars();
}
+
+
files_popen.h
#pragma once
#include "runtime/kphp_core.h"
using Stream =mixed;
//2022-04-19 av
Stream f$popen(const string &stream, const string &mode);
bool f$pclose(Stream &stream);
void global_init_popen_lib();
void free_popen_lib();
files_popen.cpp
#include "streams.h"
#include "files_popen.h"
#include <stdio.h>
#include "runtime/string_functions.h"//php_buf, TODO
const string popen_wrapper_name("popen://", 8);
//2022-04-19 av
Stream f$popen(const string &command, const string &mode)
{
if (dl::query_num != opened_files_last_query_num) {
new(opened_files_storage) array<FILE *>();
opened_files_last_query_num = dl::query_num;
}
string fullname = popen_wrapper_name;
fullname.append( command );
printf("open: %s\n", fullname.c_str());
dl::enter_critical_section();//NOT OK: opened_files
FILE *file = popen(command.c_str(), mode.c_str());
if (file == nullptr) {
dl::leave_critical_section();
return false;
}
opened_files->set_value(fullname, file);
dl::leave_critical_section();
return fullname;
}
bool f$pclose(const Stream &stream) {
string filename = stream.to_string();
if (dl::query_num == opened_files_last_query_num && opened_files->has_key(filename)) {
dl::enter_critical_section();//NOT OK: opened_files
int result = pclose(opened_files->get_value(filename));
opened_files->unset(filename);
dl::leave_critical_section();
return (result == 0);
}
return false;
}
void global_init_popen_lib() {
static stream_functions file_stream_functions;
file_stream_functions.name = string("popen", 5);
file_stream_functions.fopen = f$popen;
file_stream_functions.fwrite = file_fwrite;
file_stream_functions.fseek = nullptr;;
file_stream_functions.ftell = nullptr;
file_stream_functions.fread = file_fread;
file_stream_functions.fgetc = file_fgetc;
file_stream_functions.fgets = file_fgets;
file_stream_functions.fpassthru = file_fpassthru;
file_stream_functions.fflush = file_fflush;
file_stream_functions.feof = file_feof;
file_stream_functions.fclose = f$pclose;
file_stream_functions.file_get_contents = file_file_get_contents;
file_stream_functions.file_put_contents = file_file_put_contents;
file_stream_functions.stream_socket_client = nullptr;
file_stream_functions.context_set_option = nullptr;
file_stream_functions.stream_set_option = nullptr;
file_stream_functions.get_fd = nullptr;
register_stream_functions(&file_stream_functions, false);
}
void free_popen_lib() {
dl::enter_critical_section();//OK
if (dl::query_num == opened_files_last_query_num) {
const array<FILE *> *const_opened_files = opened_files;
for (array<FILE *>::const_iterator p = const_opened_files->begin(); p != const_opened_files->end(); ++p) {
fclose(p.get_value());
}
opened_files_last_query_num--;
}
if (opened_fd != -1) {
close_safe(opened_fd);
}
opened_fd = -1;
dl::leave_critical_section();
}
shell_exec() implementation (php)
function shell_exec(string $cmd):string
{
$fd = popen($cmd, "r");
$result = "";
/** @noinspection PhpAssignmentInConditionInspection */
while (($buffer = fread($fd, 2048))) {
$result .= $buffer;
}
//pclose($fd);
fclose($fd);
return $result;
}