how to translate zend_parse_parameters from c++ to pascal? - php

I need parse PHP extension parameters using lazarus/freepascal, but I do not know how to define the C function zend_parse_parameters in lazarus as:
int zend_parse_parameters ( int num_args TSRMLS_DC, char* type_spec, ... )
Can anybody help me?

Probably something like
uses ctypes;
function zend_parse_parameters(num_args:cint;type_spec:pchar):cint;cdecl; varargs;
but I don't know what to do with the macro (I assume it is merely a helper macro that links together the variable part and the num_args).

here is my test code of lazarus under CENTOS6.3:
procedure encryptext (ht : integer; return_value : pzval; this_ptr : pzval;
return_value_used : integer; TSRMLS_DC : pointer); cdecl;
var
getmyparameters: function(argu_num:integer;
type_apec:pansichar;Args : Array of const):integer;cdecl;
a:integer;
rtnstr:string;
begin
if (PHPLib < 1) then exit;
getmyparameters := GetProcAddress(PHPLib, 'zend_parse_parameters');
if (#getmyparameters = nil) then
begin
raise EPHP4DelphiException.Create('zend_parse_parameters');
exit;
end;
if ht < 1 then
begin
zend_wrong_param_count(TSRMLS_DC);
Exit;
end;
a := 1;
if (getmyparameters(ht,pansichar('s'),[pansichar(rtnstr),#a]) <> SUCCESS ) then exit;
ZVAL_STRING(return_value,pansichar(rtnstr),true);
end;
php code of /var/www/html/a.php:
<?php
echo encryptext('hello');
?>
the error message is:
PHP Warning: encryptext() expects exactly 0 parameters, 1 given in /var/www/html/a.php on line 2

Related

Iterate over a map decoded from PHP-serialization format

How I can read conditions unserialised data in golang in map format?
[map[19:map[conditions:map[0:map[operator:== value:AMW-1900-50SLE-ROOM
is_value_processed:false type:feedexport/rule_condition_product
attribute:sku] 1:map[type:feedexport/rule_condition_product
attribute:sku operator:== value:ASL-B654-77-74-98-ROOM
is_value_processed:false] 2:map[is_value_processed:false
type:feedexport/rule_condition_product attribute:sku operator:==
value:ASL-B217-57-54S-95-ROOM]] type:feedexport/rule_condition_combine
attribute:<nil> operator:<nil> value:1 is_value_processed:<nil>
aggregator:any]]]
This is the code:
package main
import (
"fmt"
"github.com/wulijun/go-php-serialize/phpserialize"
)
func main() {
rules := RulesList()
for _, rule := range rules{
fmt.Println(rule.Conditions.(interface{}))
}
}
type Rule struct {
RuleId int `json:"rule_id"`
Conditions interface{} `json:"conditions"`
}
func RulesList() ([]Rule) {
db := DbConn()
res, err := db.Query(`SELECT r.rule_id, r.conditions_serialized AS
conditions FROM m_feedexport_rule AS r`)
CheckError(err)
rule := Rule{}
rules := []Rule{}
for res.Next() {
var ruleId int
var conditions string
err = res.Scan(&ruleId, &conditions)
CheckError(err)
cons, err := phpserialize.Decode(conditions)
CheckError(err)
rule.RuleId = ruleId
rule.Conditions = cons
rules = append(rules, rule)
}
return rules
}
The result is ok but I need it in map form, now this is the interface which I can't loop over. In case if anyone don't understand the code, ask me.
Thanks a lot.
You're talking about the type of the variable cons, are you?
Background
If yes, the reason its type is interface{} is because in PHP, it's possible to serialize a value of any type (from bare integer to a complicated object), and hence any deserialization code must cope with it. Since in Go the so-called "empty interface", interface{},
is satisfied by any type at all (including any custom type implemented by a programmer), it's sensbile for a decoder of PHP-serialized data to return a value of type interface{}.
Solution
After making sure decoding succeeded,
you need to either type-assert
the resulting value to a type you need or to use
a type switch
to diverge processing based on the concrete type of the
value returned by the decoder.
The approach is very well demonstrated by the
package you're using in its own test suite.
A snippet from it demonstrating the basic approach
if decodeRes, err = Decode(result); err != nil {
t.Errorf("decode data fail %v, %v", err, result)
return
}
decodeData, ok := decodeRes.(map[interface{}]interface{})
if !ok {
t.Errorf("decode data type error, expected: map[interface{}]interface{}, get: %T", decodeRes)
return
}
obj, _ := decodeData["object"].(*PhpObject)
if v, _ := obj.GetPrivateMemberValue("a"); v != int64(1) {
t.Errorf("object private value expected 1, get %v, %T", v, v)
}
if v := obj.GetClassName(); v != "A" {
t.Errorf("object class name expected A, get %v", v)
}
Here, decodeRes is what returned by the decoder.
That value is then type-asserted to make sure it's concrete type
(also called "dynamic" — meaning "at runtime") is
map[interface{}]interface{}.
Note that the so-called "two-argument" type assert is used
(it's also called a "comma-ok idiom") to not make the program
panic at runtime in case the concrete type is different from
the expected (always do this on data fetched from outside!).
The value of the type-asserted concrete type is stored in the
decodeData variable, and then that variable is inspected further.

how to get values from a interface in golang

I need to get values from a serialized string which generated from php code
So I use a package named:php_serialize to unserialize the string and then got a result of interface{} type .
But I have no idea how to get values inside the result.
This is code:
package main
import (
"github.com/yvasiyarov/php_session_decoder/php_serialize"
"fmt"
)
func main() {
// this string is generated from php code
str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}`
decoder := php_serialize.NewUnSerializer(str)
if result, err := decoder.Decode(); err != nil {
panic(err)
} else {
fmt.Println(result)
}
}
The print result is :
map[name:tom age:23 friends:map[0:map[name:jerry] 1:map[name:jack]]]
This result is a php_serialize.PhpValue type, which is interface{} type
The next step is how to get values inside the result?
such as get the age field and value
You must assert the result to map[string]interface:
mResult := result.(map[string]interface{})
fmt.Println(mResult["name"])
And once more assertion for friends:
mFriends := mResult["friends"].(map[int]map[string]interface{})
Then use it: mFriends[0]["name"]
Here some ways to access the data:
package main
import (
"fmt"
"github.com/yvasiyarov/php_session_decoder/php_serialize"
)
func main() {
// this string is generated from php code
str := `a:3:{s:4:"name";s:3:"tom";s:3:"age";s:2:"23";s:7:"friends";a:2:{i:0;a:1:{s:4:"name";s:5:"jerry";}i:1;a:1:{s:4:"name";s:4:"jack";}}}`
decoder := php_serialize.NewUnSerializer(str)
result, err := decoder.Decode()
if err != nil {
panic(err)
}
fmt.Println(result)
// simple assert
t := result.(php_serialize.PhpArray)
// use php_seriale build in function to get string
strVal := php_serialize.PhpValueString(t["name"])
fmt.Println(strVal)
// type switch in case of different valid types
switch t := result.(type) {
default:
fmt.Printf("unexpected type %T\n", t) // %T prints whatever type t has
case php_serialize.PhpArray:
fmt.Println(t)
fmt.Println(t["name"])
fmt.Println(t["age"])
// should be done recursively...
switch f := t["friends"].(type) {
default:
fmt.Printf("unexpected type %T\n", f) // %T prints whatever type t has
case php_serialize.PhpArray:
fmt.Println(f)
fmt.Println(f[0])
fmt.Println(f[1])
}
}
}
I hope this gives you some ideas.
Basic concept
php_serialize has built in functions to convert primitives.
Variable structures are represented with built in types which need to be used to access the structure.

Handle a PL/SQL function returning a record in PHP

I've been looking on the Internet and I didn't find an answer so here I am.
I've a PL/SQL function returning a record :
create or replace package pck_test is
TYPE coord_geo is record (coord_x float, coord_y float);
function ArrondiGeo(coord_x float, coord_y float) return coord_geo;
end pck_test;
/
create or replace package body pck_test is
FUNCTION ArrondiGeo(coord_x FLOAT,coord_y FLOAT) RETURN coord_geo
IS
temp_x FLOAT(24);
temp_y FLOAT(24);
rec_coord coord_geo;
BEGIN
temp_x := ROUND(coord_x,4)/5;
temp_y := ROUND(coord_y,4)/5;
temp_x := ROUND((temp_x*5),3);
temp_y := ROUND((temp_y*5),3);
rec_coord.coord_x := temp_x;
rec_coord.coord_y := temp_y;
RETURN rec_coord;
END;
END pck_test;
/
And I want to use it in a PHP function but I don't really know how ...
I tried this but it doesn't work :
public function get_tronc($x,$y)
{
$q = oci_parse($this->_db, 'begin :r := pck_test.ArrondiGeo(:x,:y); end;');
oci_bind_by_name($q, ':x', $x);
oci_bind_by_name($q, ':y', $y);
oci_bind_by_name($q, ':r', $r);
oci_execute($q);
return $r;
}
The error is :
Warning: oci_execute(): ORA-06550: line 1, column 13: PLS-00382: expression is of wrong type ORA-06550: line 1, column 7: PL/SQL: Statement ignored in /users/info/il3/jboeglin/Bureau/BDD/site/models/userManager.php on line 77
So that's a self explaining error but I still can't figure how I can use it.
Thank you.
For a named datatype, you probably need to bind your parameter specifying the SQLT_NTY type:
$r = oci_new_collection($this->db, 'COORD_GEO');
oci_bind_by_name($q, ':r', $r, -1, SQLT_NTY);
...
oci_execute($q);
// do whatever you need with your data
$data = $elem = $collection->getElem(1);
// then discard it
$r->free();
See the manual of oci_bind_by_name for details.
For plain PL/SQL records, you're probably out of luck: according to Oracle's documentation you can't use OCI to fetch a record. As of Oracle 11g:
The following two types are internal to PL/SQL and cannot be returned as values by OCI:
Boolean, SQLT_BOL
Record, SQLT_REC
If this is correct (I'm not a regular PHP user), you will probably have to wrap your function at PL/SQ level:
either, in a procedure with the required number of OUT parameters;
or maybe, depending your needs, in a table function.
For sake of completeness, please note that Oracle 12c + OCI8 2.0.7 remove the restriction that had previously not allowed to return a boolean value.
Thank you for you answer, I tried SQLT_NTY but it doesn't work probably because OCI can't return records like you said, ...
I'll try to look at a table function.
Edit : I finally used a PROCEDURE
create or replace package pck_test is
PROCEDURE ArrondiGeo(coord_x IN FLOAT,coord_y IN FLOAT,temp_x OUT FLOAT,temp_y OUT FLOAT);
end pck_test;
/
create or replace package body pck_test is
PROCEDURE ArrondiGeo(coord_x IN FLOAT,coord_y IN FLOAT,temp_x OUT FLOAT,temp_y OUT FLOAT)
IS
BEGIN
temp_x := ROUND(coord_x,4)/5;
temp_y := ROUND(coord_y,4)/5;
temp_x := ROUND((temp_x*5),3);
temp_y := ROUND((temp_y*5),3);
END;
END pck_test;
/
and this php function :
public function get_tronc($x,$y)
{
$q = oci_parse($this->_db, 'begin pck_test.ArrondiGeo(:x,:y,:xm,:ym); end;');
oci_bind_by_name($q, ':x', $x);
oci_bind_by_name($q, ':y', $y);
oci_bind_by_name($q, ':xm', $xm,40);
oci_bind_by_name($q, ':ym', $ym,40);
oci_execute($q);
$r=array($xm,$ym);
return $r;
}

Base64 Encoding Delphi

I'm making a Delphi application and I'm trying to encode with base64 encoding stream and I made two functions:
function EncodedInputParams(input: TStringStream): string;
var
output: TStringStream;
encoder: TIdEncoderMIME;
begin
input.Encoding.UTF8;
input.Position := 0;
output := TStringStream.Create;
try
encoder := TIdEncoderMIME.Create(nil);
encoder.Encode(input, output);
output.Seek(0, soFromBeginning);
Result := output.DataString;
finally
output.Free;
end;
end;
function SecondEncoding(input: TStringStream): string;
var
output: TStringStream;
midRes: string;
begin
input.Encoding.UTF8;
input.Position := 0;
output := TStringStream.Create;
try
EncodeStream(input, output);
output.Seek(0, soFromBeginning);
midRes := output.DataString;
midRes := StringReplace(midRes, #13#10, EmptyStr, [rfReplaceAll]);
result := midRes;
finally
output.Free;
end;
end;
Functions are working fine but the problem is that these solutions return different string than a string encoded same way in PHP: http://www.tools4noobs.com/online_php_functions/base64_encode/ .
Any ideas how to rewrite one of the function to return string like one written in PHP.

How can I capture output from the Windows cmd shell?

Is there any way with, say Perl or PHP, that I can grab output from another process that outputs to the Windows cmd shell? I have a game server that outputs certain information, for example say 'player finished track in 43s' and I want to grab that line and use Perl or PHP to send a request to a webserver to update ranks on a web page. Is there a way to grab that output pipe in Perl or PHP? Or could I achieve this using C++ Windows API maybe?
Let me clarify here: I want to execute a seperate Perl or PHP script that grabs output from the Windows cmd shell, and the output that is being displayed to the Windows cmd shell is coming from a different process.
You could use IPC::Open3 to read from the other process' standard output. Note that inter-process communication assumes a parent/child relationship between the processes. If that's not the case... I'm not aware of a mechanism for attaching to the output of a pre-existing process. In that case you may need to alter the producer to write data to a log file (or database) that your application can read from.
If all you care about is STDOUT, you can just use open2 from IPC::Open2:
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
#if there are arguments pretend to be the server
#for this example
if (#ARGV) {
local $| = 1;
for my $i (1 .. 100) {
print "pid $$ iter $i\n";
sleep 1;
}
exit;
}
#run perl with the current script as its argument,
#pass in an arg so that we trigger the behaviour
#above
open2 my $out, my $in, $^X, $0, 1
or die "could not run '$^X $0 1': $!\n";
while (<$out>) {
s/[\r\n]//g;
print "pid $$ saw [$_]\n";
}
You need to start your server within Perl:
my $server_out = `server.exe`; # Note the backticks.
Now $server_out contains the output of server.exe. But the trick here is that you have to wait until server.exe exits to get the out put.
Try IPC::Run (which is not a core module)
use English;
use IPC::Run;
my ($stdout, $stderr);
IPC::Run::run([$cmd, $arg1, $arg2, $argN], \undef, \$stdout, $stderr);
while(<$stdout>) {
print "Cmd said $_\n";
}
Note: Code not tested.
Found the info here.
Capturing the output in Perl is as simple as:
$output = qx(command);
or
$output = `command`; # backticks
Refer: perldoc perlop
This code redirects the STDOUT of a console application to a stringlist, which you can use on a memo for example. It's Delphi code, but in C++ the basic idea is exactly the same.
I use it to run console applications hidden, while redirecting the output to my own application, to show in a pane. It adds a new line to AStrings as soon as data comes in, so you'll have access to the output of the other application before it finishes.
procedure RunConsoleApp(const CommandLine: string; AStrings: TStrings);
type
TCharBuffer = array[0..MaxInt div SizeOf(Char) - 1] of Char;
const
MaxBufSize = 1024;
var
I: Longword;
SI: TStartupInfo;
PI: TProcessInformation;
SA: PSecurityAttributes;
SD: PSECURITY_DESCRIPTOR;
NewStdIn: THandle;
NewStdOut: THandle;
ReadStdOut: THandle;
WriteStdIn: THandle;
Buffer: ^TCharBuffer;
BufferSize: Cardinal;
Last: WideString;
Str: WideString;
ExitCode_: DWORD;
Bread: DWORD;
Avail: DWORD;
begin
GetMem(SA, SizeOf(TSecurityAttributes));
case Win32Platform of
VER_PLATFORM_WIN32_NT:
begin
GetMem(SD, SizeOf(SECURITY_DESCRIPTOR));
SysUtils.Win32Check(InitializeSecurityDescriptor(SD, SECURITY_DESCRIPTOR_REVISION));
SysUtils.Win32Check(SetSecurityDescriptorDacl(SD, True, nil, False));
SA.lpSecurityDescriptor := SD;
end; {end VER_PLATFORM_WIN32_NT}
else
SA.lpSecurityDescriptor := nil;
end; {end case}
SA.nLength := SizeOf(SECURITY_ATTRIBUTES);
SA.bInheritHandle := True;
SysUtils.Win32Check(CreatePipe(NewStdIn, WriteStdIn, SA, 0));
if not CreatePipe(ReadStdOut, NewStdOut, SA, 0) then
begin
CloseHandle(NewStdIn);
CloseHandle(WriteStdIn);
SysUtils.RaiseLastWin32Error;
end; {end if}
GetStartupInfo(SI);
SI.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
SI.wShowWindow := {SW_SHOWNORMAL} SW_HIDE;
SI.hStdOutput := NewStdOut;
SI.hStdError := NewStdOut;
SI.hStdInput := NewStdIn;
if not CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_CONSOLE, nil, nil, SI, PI) then
begin
CloseHandle(NewStdIn);
CloseHandle(NewStdOut);
CloseHandle(ReadStdOut);
CloseHandle(WriteStdIn);
SysUtils.RaiseLastWin32Error;
end; {end if}
Last := '';
BufferSize := MaxBufSize;
Buffer := AllocMem(BufferSize);
try
repeat
SysUtils.Win32Check(GetExitCodeProcess(PI.hProcess, ExitCode_));
PeekNamedPipe(ReadStdOut, Buffer, BufferSize, #Bread, #Avail, nil);
if (Bread <> 0) then
begin
if (BufferSize < Avail) then
begin
BufferSize := Avail;
ReallocMem(Buffer, BufferSize);
end; {end if}
FillChar(Buffer^, BufferSize, #0);
Windows.ReadFile(ReadStdOut, Buffer^, BufferSize, Bread, nil);
Str := Last;
I := 0;
while (I < Bread) do
begin
case Buffer^[I] of
#0: inc(I);
#7: begin
inc(I);
Windows.Beep(800, 50);
Str := Str + '^';
end;
#10:
begin
inc(I);
AStrings.Add(Str);
Str := '';
end; {end #10}
#13:
begin
inc(I);
if (I < Bread) and (Buffer^[I] = #10) then
inc(I);
AStrings.Add(Str);
Str := '';
end; {end #13}
else
begin
Str := Str + Buffer^[I];
inc(I);
end; {end else}
end; {end case}
end; {end while}
Last := Str;
end; {end if}
Sleep(1);
Application.ProcessMessages;
until (ExitCode_ <> STILL_ACTIVE);
if Last <> '' then
AStrings.Add(Last);
finally
FreeMem(Buffer);
end; {end try/finally}
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
CloseHandle(NewStdIn);
CloseHandle(NewStdOut);
CloseHandle(ReadStdOut);
CloseHandle(WriteStdIn);
end; {end procedure}
Here is a PHP specific solution, the project allows PHP to obtain and interact dynamically with a real cmd terminal. Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code:
//if you prefer Powershell, replace 'cmd' with 'powershell'
$shellObj = \MTS\Factories::getDevices()->getLocalHost()->getShell('cmd');
$strCmd1 = 'some_app.exe -param "test"';
$return1 = $shellObj->exeCmd($strCmd1);
The return will give you the command return OR error from cmd, just as if you sat at the console.
Furthermore, you can issue any command you like against the $shellObj, the environment is maintained throughout the life of the PHP script. So instead of bundling commands in a script file, just issue them one by one using the exeCmd() method, that way you can also handle the return and any exceptions.

Categories