PHP and COM

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

28 comments

Comments 1 - 10 of 28 previous next Post a comment

  • + wezfurlong Wez Furlong 2 years ago
    The cool thing is that you can persist (and restore) the object state into any PHP compatible stream.
    So, we’ve dumped the object state onto an ftp site here, but could have stored it into a memory stream or some kind of db stream or …

    Bogus because I don’t have a practical use for it (only common COM object that supports IPersist is the MSXML stuff; you can save to file from there using native API (but not to PHP streams so…)
  • + wezfurlong Wez Furlong 2 years ago
    Can load into any activescript host; Windows Scripting Host, ASP, the ScriptControl we used earlier, the WeaverSlave IDE, Kapsules desktop widget application
  • + wezfurlong Wez Furlong 2 years ago
    PHP also has an ActiveScript compatible interface; it is still a little bit experimental, but works for most of the stuff I’ve tried.
    The DLL is called php5activecript.dll and the best available version can be found in the PECL repository on our snapshots site.
  • + wezfurlong Wez Furlong 2 years ago
    The Language property can be set to the name of any language that you have installed; by default, windows ships with javascript and vbscript.
    You can download ActivePerl, ActiveRuby and ActivePython
    The COM extension provides an IDispatchEx wrapper for PHP objects, so that you can invoke them from other COM compatible scripting languages using this technique.
  • + wezfurlong Wez Furlong 2 years ago
    The main new thing here is com_message_pump(); you can thing of this as being something like sleep() except that the time is measured in milliseconds. The other big difference is that it will handle COM messages while it sleeps, returning after it processes the queue.
    We need to do this so that the COM can maintain various state and be able to actually call into our callback.
    If you’re writing any COM scripts, you should probably use com_message_pump() in any place where you are sleeping for more than a couple of seconds.
  • + wezfurlong Wez Furlong 2 years ago
    IE has a number of different event interfaces that could bind to; the one we’re interested in is called DWebBrowserEvents2. It has a number of methods that will be called for a number of useful events. In particular, we want the “DocumentComplete” method.
    This is called once the page has downloaded and rendered; you are passed a reference to the document object for the page and the url.
    You can use these as you see fit—you might want to walk the DOM to extract (or insert) information, or you might just want to indicate to the user that you’re ready.
    The handler above simply prints out the URL that loaded and sets the dom as a member variable.
    Now we need to hook it up…
  • + wezfurlong Wez Furlong 2 years ago
    This script launches IE, makes it visible and then navigates to the PHP home page.
    Let’s assume that we want to make sure that it has fully loaded and rendered before doing something else in our script.
  • + wezfurlong Wez Furlong 2 years ago
    This script is a separate entity from the rest of your site; you should run it using php.exe (the CLI version), and that process will be the only part that talks to MS Word.
    It’s quite a simple script; it creates a server socket and then loops waiting for a client connection; stream_socket_accept() returns a stream that we can use to talk to the client.
    We un-serialize the data into a php variable and pass that into the code that actually generates the doc.
    Once its done, we send back a line of text to the client and close the connection.

    This approach is much simpler to code, and less prone to failure.
    Since the daemon only accepts once connection at a time, one after the other, we’re effectively getting a mutex for free (although sockets cost a bit more resources).

    Shmop might be faster, but this is approach is more reliable.
    You could also place the server on a separate machine and have it generate the docs there.
    Taking this further, you could move your web code over to unix and call out to a windows box (or virtual machine) to generate the office documents.
  • + wezfurlong Wez Furlong 2 years ago
    We’ll run the daemon on the loopback interface (so no external access to it is possible) on TCP port 4000… you can choose any port that doesn’t conflict with other services that you might be running on the machine.

    We’re using stream_socket_client() to connect to the daemon; this is part of the new stream transport subsystem in PHP 5 and gives you more options than the traditional fsockopen() function. You could use fsockopen(); I’m only using stream_socket_client() because the server name is symmetric with the stream_socket_server() call on the next slide; fsockopen() would need two parameters to do the same thing.

    Here we’re assuming that $data is some kind of object or array that contains the information needed to generate the document.
    We serialize it and send the whole thing over the socket to the server process; then we wait for it to complete; we simply wait for it to send a line of output back.
  • + wezfurlong Wez Furlong 2 years ago
    Important points
    You need to ensure that you call drop_mutex() before the request ends, otherwise you lock out other requests (can be solved by restarting the web server)
    We’re not setting the application visible, to save resources.
    We’re not calling $word->Quit(), as we want to keep the application around for the next request
    Readfile represents doing something with the document… $filename is some unique filename

Comments 1 - 10 of 28 previous next

Post a comment
Embed Video
Edit your comment Cancel

4 Favorites & 1 Group

PHP and COM - Presentation Transcript

  1. PHP and COM
    • Wez Furlong < [email_address] >
  2. Plan
    • What is COM?
    • What's it good for?
    • How do I use it?
      • Instantiation... and Monikers
      • Exceptions
      • Typelibraries
      • Variants
      • .Net Interop
      • ActiveScript
      • Persistence (experimental)
  3. 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
  4. 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
  5. 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
  6. What's it good for?
    • Talking to other applications and libraries
    • Most win32 software vendors provide a COM interface
    • Can be used to transition from ASP to PHP
    • Can use “easy” languages to extend PHP
  7. How do I use it?
    • $word = new COM(“Word.Application”); $word->visible = true; $word->Documents->Add(); $word->Selection->TypeText(“hello”); $word->ActiveDocument->SaveAs(“test.doc”); $word->Quit();
  8. Instantiation
    • $word = new COM(“Word.Application”, array( ‘Server’ => ‘otherbox’, ‘Username’ => ‘foo’, ‘Password’ => ‘bar’ ), CP_UTF8);
  9. Exceptions
    • try { $o = new COM(“…”); } catch (com_exception $e) { print “failed to create: $e”; }
    • $e->getCode() corresponds to weird hex number (will show example later)
  10. Typelibraries
    • Import constants from a COM server as regular PHP constants.
    • Manually
      • com_load_typelib(‘Word.Application’);
      • echo wdGoToBookmark;
    • From php.ini:
      • com.typelib_file=C:mytypelibs.txt
  11. Variants
    • PHP COM is really PHP Variant
    • Variant is win32 equivalent of PHP typeless variables
    • JIT conversion in PHP 5
    • OLE default properties
      • $doc = $word->ActiveDocument;
      • print $doc; // prints document title
  12. Variant Arrays
    • $user = new COM( “LDAP://cn=user,ou=test,dc=php,dc=net”);
    • $arr = $user->GetEx(“otherHomePhone”);
    • for ($i = 0; $i < count($arr); $i++) { print $arr[$i] . “ ”; }
  13. Iterators
    • Set domainObject = GetObject(&quot;WinNT://Domain&quot;)
    • For Each obj in domainObject Response.Write obj.Name & &quot;<br />“ Next
    • $domainObject = new COM(&quot;WinNT://Domain&quot;);
    • foreach ($domainObject as $obj) { echo $obj->Name . &quot;<br />&quot;; }
  14. 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
  15. .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() . $stack->pop();
  16. Some Sample Scripts
    • Look at some common tasks implemented in PHP
    • Gotchas?
  17. WMI for system monitoring
    • $wmi = new COM( “WinMgmts:{impersonationLevel=impersonate}” .“//{$hostname}/root/cimv2” );
    • $cpus = $wmi->ExecQuery( &quot;Select * from Win32_Processor&quot;);
    • foreach ($cpus as $cpu) { printf(“%s %dMHz %d%% ”, $cpu->Name, $cpu->MaxClockSpeed, $cpu->LoadPercentage); }
  18. 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->MoveNext(); }
  19. MS Office (Word)
    • $word = new COM(“Word.Application”);
    • $word->visible = true;
    • $word->Documents->Add();
    • $word->Selection->TypeText(“hello ” . $_SESSION[‘username’]);
    • $word->ActiveDocument->SaveAs(“test.doc”);
    • $word->Quit();
  20. 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 win2k and later
  21. 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); }
  22. 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->getCode() == MK_E_UNAVAILABLE) return new COM(‘Word.Application’); throw $e; } }
  23. Shmop mutex 4
    • $mtx = try_mutex(3); if (!$mtx) { .. Try again later … } $word = get_one(); $word->Documents->Add(); $word->Selection->TypeText(“foo”); $word->ActiveDocument->SaveAs($filename); $word->ActiveDocument->Close(); drop_mutex($mtx); readfile($filename);
  24. 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
  25. Client for Word Daemon
    • $daemon = stream_socket_client(‘127.0.0.1:4000’);
    • if ($daemon) {
    • fwrite($daemon, serialize($data));
    • $result = fgets($daemon);
    • }
  26. 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, “DONE ”); fclose($client); }
  27. With Events
    • COM event handling framework is build from ‘Connection Points’
    • A source object is implements IConnectionPointContainer
    • A sink object (callback handler) implements a dispinterface
    • dispinterfaces allow a loose handler implementation; perfect for scripting languages
  28. turning on events
    • bool com_event_sink($object,
    • $sinkobject [, $sinkname]);
    • Plumbs in event handling;
    • Events from $object are sunk into $sinkobject
  29. Sinking events from IE
    • $ie = new COM(&quot;InternetExplorer.Application&quot;);
    • $ie->Visible = true;
    • $ie->Navigate(&quot;http://www.php.net&quot;);
  30. IE Events 2
    • class IEEvents { var $dom = null; function DocumentComplete($dom, $url) { echo “$url complete ”; $this->dom = $dom; } }
  31. IE Events 3
    • $sink = new IEEvents; $ie = new COM(&quot;InternetExplorer.Application&quot;); $ie->Visible = true; com_event_sink($ie, $sink, ‘DWebBrowserEvents2’); $ie->Navigate(&quot;http://www.php.net&quot;); while (!$sink->dom) { com_message_pump(4000); }
    • // we can do stuff with $sink->dom here, or just continue with something else
  32. IActiveScript
    • 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
  33. Invoke JScript from PHP
    • class foo { function bar($msg) { echo $msg; } }
    • $js = new COM(‘ScriptControl’); $js->Language = ‘JScript’; $js->AddObject(‘foo’, new foo, false); $js->AddCode(‘foo.bar(“js!”);’);
  34. ActiveScript
    • This SAPI lets you load PHP into other scripting engines
    • You need to regsvr32 php5activescript.dll to enable it
    • Language = PHPScript
    • Sadly, can't load PHP into PHP via COM due to architecture of PHP SAPI interface
  35. Using PHP in Windows Script Host
    • Create a .wsf file like this:
    • <job id=&quot;test&quot;> <script language=&quot;PHPScript&quot;> $WScript->Echo(&quot;Hello&quot;); </script> </job>
    • cscript test.wsf
  36. 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
  37. Bogus Example
    • $object = new COM(‘…’); $object->doSomething(); $dest = fopen(‘ftp://…/…’, ‘wb’); $p = new COMPersistHelper($object); $p->SaveToStream($dest);
  38. Bogus Example 2
    • $object = new COM(‘…’); $src = fopen(‘ftp://…/…’, ‘rb’); $p = new COMPersistHelper($object); $p->LoadFromStream($src);
    • // $object is now in same state as it was on previous slide
  39. 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/en-us/wmisdk/wmi/wmi_start_page.asp
    • Server-side MS Office: http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757
    • PHP snapshots http://snaps.php.net

+ Wez FurlongWez Furlong, 2 years ago

custom

7782 views, 4 favs, 17 embeds more stats

A discussion of the OLE/COM bridge in PHP 5.
These more

More info about this document

© All Rights Reserved

Go to text version

  • Total Views 7782
    • 7031 on SlideShare
    • 751 from embeds
  • Comments 28
  • Favorites 4
  • Downloads 256
Most viewed embeds
  • 341 views on http://netevil.org
  • 241 views on http://www.phpeye.com
  • 78 views on http://www.planet-php.net
  • 32 views on http://phpeye.com
  • 16 views on http://www.planet-php.org

more

All embeds
  • 341 views on http://netevil.org
  • 241 views on http://www.phpeye.com
  • 78 views on http://www.planet-php.net
  • 32 views on http://phpeye.com
  • 16 views on http://www.planet-php.org
  • 13 views on http://min2liz.net
  • 10 views on http://planet-php.org
  • 8 views on http://www.netevil.org
  • 3 views on http://www.webonorme.net
  • 2 views on http://lj-toys.com
  • 1 views on http://cameleon.mine.nu
  • 1 views on http://planet-php.net
  • 1 views on http://axwl.vicp.cc
  • 1 views on http://64.233.179.104
  • 1 views on http://64.233.169.104
  • 1 views on http://209.85.175.104
  • 1 views on http://100.ig.gmodules.com

less

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

Cancel
File a copyright complaint
Having problems? Go to our helpdesk?

Categories

Groups / Events