PHPのお勉強!

PHP TOP

com クラス

(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)

はじめに

com クラスにより、OLE 互換の COM オブジェクトのインスタンスを作成し、 そのメソッドをコールしたりそのプロパティにアクセスしたりすることが 可能となります。

クラス概要

class com extends variant {
/* メソッド */
public __construct(
    string $module_name,
    array|string|null $server_name = null,
    int $codepage = CP_ACP,
    string $typelib = ""
)
}

Overloaded Methods

返されるオブジェクトは、オーバーロードされたものです。つまり、 PHP 側では通常のクラスのメソッドは見えないということです。 その代わりに、プロパティやメソッドへのアクセスは COM を通じて行います。

参照渡しのパラメータを受け付けるメソッドを PHP が 自動検出するようになりました。それらのメソッドについては、PHP が自動的に 変数を参照渡し形式に変換します。つまり、メソッドのコールをより自然に 行えるということです。コードの中で特別な処理をする必要はありません。

com の例

例1 com の例 (1)

<?php
// word を起動します
$word = new com("word.application") or die("Unable to instantiate Word");
echo
"Loaded Word, version {$word->Version}\n";

// 前面に移動させます
$word->Visible = 1;

// 空のドキュメントを開きます
$word->Documents->Add();

// 何か複雑なことを行います
$word->Selection->TypeText("This is a test...");
$word->Documents[1]->SaveAs("Useless test.doc");

// word を閉じます
$word->Quit();

// オブジェクトを開放します
$word = null;

?>

例2 com の例 (2)

<?php

$conn
= new com("ADODB.Connection") or die("Cannot start ADO");
$conn->Open("Provider=SQLOLEDB; Data Source=localhost;
Initial Catalog=database; User ID=user; Password=password"
);

$rs = $conn->Execute("SELECT * FROM sometable"); // Recordset

$num_columns = $rs->Fields->Count();
echo
$num_columns . "\n";

for (
$i=0; $i < $num_columns; $i++) {
$fld[$i] = $rs->Fields($i);
}

$rowcount = 0;
while (!
$rs->EOF) {
for (
$i=0; $i < $num_columns; $i++) {
echo
$fld[$i]->value . "\t";
}
echo
"\n";
$rowcount++; // increments rowcount
$rs->MoveNext();
}

$rs->Close();
$conn->Close();

$rs = null;
$conn = null;

?>

目次

add a note

User Contributed Notes 36 notes

up
14
tsintra at humansoft dot pt
15 years ago
After one week of trying to understand what was wrong with my PHP communication with MS Word, i finally got it working...
It seems that if you're running IIS, the COM object are invoked with restricted privileges.
If you're having permission problems like not being able to opening or saving a document and you're getting errors like:

- This command is not available because no document is open
or
- Command failed

try this (if you're running IIS):

- Execute "dcomcnfg"
- Open Component Services > Computers > My Computer > DCOM Config
- Search for Microsoft Office Word 97-2003 Document (it will be something like this translated to your language, so take a while and search for it)
- Right-Click on it and open the properties
- Choose "Identity" tab
- Normally this is set to "the launching user". You have to change this to "the interactive user" or a admin user of your choice.
- Apply these new settings and test your COM application. It should work fine now.

I hope I save lots and lots of hours of headaches to some of you :)
up
5
info at ensostudio dot ru
4 years ago
Complete example of using WScript.Shell:
<?php
/**
* Methods & properties
* @link https://msdn.microsoft.com/en-us/library/2f38xsxe(v=vs.84).aspx
*/
$shell = new com('WScript.Shell', null, CP_UTF8);
var_dump($shell->CurrentDirectory);
foreach (
$shell->Environment as $value) {
var_dump($value);
}
// check file 'Test.php'
$process = $shell->Exec('.../php.exe --syntax-check --file=".../src/Test.php"');
// wait complete: 1 - done
while (! $process->Status) {
usleep(5000);
}
// results: -1 - syntax error, 0 - no error
var_dump($process->ExitCode);
// show responce
var_dump($process->StdOut->ReadAll());
// show errors
var_dump($process->StdErr->ReadAll());
?>
up
10
rogier
13 years ago
Took me a while to figure this out by trial and error:

