Access the Windows Registry with PHP

Have you ever woken up in the morning and thought to yourself, “I want to do something crazy today?” Well, if today was one of those mornings then you’re in luck. I’d like to give you a little introduction on accessing the Windows Registry using PHP. PHP… the Registry… CRAZY!

The Windows Registry is simply a hierarchically structured database in which the Windows operating system and other applications store important configuration information. All sorts of data is stored in the registry: user profiles, file-type associations, hardware information, serial numbers, and more. With functions available from the win32std extension, your Windows-based PHP applications can access the registry too.

The win32std extension can be downloaded as a pre-compiled library from downloads.php.net/pierre/. Simply drop it into your PHP’s ext folder, update your php.ini file, and restart Apache if necessary. Note that right now the DLLs you’d download are 32-bit, so if you’re using a 64-bit build of WampServer or such then you won’t have much success. You’ll have to either downgrade WampServer to a 32-bit build or try compiling the library yourself.

The Registry Layout

The registry has a reputation of being a dark, dangerous and scary place in the Windows operating system. This is probably an over exaggerated fear, but still I’ll reiterate Microsoft’s registry mantra: “Before you modify the registry, back it up and make sure you understand how to restore it if a problem occurs. Improper changes could cause serious problems that may require you to reinstall your operating system.”

So what does this dark, scary place look like? The Windows Registry is divided up into 5 main groups known as keys:

HKEY_CURRENT_CONFIG
This key stores information about the computer’s hardware such as monitor resolution and speaker settings. You may see this key abbreviated as HKCC.

HKEY_LOCAL_MACHINE
This key contains configuration information for the machine such as printers, software and networking information. The key is loaded first and then entries from the user’s profile override various values. You’ll see this key abbreviated as HKLM.

HKEY_USERS
This key holds all the profiles for the local user accounts on the machine. Such things as the user’s screensaver selection, theme information and other preferences are stored here. This key is abbreviated as HKU.

HKEY_CLASSES_ROOT
This key is an alias pointing to HKEY_LOCAL_MACHINESoftware which stores information about file associations and mime-types. The abbreviation is HKCR.

HKEY_CURRENT_USER
This key is an alias pointing to the profile in HKEY_USERS for the currently logged in user. You’ll see this key abbreviated as HKCU.

Each key contains subkeys which in turn contain other subkeys, configuration values, or both.

Working under HKEY_CURRENT_USER is sufficient for playing around with a few CLI scripts and a sandbox. Only use HKEY_LOCAL_MACHINE for system-wide application data and situations where you are comfortable working with Microsoft’s security permissions. Understand what is right for your situation, know under which account PHP runs, and create your keys appropriately.

Making a Sandbox

I recommend setting up a special key for use in your scripts for the sake of safety, especially when you’re developing. To err is human and we don’t want to accidentally overwrite anything important. Organization is another reason for setting up a designated key. There’s a lot of information stored in the registry and we want to be able to locate our own values easily.

Registry Editor is a Microsoft program used to view and edit the registry. To create our sandbox, go to Start, type “regedit” in the search bar, and select regedit.exe in the results list that appears.

The left pane shows a tree structure of the existing keys while the right pane shows values stored within them. Expand the HKEY_CURRENT_USER node, right-click on the Software key and select New > Key from the popup context menu. Alternatively, we could have also traversed through the tree using the arrow keys so that the Software key is highlighted and select New > Key from the Edit menu. Supply a name for the key and press enter.

Now that we have a place to play, allow me to introduce you to the functions that win32std offers to manipulate registry entries.

Reading from the Registry

The reg_open_key() function opens a connection to the registry and returns a resource. This resource is then used with other registry functions to act on that connection. The reg_close_key() function closes the connection.

reg_open_key() takes two arguments: first a predefined constant representing one of the five primary registry groups, then the remainder of the path to the desired key.

<?php
$keyConst = HKEY_CURRENT_USER;

// backslash is used as an escape so it must be escaped itself
$key = "Software\Intel";

// open the registry key HKCUSoftwareIntel
if (!($reg = @reg_open_key($keyConst, $key))) {
    throw new Exception("Cannot access registry.");
}
...

reg_close_key($reg);

Now that you have an open connection, you can retrieve information from the registry using the reg_enum_key(), reg_enum_value() and reg_get_value() functions.

If just the resource is passed to reg_enum_key() then it will return an array of subkeys under the current key. An integer value can also be passed to retrieve the subkey at a particular index.

<?php
// retrieve an array of subkeys under the current key
$subkeys = reg_enum_key($reg);
foreach ($subkeys as $index => $subkey) {
    echo "The subkey at " . $index . " is " . $subkey . "n";
}

// retrieve a specific subkey
$index = 2;
$subkey = reg_enum_key($reg, $index);
echo "The subkey at " . $index . " is " . $subkey . "n";

As reg_enum_key() returns keys, reg_enum_value() returns the values of the keys. The function accepts the resource and an optional index. The value name can be passed to reg_get_value() to retrieve the value’s value (isn’t that a mouthful!).

<?php
// retrieve an array of values under a given key
$values = reg_enum_value($reg);
foreach ($values as $index => $value) {
    echo "The value at " . $index . " is " . $value . " and stores ";
    echo reg_get_value($reg, $value) . "n";
}

// retrieve a specific value given the index
$index = 1;
$value = reg_enum_value($reg, $index);
echo "The value at " . $index . " is " . $value . " and stores ";
echo reg_get_value($reg, $value) . "n";

