Introduction
On occasion you might need to gain greater access from PHP to the underlying Operating System. This article demonstrates the basic steps of one technique for the mentioned purpose by creating
an ATL COM DLL, registering it, and finally invoking it through PHP hosted in the Windows environment running the Apache web server.
Requirements
The requirements list the software used to create and test the demo, and do not necessarily exclude other versions of the same software unless specifically noted.
- Windows XP Professional
- Apache 2.0.54 web server
- PHP 5.2.6. (in prior versions, an access violation in oleaut32.dll was triggered)
- Visual Studio .NET Professional
Create the ATL COM DLL
In the following steps, we will create an ATL COM DLL with a class and two member methods, one that will retrieve the approximate percentage of physical memory in
use, and the second one that will restart the host computer.
- Start Visual Studio .NET
- Start a "New Project"
- Select "Visual C++ Projects"
- Select "ATL Project"
- Click "OK"
- Name the project "ATLDemo"
- Click "OK"
- As the default option is "Dynamic-link library (DLL)", click "Finish"
Visual Studio .NET will now generate the project and we are ready to proceed.
- Right-click on the project name
- Go to the "Add" option
- Select "Add Class…"
- Select "ATL Simple Object"
- Click "Open"
- Enter "MyClass" for the short name
- Click "Finish" as we will accept all the default options
Our new class has now been added and you might notice the system has also generated an Interface class for us, in this case named IMyClass
. As the next step, we will add our
two member methods by following the steps below:
- Right-click on the interface class named "
IMyClass
"
- Go to "Add"
- Select "Add Method"
- Enter
GetMemoryLoad
for the method name
- Check the "in" checkbox under the "Parameter attributes" section
- Select
VARIANT*
for the parameter type
- Name the parameter "
vtMemoryLoad
"
- Click "Add"
- Click "Finish"
The new member method has now been added and as the next step, we will add code to it:
STDMETHODIMP CMyClass::GetMemoryLoad(VARIANT* vtMemoryLoad)
{
MEMORYSTATUSEX memstatex;
memstatex.dwLength = sizeof(memstatex);
::GlobalMemoryStatusEx(&memstatex);
vtMemoryLoad->ulVal = memstatex.dwMemoryLoad;
return S_OK;
}
We will now repeat steps 1-9 in order to add the second function as part of this demo.
- Right-click on the Interface class named "
IMyClass
"
- Go to "Add"
- Select "Add Method"
- Enter
RestartHost
for the method name
- Check the "in" checkbox under the "Parameter attributes" section
- Select
VARIANT*
for the parameter type
- Name the parameter "
vtLastError
"
- Click "Add"
- Click "Finish"
Add the following code to the new function:
STDMETHODIMP CMyClass::RestartHost(VARIANT* vtLastError)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if(::OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
if(::GetLastError() == ERROR_SUCCESS) {
::InitiateSystemShutdown(NULL, _T("ATL COM DLL/PHP Demo"), 0, TRUE, TRUE);
}
}
vtLastError->ulVal = ::GetLastError();
return S_OK;
}
As the next step, we will compile the DLL. By default, a project remains in Debug mode and after a successful compilation and thorough testing, we can switch
it to the Release mode before deploying the DLL. We will do so immediately for the purpose of this demo:
- Click on "Project" on the menu
- Click "ATLDemo Properties"
- Change the "Configuration:" option to "Release"
- Click "OK"
- Click "Build" on the menu
- Click "Rebuild Solution"
This concludes the process of creating our sample ATL COM DLL.
Registering the ATL COM DLL
Now that we have created the ATL COM DLL, the next step will be to register it so that it is available for use by other applications through the COM interface.
- Locate the DLL by browsing to the "Release" directory of the project, or by searching for the DLL, in this case, by its name "ATLDemo.dll"
- Move the DLL to its final destination, in this case, we will place the DLL into the "C:\WINDOWS\system32" directory
- Register the DLL through the command line by calling the REGSVR32 utility:
- Click "Start"
- Click "Run"
- Enter "CMD"
- In the command line prompt, enter: REGSVR32 "C:\WINDOWS\system32\ATLDemo.dll"
- You should see a message box informing you that the registration has been successful
This concludes registering our sample ATL COM DLL and making it available for use by COM aware applications.
Invoking the ATL COM DLL through PHP
In this section of the article, we will write a PHP page that will invoke our newly created ATL COM DLL and make use of it. Please note that at this
point, it is assumed that you have an Apache web server running in the Windows environment. In this demo, the Apache web server is run as an executable under an
account that has full administrator privileges. Security settings might present an obstacle depending on your configuration of the web server, e.g., if you are running
the Apache web server as a service under an account with insufficient privileges, to be able to create a COM object, you would have to adjust the privileges for that account.
The same applies to running IIS instead of Apache; however, as this is a simple concept article, the security settings will not be discussed in detail.
PHP for Windows in its core features the ability to invoke COM objects. For details, please see http://us.php.net/com.
Our first step will be to identify the ProgID
for our class in order to be able to instantiate the instance of the class; the easiest technique will be by accessing the
Registry and learning the value:
- Click "Start"
- Click "Run"
- Enter REGEDIT
- Click "OK"
- Under the
HKEY_CLASSES_ROOT
, locate the name of the DLL
- The value has been found and identified as
ATLDemo.MyClass
Next, we will write the PHP code that will create an instance of the class, immediately display the approximate percentage of the available physical memory, and
offer the ability to restart the host computer.
<?php
$obj = new COM("ATLDemo.MyClass");
$vtMemoryLoad = new VARIANT(0, VT_UI4);
$obj->GetMemoryLoad($vtMemoryLoad);
print '<p>Physical memory in use : '.$vtMemoryLoad.'%</p>';
if($_POST['btnRestart']) {
$vtLastError = new VARIANT(0, VT_UI4);
$obj->RestartHost($vtLastError);
print '<p>Initiated host restart...</p>';
print '<p>Last Error Code: '.$vtLastError.'</p>';
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
<input type="submit" value="Restart Host"
name="btnRestart" id="btnRestart" />
</form>
- Save the file as "index.php" in a new web server directory
- Run it through the browser
- Notice the memory use value, subsequent calls to the page will change the output depending on use
- Click the "Restart Host" button to restart the computer (Note: Please save any pending work before testing)
Conclusion
Thank you very much for reading this article. I hope the article or at least some aspects of it might be useful to you. Constructive criticism is appreciated and
will be taken into consideration.