Trouble using DOTNET from PHP. - php

I've been trying to call a .net assembly from PHP through com (using DOTNET()). It seems like php is finding the DLL and initializing properly, but I can't see/use the methods for some reason. Anyone know how I might be able to fix this?
Here is the php code I'm using to call the .net class. When I call it the output is "hello1 hello2". When I try to directly call the function by doing $csclass->ModelBuilder("","") I get a 500 server error specifying that it couldn't find the function.
<?php
echo "hello1";
try{
$csclass = new DOTNET("ModelBuilder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1208136d23b48dc5",
"ModelBuilder.ModelBuilder2");
$class_methods = get_class_methods($csclass);
foreach ($class_methods as $method_name) {
echo "$method_name\n";
}
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
echo "hello2";
?>
Here is the the class in the assembly I'm trying to call (built using .net 3.5, signed with a strong name, and registered with gacutil):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using OfficeOpenXml;
using System.Runtime.InteropServices;
namespace ModelBuilder
{
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class ModelBuilder2
{
[ComVisible(true)]
public Boolean BuildModel(String outputFileLoc,String excelTemplateFile)
{
try
{
//do stuff
return true;
}
catch (Exception e)
{
return false;
}
}
}

The get_class_methods() will not work with a Dotnet class object. That thing is a proxy, and it does not behave the way a normal php object does.
If you really are focused on listing the methods of the object, then you need to look into implementing IDispatch on your .NET object. If, however, your main goal is to simply use the .NET object, and your attempt to list the methods was just a side effort to diagnose why that was not working, then I have some suggestions for you.
rather than using gacutil, consider whether you can insert the required DLL into the php directory, the place where php.exe resides. If php.exe resides at c:\php5\php.exe, then
copy your assembly into c:\php5.
If you follow the above suggestion, the .NET assembly need not be strongly named. It needs to be strongly named if you plan to GAC it. As I said, you don't need to GAC it, in order to load it with php. If you copy the assembly into the PHP dir, then you can use an un-signed assembly.
For early development and exploration with this, use the php.exe program from the command-line, rather than using IIS to launch php via a web request. This lets you see the error messages directly, rather than worrying about 500 errors from IIS.
Example
Suppose this is the C# code:
using System;
namespace Ionic
{
public class MathEx
{
System.Random rnd;
public MathEx ()
{
rnd = new System.Random();
}
public int RandomEven()
{
return rnd.Next()*2;
}
}
}
Compile it from the command-line like this:
c:\net3.5\csc.exe /t:library /out:Ionic.MathEx.dll MathEx.cs
copy the assembly to the dir that holds php.exe:
copy Ionic.MathEx.dll \php
1 file(s) copied.
Then, suppose I have a php script named mathex.php with these contents:
<?php
$my_assembly = 'Ionic.MathEx'; // name of the dll without the .dll suffix
$clz = new DOTNET($my_assembly, 'Ionic.MathEx');
for ($i=0; $i<5; $i++) {
echo $i . " " . $clz->RandomEven() . "\n";
}
?>
... and if I run it from the command line this way:
\php\php.exe mathex.php
...then I get these results:
0 -1083602762
1 1535669896
2 -86761710
3 -1204365564
4 459406052
Nota Bene
I tried doing this with an assembly compiled with .NET 4.0, but it did not work, giving me an error message about a .NET runtime mismatch. Like this:
Fatal error: Uncaught exception 'com_exception' with message 'Failed to instantiate .Net object
[CreateInstance] [0x8013101b] ' in C:\dev\php\mathEx.php:6
Stack trace:
#0 C:\dev\php\mathEx.php(6): dotnet->dotnet('Ionic.MathEx', 'Ionic.MathEx')
#1 {main}
thrown in C:\dev\php\mathEx.php on line 6
The 0x8013101b indicates a runtime mismatch - the runtime version of the assembly does not match the runtime version of the app that is trying to load the assembly.
From this I conclude that php5 is compiled to support .NET 2.0 (which includes 3.0 and 3.5). The runtime version changed for .NET 4.0, so assemblies that you compile with a .NET 4.0 compiler (including VS2010) will not be usable with php5.exe. The workaround is to just compile with the .NET 2.0 or 3.5 compiler (VS2005, vs2008).

Related

Can Monolog be used on GAE and have the logging levels recorded in Stack Driver?

There are a number of posts on the internet that indicate the right way to use Monolog on the google app engine (GAE standard) is like so:
$logger = new Monolog\Logger($name);
$syslogHandler = new \Monolog\Handler\SyslogHandler("Ident_String", LOG_USER, \Monolog\Logger::INFO);
$syslogHandler->setFormatter(new \Monolog\Formatter\JsonFormatter());
$logger->pushHandler($syslogHandler);
break;
$logger->warn("Starting priam import." );
That does get me logging, but the level is buried in the textPayload:
textPayload: "[28-Feb-2020 11:00:07] WARNING: [pool app] child 22
said into stderr: "[2020-02-28 06:00:07] match_old.INFO: Doing a super
huge SELECT to get all intls. [] []""
and the level icon is always a stippled out asterisk.
Has something changed? I'm using the php 7.3 run-time on GAE standard. Is there a way to use Monolog on GAE that let's you take proper use of stack driver?
There is a package available that allows you to push Monolog to Stackdriver.
As per the doc:
The supplied StackdriverHandler copies the given log level into the
Stackdriver's severity based on your log method.
It also respects the context argument which allows you to send extra
contextual data with your log message. This will be stored in the log
message under jsonPayload.data.
The source code can be found here monolog-stackdriver
I wound up conditionally loading a different logger locally than I do on GAE. It's workable, but it seems like an unnecessary hack considering monolog is such a popular library. And, oh, it's 2020.
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Google\Cloud\Logging\LoggingClient;
function get_logger($name) {
$kind = getenv('LOG_TYPE')?:'remote';
return _get_logger($kind, $name);
}
function _get_logger($kind, $name) {
if ($kind ==='local') {
$logger = new Monolog\Logger($name);
$logger->pushHandler(new Monolog\Handler\StreamHandler('php://stdout', Monolog\Logger::INFO));
return $logger;
}
$logging = new LoggingClient();
$logger = $logging->psrLogger($name);
return $logger;
}
I'm hoping someone can make this work with monolog.

Determining assembly name for use with PHP DOTNET

I am trying to use Microsoft's Speech Platform 11 through PHP's DOTNET object
https://msdn.microsoft.com/en-us/library/jj127858.aspx
The platform should be instantiated as follows
$platform = new DOTNET("assembly-name", "Microsoft.Speech.Recognition");
But how to retrieve the assembly name for Speech Platform 11? (to replace "assembly-name" in the initialization call)
I have tried several assembly names by... guesswork, obviously with no luck.
The initialization error being thrown
Failed to instantiate .Net object [CreateInstance] [0x80070002] The system cannot find the file specified
UPDATE
With the following code, I was able to get PHP to find and use the assembly
$full_assembly_string = 'Microsoft.Speech, Version=11.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35';
$full_class_name = 'Microsoft.Speech.Recognition.SpeechRecognitionEngine';
$interface = new DOTNET($full_assembly_string, $full_class_name);
However, there's a new roadblock:
Failed to instantiate .Net object [Unwrapped, QI for IDispatch] [0x80004002] No such interface supported
At first glance it seems it has to do with COM visibility. But if for any reason the class isn't visible to COM (and it seems odd), how to change this? Is it even possible?
Not tested. Just another guess.
According to the Microsoft Speech Platform SDK 11 Docs:
https://msdn.microsoft.com/en-us/library/microsoft.speech.recognition.speechrecognitionengine.aspx
i would give this a try:
"assembly" Microsoft.Speech
"classname" Microsoft.Speech.Recognition.SpeechRecognitionEngine
Microsoft.Speech.Recognition is only the namespace
$sre = new DOTNET(
'Microsoft.Speech',
'Microsoft.Speech.Recognition.SpeechRecognitionEngine'
);
Methods are documented here: https://msdn.microsoft.com/en-us/library/microsoft.speech.recognition.speechrecognitionengine_members(v=office.14).aspx#Anchor_2

Gitonomy cannot access my remote repository

I am testing out the Gitonomy Library within PHP and something I just cannot put my finger on. I have created a small application found here with a class that uses the Repository class from the library to list available branches on GITHUB Remote REposictory. Below is the class:
namespace LuSoft\Library{
use Gitonomy\Git\Repository as RemoteRepositroy;
class Repository
{
public function getBranches($repository)
{
if(!is_string($repository)){
throw new Exception("Reposotory must be in a form of a string.");
}
$rr = new RemoteRepositroy($repository);
$branches = [];
foreach($rr->getReferences()->getBranches() as $branch){
$branches[] = $branch->getName();
}
$rr->run('fetch', array('--all'));
return $branches;
}
}
}
I have followed the example from here. Below is how I call this class in my index.php page.
require_once "vendor/autoload.php";
use LuSoft\Library\Repository;
$repository = new Repository();
try{
var_dump($repository->getBranches(__DIR__));
}catch(\Exception $e){
echo "Exception :" . $e->getMessage();
}
Below is the error that I get:
Exception :Error while getting list of references: '"git"' is not
recognized as an internal or external command, operable program or
batch file.
I am using the application I am testing with to get the branches and if things went on correctly I am suppose to be seeing master.
Can someone please explain to me how does the library really work in simplest form?
NB: My index.php is on the same folder level of the application where git has been initialized.

Where is the tutorial "processor" generated?

I just started working with the github hosted build of apache thrift, I am basically interested in a java client and PHP server implementation, but for now i am using the php server and client only
All nice and easy i made my thrift file
namespace php mobiledata
struct sms
{
1: string from,
2: string to,
3: string smstext,
4: string smsdatetime,
5: string smsdirection
}
struct smsdetails
{
1: list<sms> smsdata
}
service mobiledataservice
{
void insertsmsdata (1: smsdetails smslist)
}
And I generated the gen-php folder, which has got Types.php and mobiledataservice.php
the basic sample that comes with the github for php as server shows a line of code
$handler = new CalculatorHandler();
$processor = new \tutorial\CalculatorProcessor($handler);
I can't find this class "CalculatorProcessor" and certainly I don't have a comparative class generated in my gen_php like mobiledataprocessor, and it baffles me as to how I would run my server in absence of processor.
The server code is generated by calling
thrift -r -gen php:server tutorial.thrift
Note the :server part after -gen php, this triggers the processor generation.
These are all PHP options available:
php (PHP):
inlined: Generate PHP inlined files
server: Generate PHP server stubs
oop: Generate PHP with object oriented subclasses
rest: Generate PHP REST processors

PHP DOTNET() not able to load from "System" assembly

Trying to use the Microsoft's .NET classes from System.Security.Cryptography.X509Certificates located in System assembly raises the following error:
$certificate2 = new DOTNET('System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', 'System.Security.Cryptography.X509Certificates.X509Certificate2');
com_exception: Failed to instantiate .Net object [Unwrapped, QI for IDispatch] [0x80004002] No such interface supported
in ...\test.php on line 2
Whereas the following calls do work and return DOTCOM instances.
$certificate = new DOTNET('mscorlib', 'System.Security.Cryptography.X509Certificates.X509Certificate');
$form = new DOTNET('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', 'System.Windows.Forms.Form');
Is there something special to System.dll or its classes contained in System.Security.Cryptography.X509Certificates?
Why could this file or classes not be usable?
digging deeper
The Exception origins to a failed method call in php_dotnet extension source code, line 250. But this is too low level for me. The call is:
hr = IUnknown_QueryInterface(V_UNKNOWN(&unwrapped), &IID_IDispatch, &V_DISPATCH(&obj->v));
side notes
PHP version is 5.5.5
this happens on a Windows 7 and Windows Server 2008 R2 box
the assembly seems to accessed correctly, but classes can not be found
selected .NET Framework Version is 2.0.0.0 (<=3.5), because PHP DOTNET does not work with Version >= 4
Cryptography classes from mscorlib do not suffice, because of limited functionality
Try this.It's working for me
<?php
$stack = new DOTNET("mscorlib", "System.Collections.Stack");
$stack->Push(".Net");
$stack->Push("Hello ");
echo $stack->Pop() . $stack->Pop();
?>
The link for the doc, Click here

Categories