If your frustrated when getting a com-exception like "Error [0x80004002] ..." (with a message nagging you about an unsupported interface), and you're calling a class method through COM that expects a char as an argument, you should NOT call the method with a single-character string.

The correct way of calling a method like this is to use a VARIANT with a type of VT_UI1.

COM enabled method definition:

public bool DoSomething(char arg);

<?php

$com
= new COM('Some.Class.Name');

// This will fail
$var = 'a';
$com->DoSomething($var);

// This works correctly
$var = new VARIANT(ord('a'), VT_UI1);
$com->DoSomething($var);

?>

I hope this helps some people
up
2
yinon at xacct dot com
22 years ago
In order to get the Word exaple running, do the following on the server side.
Worked for me...
1. Click START-->RUN and enter "dcomcnfg"
2. In the "Applications" tab, go down to "Microsoft Word Document"
3. Click PROPERTIES button
4. Go to the "Security" Tab
5. Click "Use custom access permissions", and then click EDIT
6. Click ADD and then click SHOW USERS
7. Highlight the IIS anonymous user account (usually IUSR_<machinename>), click ADD
8. Go back to the "Security" tab by hitting OK
9. Click "Use custom launch permissions", and the click EDIT
10. Click ADD and then click SHOW USERS
11. Highlight the IIS anonymous user account (usually IUSR_<machinename>), click ADD
12. Hit OK, and then hit APPLY.

Also, you should look at the "Identity" tab in the Microsoft Word Document PROPERTIES and see that it is set to "Interactive User"


ALSO, log into the machine AS the IUSR_<machinename> account, start word, and make sure to click through the dialog boxes that Word shows the first time it is run for a certain user. In other words, make sure Word opens cleanly for the IUSR_ user.

More useful information could be found here:
http://www.email-screen.com/support-doc2txt.html
up
4
mbirth at webwriters dot de
16 years ago
Using the DynamicWrapper from http://freenet-homepage.de/gborn/WSHBazaar/WSHDynaCall.htm and after registering it via "regsvr32 dynwrap.dll", you can easily set output colors to make colorful CLI scripts even on Windows.

<?php

$dw
= new COM('DynamicWrapper'); // needs dynwrap.dll (regsvr32 dynwrap.dll)

// register needed features
$dw->Register('kernel32.dll', 'GetStdHandle', 'i=h', 'f=s', 'r=l');
$dw->Register('kernel32.dll', 'SetConsoleTextAttribute', 'i=hl', 'f=s', 'r=t');
$dw->Register('kernel32.dll', 'SetConsoleTitle', 'i=s', 'f=s', 'r=l');

// get console handle
$ch = self::$dw->GetStdHandle(-11); // -11 = STD_OUTPUT_HANDLE

?>

After these initialization steps, you can set the console output color using:

<?php
$dw
->SetConsoleTextAttribute($ch, 14);
echo
'This is yellow text!';
$dw->SetConsoleTextAttribute($ch, 7);
echo
'Back to normal gray!';
?>

Using SetConsoleTitle you can even set the title displayed in the console window.

Color values are 0..7 for dark colors and 8..15 for light colors. Sequence is (black/silver, blue, green, cyan, red, magenta, yellow/brown, white/gray). I also found that if you add 16384 to the value, it should be inverse. 32768 added should get underlined text. But these latter two didn't work for me.
up
2
mastrboy.servebeer.com
16 years ago
quick wmi query example:

<?php
$obj
= new COM ( 'winmgmts://localhost/root/CIMV2' );
$wmi_computersystem = $obj->ExecQuery("Select * from Win32_ComputerSystem");
$wmi_bios = $obj->ExecQuery("Select * from Win32_BIOS");
foreach (
$wmi_computersystem as $wmi_call )
{
$model = $wmi_call->Model;
}