Writing to the Registry

There are a handful of data types you can choose from when reading from and writing to the registry. They’re generally of little consequence because of PHP’s dynamic nature but you do have to specify the type when you write a value. Most of the time you’ll find yourself using REG_SZ or REG_DWORD, but here’s a list of the data types exposed By the extension:

  • REG_DWORD – value is stored as a 32-bit long integer
  • REG_SZ – value is stored as a fixed-length string
  • REG_EXPAND_SZ – value is stored as a variable-length string
  • REG_MULTI_SZ – value is a list of items separated by a delimiter such as a space or comma
  • REG_BINARY – value is a binary string
  • REG_NONE – value has no particular data type associated with it

The reg_set_value() function is used to write a value to the registry. If the value already exists then the new value will overwrite it, but if it doesn’t exist then it will create it. The function takes four arguments: first the open resource, then the name of the value, then a predefined constant representing the value’s data type and finally the data itself.

<?php
$keyConst = HKEY_CURRENT_USER;
$key = "Software\SitePoint";
if (!($reg = @reg_open_key($keyConst, $key))) {
    throw new Exception("Cannot access registry.");
}

$values = array(
    array("dbDriver", REG_SZ,    "mssql"),
    array("dbHost",   REG_SZ,    "localhost"),
    array("dbPort",   REG_DWORD, 1433),
    array("dbSchema", REG_SZ,    "MyAppDB"),
    array("dbUser",   REG_SZ,    "DBUser"),
    array("dbPass",   REG_SZ,    "s3cr3t"));

foreach ($values as $value) {
    reg_set_value($reg, $value[0], $value[1], $value[2]);
}

reg_close_key($reg);

An Example – USB Drive Dongle

You might be wondering if there’s a practical use for working with the Registry. In a web-based application, you could store your configuration information in the registry. If you’ve written a desktop application then the registry could be a good place to store all sorts of information from application data to user preferences. Windows itself writes all sorts of interesting hardware and state related information to the registry, and some of it could be useful if you’re creative enough.

Suppose our PHP application has been licensed in such a way that a USB dongle is required to be attached to the server to run it. How can PHP detect the presence of the dongle? The answer on Windows lies in the Registry! Each device has a unique identifier, and so the script can search the appropriate keys for the identifier when it starts up to determine whether the dongle is plugged in or not.

The first step is to determine the identifier of the device. For this example I’ll use a commodity thumbdrive. Simply plug the drive into a USB port on the computer, and then go to Start, type “device” in the search bar, and select Device Manager in the results list that appears.

Find the device in Device Manager, right click the entry, and select Properties from the context menu. Then go to the Details tab of the Properties window and select “Device Instance Path” from the drop down list. The sequence of the hexadecimal numbers towards the end of the value is the device id (marked in red).

Windows records the presence of USB devices under various subkeys of HKEY_LOCAL_MACHINESystemCurrentControlSetServices. Storage media like my thumbdrive will appear under USBSTOR; other devices may appear under usbaudio, usbccgp, and usbehci. Also, note that HKEY_LOCAL_MACHINE will be accessibly only be privileged accounts.

So now we can simply search the key’s Enum subkey for the device instance. When the drive is attached it will be listed, and when it’s not attached it won’t be listed.

<?php
// device instance ID
$id = "0060E049DF74EC311000711F";

// WARNING: must run with administrative privs to access these keys
$keyConst = HKEY_LOCAL_MACHINE;
$key = "SYSTEM\CurrentControlSet\services\USBSTOR\Enum";

if (!($reg = reg_open_key($keyConst, $key))) {
    throw new Exception("Cannot access registry.");
}

$found = false;
$numDevices = reg_get_value($reg, "Count");
for ($i = 0; $i < $numDevices; $i++) {
    $value = reg_get_value($reg, $i);
    if (strpos($val, $id) !== false) {
        $found = true;
        break;
    }
}    
reg_close_key($reg);

echo "USB drive dongle ", ($found) ? "found" : "not found";

This simple check also opens up some other interesting possibilities; you could easily code a sensitive admin-only interface which verifies the dongle and the request is sent from the server itself by checking $_SERVER["REMOTE_ADDR"]. This set up would require the user to be physically at the designated server and provide a form of physical authentication.

In Conclusion

Throughout the course of this article we’ve seen what the Windows Registry is and a small sample of what information can be found in it. You can write your own configuration data, or you can read back information, using the functions provided by the win32std extension.

By the way, the win32std extension offers more than just access to the registry. If you’re interested, check out wildphp.free.fr/wiki/doku.php?id=win32std:index to see what else it offers.

Image via Fotolia

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Alex Fraundorf

    Very cool article Tim. It’s always fun to see practical examples of how powerful and flexible PHP really is.

  • Tom Lankhorst

    A-ma-zing, it’s a real interesting method of sharing data between web services and other Windows applications. This method kills the platform independence of PHP but that should not be any problem for applications under controlled circumstances like in a self-hosted virtual machine or so.

  • Lekshmana Perumal M

    sir,

    one doubt in php.ini file which place update this win32std extension.Please any one help me..

    • http://www.blogaddition.com Manish

      find the line ‘;extension=php_bz2.dll’ in php.ini and just put an another line ‘extension=php_win32std.dll’ below this. But make sure that you have put the file php_win32std.dll in your php/ext folder.

  • victor

    This was amazing, but is there any way to apply this to the server, i mean code on server will work only if there is an usb attached to it(the server)?