PHP and COM Wez Furlong wezmessagesystems com Plan

  • Slides: 39
Download presentation
PHP and COM Wez Furlong <wez@messagesystems. com>

PHP and COM Wez Furlong <wez@messagesystems. com>

Plan • What is COM? • What's it good for? • How do I

Plan • What is COM? • What's it good for? • How do I use it? • Instantiation. . . and Monikers • Exceptions • Typelibraries • Variants • . Net Interop • Active. Script • Persistence (experimental)

Common Object Model • Frequently mislabeled as Component Object Model • Specifies programming interfaces

Common Object Model • Frequently mislabeled as Component Object Model • Specifies programming interfaces for OO code • Those interfaces are programming language independent • Provides a mechanism for code re-use

OLE • A subset of these interfaces are collectively known as OLE: Object Linking

OLE • A subset of these interfaces are collectively known as OLE: Object Linking and Embedding • They define a way to dynamically create and invoke methods on objects that implement those interfaces • PHP COM is really PHP OLE

COM Servers • A COM Server is some module that exposes a COM interface

COM Servers • A COM Server is some module that exposes a COM interface via creatable classes • In-Proc (DLL) => fast • Out-of-Proc (EXE) => not so fast • DCOM => on another machine • Your code sees these as the same thing

What's it good for? • Talking to other applications and libraries • Most win

What's it good for? • Talking to other applications and libraries • Most win 32 software vendors provide a COM interface • Can be used to transition from ASP to PHP • Can use “easy” languages to extend PHP

How do I use it? $word = new COM(“Word. Application”); $word->visible = true; $word->Documents->Add();

How do I use it? $word = new COM(“Word. Application”); $word->visible = true; $word->Documents->Add(); $word->Selection->Type. Text(“hello”); $word->Active. Document->Save. As(“test. doc”); $word->Quit();