foreach (
$wmi_bios as $wmi_call )
{
$serial = $wmi_call->SerialNumber;
$bios_version = $wmi_call->SMBIOSBIOSVersion;
}
echo
"Bios version : $bios_version\n".
"Serial number : $serial\n".
"Hardware Model : $model\n";
?>
up
2
halfer
17 years ago
Thanks to paul at completewebservices who added a note earlier; I have used his code to solve a particularly difficult issue with the Crystal 9 runtime component. For some reason, VBA/VBS can pass a native Date type as a parameter to a Crystal Report requiring a date, but in PHP I've tried all manner of strings, unix timestamps, COM variant dates etc and all of these resulted in a com_exception.

My solution was to employ VBScript to borrow the CDate function, which works correctly. Not the most elegant of solutions, but this parameterised approach is to be preferred to search-n-replacing the RecordSelectionFormula string. Of course if anyone here has an even better approach, do post it here - I am sure it would be of use.

<?php
// $rptParam is a report parameter object having a type of date
$oScript = new COM("MSScriptControl.ScriptControl");
$oScript->Language = "VBScript";
$oScript->AllowUI = false;
$oScript->AddObject('rptParam', $rptParam, true);
$oScript->AddCode('Function SetDateParameter(strDate)
rptParam.AddCurrentValue(CDate(strDate))
End Function'
);
$oScript->Run("SetDateParameter", "25 April 2006");
?>
up
3
z3n at overflow dot biz
15 years ago
On a query reply using ADODB.Connection object, all my $rs->Fields['field_name']->Value returned `variable Object` when inserted into a array, like this:

<?php
for ($rl[$v]=array(),_qm($_query);!$res->EOF;$res->MoveNext()) {
$rl[$v][]=$res->Fields['x']->Value;
}
?>

I figured out that converting the value into a INT fixed the issue:

<?php $rl[$v][]=intval($res->Fields['x']->Value); ?>
up
1
james dot m dot love at gmail dot com
15 years ago
If you're using COM to create a DSN Less connection to an MS Access 2007 database, you'll find through Googling that you need to use an updated version of Jet, so the connection string I've found looks like this:

<?php
$databaselocation
= "C:\Path\to\db.accdb";
$conn = new COM('ADODB.Connection') or exit('Cannot start ADO.');
$conn->Open("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=$databaselocation") or die('Cannot start with Jet');
?>

However, on my setup (WinVista, Access 2007, PHP526) I found that it always 'dies' with "Cannot start with Jet", even if the connection was successful ($conn->State reads "1").

I figured to just drop the die() command on $conn->Open(). If something catastrophic happens with the ADO connection then it's own error handling engine passes stack traces, etc back to the console/standard output.

Therefore, my Open() command looks like this:

<?php
$conn
->Open("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=$databaselocation");
?>
up
1
csaba at alum dot mit dot edu
19 years ago
Getting IE to the foreground
If you are using a command line (CLI) version of PHP on a Win32 platform (e.g. XP Pro, SP2), you might want to have output directed to IE (perhaps you'll want to work with the output there) when Popup does not suffice (see my earlier post, below).

It's easy enough to get an instance of IE using $ie = new COM("InternetExplorer.Application");. The problem is, you don't necessarily see it in the foreground (especially if you already have one open) and who wants to waste keystrokes getting to it? The code below has been working for me (If you want to do other adjustments (e.g. $ie->Document->ParentWindow->resizeTo(800,500); or $ie->Document->Body->bgColor = "yellow";), doing them before the $ie->Visible = true; line will avoid screen distractions):

<?php
function newIEtoForeground($title, $evtPrefix="") {
// brings new instance of IE to foreground with title $title
if (!$extPrefix) $ie = new COM("InternetExplorer.Application");
else
$ie = new COM("InternetExplorer.Application", $evtPrefix);
$ie->Navigate2("about:blank");
$oWSH = new COM("WScript.Shell");
while (
$ie->ReadyState!=4) usleep(10000);

$ie->Document->Title = ($tmpTitle = mt_rand()); //unique title
$ie->Visible = true;
while (!
$oWSH->AppActivate("$tmpTitle - M")) usleep(10000);

$ie->Document->Title = $title;
$ie->Document->ParentWindow->opener="me"; // allows self.close()
return $ie;
}
?>

Csaba Gabor from Vienna
up
1
rickardsjoquist at hotmail dot com
21 years ago
If you want to use a DSN-less connection to a database (access for example) and return the results of a query as a multidimensional array with the fieldnames as identifier try this. Hope it helps someone :-)
--------------------------------------------------------

