kphp icon indicating copy to clipboard operation
kphp copied to clipboard

Add some missing, yet useful PHP functions

Open quasilyte opened this issue 3 years ago • 1 comments

  • [ ] getenv
  • [ ] shell-exec related functions like exec, system, shell_exec and maybe popen (+ pclose)
  • [ ] some shell-related utilities like escapeshellarg and escapeshellcmd
  • [ ] missing mb functions mb_convert_encoding, mb_internal_encoding, etc
  • [ ] missing openssl funcs like openssl_error_string and openssl_pkey_free
  • [ ] quoted_printable_encode
  • [ ] random_bytes
  • [ ] sys_get_temp_dir

quasilyte avatar Aug 06 '22 16:08 quasilyte

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;
		}

comm644 avatar Aug 06 '22 16:08 comm644