Instantiation $word = new COM(“Word. Application”, array( ‘Server’ => ‘otherbox’, ‘Username’ => ‘foo’, ‘Password’

Instantiation $word = new COM(“Word. Application”, array( ‘Server’ => ‘otherbox’, ‘Username’ => ‘foo’, ‘Password’ => ‘bar’ ), CP_UTF 8);

Exceptions try { $o = new COM(“…”); } catch (com_exception $e) { print “failed

Exceptions try { $o = new COM(“…”); } catch (com_exception $e) { print “failed to create: $e”; } $e->get. Code() corresponds to weird hex number (will show example later)

Typelibraries • Import constants from a COM server as regular PHP constants. • Manually

Typelibraries • Import constants from a COM server as regular PHP constants. • Manually • • com_load_typelib(‘Word. Application’); • echo wd. Go. To. Bookmark; From php. ini: • com. typelib_file=C: mytypelibs. txt

Variants • PHP COM is really PHP Variant • Variant is win 32 equivalent

Variants • PHP COM is really PHP Variant • Variant is win 32 equivalent of PHP typeless variables • JIT conversion in PHP 5 • OLE default properties • $doc = $word->Active. Document; • print $doc; // prints document title

Variant Arrays $user = new COM( “LDAP: //cn=user, ou=test, dc=php, dc=net”); $arr = $user->Get.

Variant Arrays $user = new COM( “LDAP: //cn=user, ou=test, dc=php, dc=net”); $arr = $user->Get. Ex(“other. Home. Phone”); for ($i = 0; $i < count($arr); $i++) { print $arr[$i]. “n”; }

Iterators Set domain. Object = Get. Object("Win. NT: //Domain") For Each obj in domain.

Iterators Set domain. Object = Get. Object("Win. NT: //Domain") For Each obj in domain. Object Response. Write obj. Name & " “ Next $domain. Object = new COM("Win. NT: //Domain"); foreach ($domain. Object as $obj) { echo $obj->Name. " "; }

Variant Functions • • • Arithmetic • variant_add variant_sub • variant_mul variant_div Casting •

Variant Functions • • • Arithmetic • variant_add variant_sub • variant_mul variant_div Casting • variant_set_type (VT_BSTR etc. ) • variant_get_type • variant_date_from_timestamp • variant_date_to_timestamp VB-like behaviour

. Net Interop. Net is modern replacement for VB Uses similar concepts to COM

. Net Interop. Net is modern replacement for VB Uses similar concepts to COM MS provide an “Interop” layer to map. Net assemblies into COM $stack = new DOTNET(‘mscorlib’, ‘System. Collections. Stack’); $stack->push(‘. Net’); $stack->Push(‘Hello ’); echo $stack->pop();

Some Sample Scripts • Look at some common tasks implemented in PHP • Gotchas?

Some Sample Scripts • Look at some common tasks implemented in PHP • Gotchas?

WMI for system monitoring $wmi = new COM( “Win. Mgmts: {impersonation. Level=impersonate}”. “//{$hostname}/root/cimv 2”

WMI for system monitoring $wmi = new COM( “Win. Mgmts: {impersonation. Level=impersonate}”. “//{$hostname}/root/cimv 2” ); $cpus = $wmi->Exec. Query( "Select * from Win 32_Processor"); foreach ($cpus as $cpu) { printf(“%s %d. MHz %d%%n”, $cpu->Name, $cpu->Max. Clock. Speed, $cpu->Load. Percentage); }

ADO DB Useful for transitioning ASP Often faster to use odbc or native drivers

ADO DB Useful for transitioning ASP Often faster to use odbc or native drivers $conn = new COM(‘ADODB. Connection’); $conn->Open($dsn); $conn->Execute(‘update …’); $rs = new COM(‘ADODB. Recordset’); $rs->Open(‘select foo from bar’, $conn); while (!$rs->EOF()) { echo $rs->Fields(‘foo’); $rs->Move. Next(); }

MS Office (Word) $word = new COM(“Word. Application”); $word->visible = true; $word->Documents->Add(); $word->Selection->Type. Text(“hello

MS Office (Word) $word = new COM(“Word. Application”); $word->visible = true; $word->Documents->Add(); $word->Selection->Type. Text(“hello ”. $_SESSION[‘username’]); $word->Active. Document->Save. As(“test. doc”); $word->Quit();

Shmop mutex • Use a single instance of Word • Use mutex to control

Shmop mutex • Use a single instance of Word • Use mutex to control access to it • extension=php_shmop. dll • Need to be running ISAPI or Apache module on win 2 k and later

Shmop mutex 2 function try_mutex($timeout) { $t = time(); do { $mtx = shmop_open(42,

Shmop mutex 2 function try_mutex($timeout) { $t = time(); do { $mtx = shmop_open(42, “cwn”, 0644, 1); if ($mtx) return $mtx; usleep(200000); // 0. 2 seconds } while (time() < $t + $timeout); return false; } function drop_mutex($mtx) { shmop_delete($mtx); }

Shmop mutex 3 com_get_active_object() returns a handle to an instance from the Running Object

Shmop mutex 3 com_get_active_object() returns a handle to an instance from the Running Object Table function get_one() { try { $w = com_get_active_object(‘Word. Application’); return $w; } catch (com_exception $e) { if ($e->get. Code() == MK_E_UNAVAILABLE) return new COM(‘Word. Application’); throw $e; } }

Shmop mutex 4 $mtx = try_mutex(3); if (!$mtx) {. . Try again later …

Shmop mutex 4 $mtx = try_mutex(3); if (!$mtx) {. . Try again later … } $word = get_one(); $word->Documents->Add(); $word->Selection->Type. Text(“foo”); $word->Active. Document->Save. As($filename); $word->Active. Document->Close(); drop_mutex($mtx); readfile($filename);

Create a server app • The shmop idea is prone to failure if something

Create a server app • The shmop idea is prone to failure if something bad happens to a request that holds the mutex • An alternative is to run a separate process as a tcp server and queue requests to it • PHP 5 makes this easy

Client for Word Daemon $daemon = stream_socket_client(‘ 127. 0. 0. 1: 4000’); if ($daemon)

Client for Word Daemon $daemon = stream_socket_client(‘ 127. 0. 0. 1: 4000’); if ($daemon) { fwrite($daemon, serialize($data)); $result = fgets($daemon); }

Word Daemon $w = new COM(‘Word. Application’); $s = stream_socket_server(‘ 127. 0. 0. 1:

Word Daemon $w = new COM(‘Word. Application’); $s = stream_socket_server(‘ 127. 0. 0. 1: 4000’); while (true) { $client = stream_socket_accept($s); $data = unserialize(stream_get_contents($client)); generate_word_doc($data); fwrite($client, “DONErn”); fclose($client); }

With Events • COM event handling framework is build from ‘Connection Points’ • A

With Events • COM event handling framework is build from ‘Connection Points’ • A source object is implements IConnection. Point. Container • A sink object (callback handler) implements a dispinterface • dispinterfaces allow a loose handler implementation; perfect for scripting languages

turning on events bool com_event_sink($object, $sinkobject [, $sinkname]); Plumbs in event handling; Events from

turning on events bool com_event_sink($object, $sinkobject [, $sinkname]); Plumbs in event handling; Events from $object are sunk into $sinkobject

Sinking events from IE $ie = new COM("Internet. Explorer. Application"); $ie->Visible = true; $ie->Navigate("http:

Sinking events from IE $ie = new COM("Internet. Explorer. Application"); $ie->Visible = true; $ie->Navigate("http: //www. php. net");

IE Events 2 class IEEvents { var $dom = null; function Document. Complete($dom, $url)

IE Events 2 class IEEvents { var $dom = null; function Document. Complete($dom, $url) { echo “$url completen”; $this->dom = $dom; } }

IE Events 3 $sink = new IEEvents; $ie = new COM("Internet. Explorer. Application"); $ie->Visible

IE Events 3 $sink = new IEEvents; $ie = new COM("Internet. Explorer. Application"); $ie->Visible = true; com_event_sink($ie, $sink, ‘DWeb. Browser. Events 2’); $ie->Navigate("http: //www. php. net"); while (!$sink->dom) { com_message_pump(4000); } // we can do stuff with $sink->dom here, or just continue with something else

IActive. Script • A set of interfaces that abstract scripting engines • A compatible

IActive. Script • A set of interfaces that abstract scripting engines • A compatible host can run any compliant script engine • Works in both directions; you can load engines in php, and you can load php into other hosts

Invoke JScript from PHP class foo { function bar($msg) { echo $msg; } }

Invoke JScript from PHP class foo { function bar($msg) { echo $msg; } } $js = new COM(‘Script. Control’); $js->Language = ‘JScript’; $js->Add. Object(‘foo’, new foo, false); $js->Add. Code(‘foo. bar(“js!”); ’);

Active. Script • This SAPI lets you load PHP into other scripting engines •

Active. Script • This SAPI lets you load PHP into other scripting engines • You need to regsvr 32 php 5 activescript. dll to enable it • Language = PHPScript • Sadly, can't load PHP into PHP via COM due to architecture of PHP SAPI interface

Using PHP in Windows Script Host Create a. wsf file like this: <job id="test">

Using PHP in Windows Script Host Create a. wsf file like this: <job id="test"> <script language="PHPScript"> $WScript->Echo("Hello"); </script> </job> cscript test. wsf

Persistence Helper • Not everything supports the relevant interfaces, so not totally useful •

Persistence Helper • Not everything supports the relevant interfaces, so not totally useful • Intention is to persist object state into streams or strings and store it into some kind of DB. • PHP streams are mapped as COM IStreams

Bogus Example $object = new COM(‘…’); $object->do. Something(); $dest = fopen(‘ftp: //…/…’, ‘wb’); $p

Bogus Example $object = new COM(‘…’); $object->do. Something(); $dest = fopen(‘ftp: //…/…’, ‘wb’); $p = new COMPersist. Helper($object); $p->Save. To. Stream($dest);

Bogus Example 2 $object = new COM(‘…’); $src = fopen(‘ftp: //…/…’, ‘rb’); $p =

Bogus Example 2 $object = new COM(‘…’); $src = fopen(‘ftp: //…/…’, ‘rb’); $p = new COMPersist. Helper($object); $p->Load. From. Stream($src); // $object is now in same state as it was on previous slide

Resources • These slides are on my blog and on slideshare. net http: //netevil.

Resources • These slides are on my blog and on slideshare. net http: //netevil. org • PHP COM manual: http: //www. php. net/manual/en/ref. com. php • WMI: http: //msdn. microsoft. com/library/default. asp? url=/library/enus/wmisdk/wmi_start_page. asp • Server-side MS Office: http: //support. microsoft. com/default. aspx? scid=kb; EN-US; q 257757 • PHP snapshots http: //snaps. php. net