<?php
function db($sql) {
$c = new COM("ADODB.Connection");
$c->open('DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=' . realpath("relative_path/db.mdb"));
$r = $c->execute($sql);
$i = 0;
$num_fields = $r->fields->count();
while (!
$r->EOF)
{
for(
$j = 0;$j<$num_fields;$j++) {
$key = $r->Fields($j);
$r_items[$i][$key->name] = $key->value;
}
$i++;
$r->MoveNext();
}
$r->close();
$c->close();
$r = null;
$c = null;
return
$r_items;
}
?>

--------------------------------------------------------
use it like this:
--------------------------------------------------------
<?php
$results
= db("SELECT field_a, field_b FROM table");
foreach(
$result as $i => $item) {
echo
$item['field_a'];
echo
$item['field_b'];
}
?>
--------------------------------------------------------
You can also use: print_r($result); if you want the structure of the array to be printed.
up
2
sparrowstail at googlemail dot com
14 years ago
This script reports all Windows drives, drive type, status (if not available), free space and total drive size:

<?php

$fso
= new COM('Scripting.FileSystemObject');
$D = $fso->Drives;
$type = array("Unknown","Removable","Fixed","Network","CD-ROM","RAM Disk");
foreach(
$D as $d ){
$dO = $fso->GetDrive($d);
$s = "";
if(
$dO->DriveType == 3){
$n = $dO->Sharename;
}else if(
$dO->IsReady){
$n = $dO->VolumeName;
$s = file_size($dO->FreeSpace) . " free of: " . file_size($dO->TotalSize);
}else{
$n = "[Drive not ready]";
}
echo
"Drive " . $dO->DriveLetter . ": - " . $type[$dO->DriveType] . " - " . $n . " - " . $s . "<br>";

}

function
file_size($size)
{
$filesizename = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
return
$size ? round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . $filesizename[$i] : '0 Bytes';
}

?>

There are a number of other properties of the drive object which can be called this way - see:

http://msdn.microsoft.com/en-us/library/ts2t8ybh%28VS.85%29.aspx
up
3
juan156_elias at gmail dot com
9 years ago
This is an example of using .Net using the NetPhp library that is based on the COM/DOTNET classes.

You can use any .dll file, wether it is or not COM decorated and any of the .Net framework types out of the box. You can also target any version of the .Net framework.

<?php

$runtime
= new \NetPhp\Core\NetPhpRuntime('COM', 'netutilities.NetPhpRuntime');

// Add both SpreadsheetLight and the OpenXML it depends on.
$runtime->RegisterAssemblyFromFile('/binaries/SpreadsheetLight.dll', 'SpreadsheetLight');
$runtime->RegisterAssemblyFromFile('/binaries/DocumentFormat.OpenXml.dll', 'DocumentFormat.OpenXml');
$runtime->RegisterAssemblyFromFile('/binaries/AjaxMin.dll', 'AjaxMin');

// Using the FullName of a type that belongs to an assembly that has already been registered.
$datetime = $runtime->TypeFromName("System.DateTime");

// Using the FullName of a type that has not been registered yet (from a file)
$minifier = $runtime->TypeFromFile("Microsoft.Ajax.Utilities.Minifier", APPLICATION_ROOT . '/binaries/AjaxMin.dll');

// Using the FullName of a type that has not been registered yet (autodiscoverable)
$datetime2 = $runtime->TypeFromAssembly("System.DateTime", "mscorlib, ....");

$datetime->Instantiate();
echo
$datetime->ToShortDateString()->Val(); // Outputs 01/01/0001

// We can only use Int32 from native PHP, so parse
// an Int64 that is equivalent to (long) in the DateTime constructor.
$ticks = $runtime->TypeFromName("System.Int64")->Parse('98566569856565656');

$datetime->Instantiate($ticks);
echo
$datetime->ToShortDateString()->Val(); // Outputs 07/05/0313

// We can only use Int32 from native PHP, so parse
// an Int64 that is equivalent to (long) in the DateTime constructor.
$ticks = $runtime->TypeFromName("System.Int64")->Parse('98566569856565656');

// Dump a .Net System.Timers.Timer object!
$data = $timer->GetPhpFromJson();

var_dump($data);

// Outputs:
// object(stdClass)[38]
// public 'AutoReset' => boolean true
// public 'Enabled' => boolean false
// public 'Interval' => int 100
// public 'Site' => null
// public 'SynchronizingObject' => null
// public 'Container' => null

// Check if today is monday
$IsMonday = $runtime->TypeFromName("System.DateTime")->Now->DayOfWeek->
Equals($runtime->TypeFromName("System.DayOfWeek")->Enum('Monday'));

?>
up
2
paul at completewebservices dot com dot au
18 years ago
It seems that PHP does not support setting of properties with arguments. This is how I got around the problem:

// Object with method I want to set
$auth = new COM("AUTHXOCX.AuthXOCXCtrl.1");

// ScriptControl
$oScript = new COM("MSScriptControl.ScriptControl");
$oScript->Language = "VBScript";
$oScript->AllowUI = TRUE;

// Add out object to the control
$oScript->AddObject('auth', $auth, true);

// Create a VBScript function that allow me to set them
$oScript->AddCode(
'Function fixAccess(accessname)
auth.AuthDataReferrerEnabled(accessname) = 1
auth.AuthDataAuthentiXDBEnabled(accessname) = 0
End Function');

// Execute function
$oScript->Run("fixAccess", $dir);
up
2
csaba at alum dot mit dot edu
19 years ago
Basic Windows IO
If you are using a command line (CLI) version of PHP on a Win32 platform, you might like to have a simple graphical interface to get input and output. The following gives an illustration for both.

<?php
// first we get some input
$oScript = new COM("MSScriptControl.ScriptControl");
$oScript->Language = "VBScript";
$title = "I/O Demo: Input half";
$initial = "Change this value";
$prompt = "Please enter a value";

$code = <<<EOF
Function getInput()
inVal = InputBox("
$prompt", "$title", "$initial")
getInput = inVal 'how return values are assigned in VB
End Function
EOF;

$oScript->AddCode($code);
$input = $oScript->Eval("getInput()");
if (
gettype($input)=="NULL") $input = "Input box was cancelled";

// now we show some output
$oWSH = new COM("WScript.Shell");
$title = "I/O Demo: Output half";
$timeout = 2; // 0 for no timeout
$style = 0 + 48; // buttons to show + alert symbol
$oWSH->Popup($input, $timeout, $title, $style);
?>

This is example is overblown for illustrative purposes. The whole input part collapses if the amount of code used is a single statement. So, this would have sufficed:
$code = "InputBox(\"$prompt\", \"$title\", \"$initial\")";
$input = $oScript->Eval($code);

This technique exposes quite a bit of scripting power tied into the Windows operating system and VBScript. However, you should have a really specific reason for using it since VBScript tends to be dog slow when compared to PHP in my tests. Simple IO like this is good, however, and the popup size can be quite large. Furthermore, this could be a viable route to go for accessing WinAPI's.

http://www.ss64.com/wsh/popup.html shows some documentation for $oWSH->Popup

Csaba Gabor from Vienna
up
2
casanoteva at yahoo dot com
15 years ago
Hi, just wanna share to everyone after tried and tested many many times to create report in PDF format from Crystal Report.
Finally I can do it without any error.
Here is my system; PHP 5.1.6, MSSQL2005 and Crystal Report Server XI RL2

<?php

//- Variables - for your RPT and PDF
echo "Print Report Test";
$my_report = "D:\\Folder1\\SubFolder1\\Report.rpt"; //
rpt source file
$my_pdf
= "D:\\Folder1\\SubFolder1\\Report.pdf"; // RPT export to pdf file
//-Create new COM object-depends on your Crystal Report version
$ObjectFactory= new COM("CrystalReports115.ObjectFactory.1") or die ("Error on load"); // call COM port
$crapp = $ObjectFactory-> CreateObject("CrystalDesignRunTime.Application"); // create an instance for Crystal
$creport = $crapp->OpenReport($my_report, 1); // call rpt report

// to refresh data before

//- Set database logon info - must have
$creport->Database->Tables(1)->SetLogOnInfo("servername", "DBname", "user", "password");

//- field prompt or else report will hang - to get through
$creport->EnableParameterPrompting = 0;

//- DiscardSavedData - to refresh then read records
$creport->DiscardSavedData;
$creport->ReadRecords();


//export to PDF process
$creport->ExportOptions->DiskFileName=$my_pdf; //export to pdf
$creport->ExportOptions->PDFExportAllPages=true;
$creport->ExportOptions->DestinationType=1; // export to file
$creport->ExportOptions->FormatType=31; // PDF type
$creport->Export(false);

//------ Release the variables ------
$creport = null;
$crapp = null;
$ObjectFactory = null;

//------ Embed the report in the webpage ------
print "<embed src=\"D:\\Folder1\\SubFolder1\\Report.pdf\" width=\"100%\" height=\"100%\">"



?>

That's all for me, anyway in Crystal Report I have to check DisCardSavedData, Save data with report and AutoSave (1 min) in Option Tab and also in Report Options I have to check save dat with report, too.

Hope this should be help to anybody

Casanoteva
up
1
pavanphp Gudipati
15 years ago
Here I Am describing a Program from which you can connect any exe(software) using COM component.
pdf2swf is a software for converting PDf to SWF files.

This is best example for WScript.Shell

<?php
#code for pdf to swf using pdf2swf software
#this codeworks in windows environment.


## Important Parameters
$software_path ="C:\\SWFTools\\pdf2swf" ;
$pdf_path ="C:\\SWFTools\\abcd.pdf" ;
$argument = "-o";
$swf_output ="C:\\SWFTools\\abcd.swf" ;



#actual code
$cmd =" $software_path $pdf_path $argument $swf_output";

$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C $cmd ", 0, true);

# 0 for command prompt invisible mode
# 3 for visible

?>
up
1
volker at kybs dot de
19 years ago
To use the windows speech system install the "Speech SDK 5.1 for Windows? applications" from the Microsoft homepage (free download).
Then you can do Text2Speech like this:

$voice = new COM("SAPI.SpVoice");
$voice->Speak("Hello, lets have a conversation");
up
1
deletethis@bjoern(at)syltonline(doot)de
19 years ago
If you can get the old "TaskScheduler.dll" and register it, it is quite simple to handle and start Windows tasks from PHP.
This is extremely useful when you got things to do which must be run in a different user context. Prepare a task with the user and use PHP & Com to build a webinterface for it.

Here is an example how to start a Windows task:

function start_task ($taskname) {
$SchedObj = new COM("Scheduler.SchedulingAgent.1");
foreach ($SchedObj->Tasks as $task) {
if (strtolower( (string) $task) == strtolower( $taskname.".job" )) {
$task->Run();
}
}
}

I'm also working on a class to handle infos, adding and removing of tasks via PHP. If you are interested drop me a line.