我想用我的
PHP后端执行一个C程序. C程序负责从我的PC上删除usb棒等usb设备.当我使用CLI打开程序(位于单独的本地驱动器上)而没有管理权限时,程序将启动并正确完成作业.
当我用PHP启动程序时使用exec(“/ path / to / my / program.exe and-parameters”),这与CLI的方式完全相同,程序只是启动并返回“失败”,所以有些不同使用CLI时.
C代码:
// // RemoveDriveByLetter.cpp by Uwe Sieber - www.uwe-sieber.de // // Simple demonstration how to prepare a disk drive for save removal // // Works with removable and fixed drives under W2K,XP,W2K3,Vista // // Console application - expects the drive letter of the drive to remove as parameter // // you are free to use this code in your projects // #include "stdafx.h" #include <stdio.h> #include <windows.h> #include <Setupapi.h> #include <winioctl.h> #include <winioctl.h> #include <cfgmgr32.h> #include <string> //------------------------------------------------- DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber,UINT DriveType,char* szDosDeviceName); //------------------------------------------------- //------------------------------------------------- int main(int argc,char* argv[]) { /*if ( argc != 2 ) { return 1; }*/ char DriveLetter = argv[1][0]; DriveLetter &= ~0x20; // uppercase if ( DriveLetter < 'A' || DriveLetter > 'Z' ) { return 1; } std::string path = ""; path += DriveLetter; path.append(":\\"); printf(path.c_str()); char szRootPath[sizeof(path)] =""; strncpy(szRootPath,path.c_str(),sizeof(path)); std::string device = ""; device += DriveLetter; device.append(":"); printf(device.c_str()); char szDevicePath[sizeof(device)] = ""; strncpy(szDevicePath,device.c_str(),sizeof(device)); std::string accesspath = ""; accesspath += "\\\\.\\"; accesspath += device; printf(accesspath.c_str()); char szVolumeAccessPath[sizeof(accesspath)] = ""; // "\\.\X:" -> to open the volume strncpy(szVolumeAccessPath,accesspath.c_str(),sizeof(accesspath)); long DeviceNumber = -1; // open the storage volume HANDLE hVolume = CreateFile(szVolumeAccessPath,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,NULL); if (hVolume == INVALID_HANDLE_VALUE) { return 1; } // get the volume's device number STORAGE_DEVICE_NUMBER sdn; DWORD dwBytesReturned = 0; long res = DeviceIoControl(hVolume,IOCTL_STORAGE_GET_DEVICE_NUMBER,&sdn,sizeof(sdn),&dwBytesReturned,NULL); if ( res ) { DeviceNumber = sdn.DeviceNumber; } CloseHandle(hVolume); if ( DeviceNumber == -1 ) { return 1; } // get the drive type which is required to match the device numbers correctely UINT DriveType = GetDriveType(szRootPath); // get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way? char szDosDeviceName[MAX_PATH]; res = QueryDosDevice(szDevicePath,szDosDeviceName,MAX_PATH); if ( !res ) { return 1; } // get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber,DriveType,szDosDeviceName); if ( DevInst == 0 ) { return 1; } PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown; WCHAR VetoNameW[MAX_PATH]; VetoNameW[0] = 0; bool bSuccess = false; // get drives's parent,e.g. the USB bridge,the SATA port,an IDE channel with two drives! DEVINST DevInstParent = 0; res = CM_Get_Parent(&DevInstParent,DevInst,0); for ( long tries=1; tries<=3; tries++ ) { // sometimes we need some tries... VetoNameW[0] = 0; // CM_Query_And_Remove_SubTree doesn't work for restricted users //res = CM_Query_And_Remove_SubTreeW(DevInstParent,&VetoType,VetoNameW,MAX_PATH,CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K! //res = CM_Query_And_Remove_SubTreeW(DevInstParent,CM_REMOVE_NO_RESTART); // with messageBox (W2K,Vista) or balloon (XP) res = CM_Request_Device_EjectW(DevInstParent,0); //res = CM_Request_Device_EjectW(DevInstParent,0); // with messageBox (W2K,Vista) or balloon (XP) bSuccess = (res==CR_SUCCESS && VetoType==PNP_VetoTypeUnknown); if ( bSuccess ) { break; } Sleep(500); // required to give the next tries a chance! } if ( bSuccess ) { printf("Success\n\n"); return 0; } printf("Failed\n"); printf("Result=0x%2X\n",res); if ( VetoNameW[0] ) { printf("VetoName=%ws)\n\n",VetoNameW); } return 1; } //----------------------------------------------------------- char* appendChartocharArray(char* array,char a) { size_t len = strlen(array); char* ret = new char[len+2]; strcpy(ret,array); ret[len] = a; ret[len+1] = '\0'; return ret; } //---------------------------------------------------------------------- // returns the device instance handle of a storage volume or 0 on error //---------------------------------------------------------------------- DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber,char* szDosDeviceName) { bool IsFloppy = (strstr(szDosDeviceName,"\\Floppy") != NULL); // who knows a better way? GUID* guid; switch (DriveType) { case DRIVE_REMOVABLE: if ( IsFloppy ) { guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY; } else { guid = (GUID*)&GUID_DEVINTERFACE_DISK; } break; case DRIVE_FIXED: guid = (GUID*)&GUID_DEVINTERFACE_DISK; break; case DRIVE_CDROM: guid = (GUID*)&GUID_DEVINTERFACE_CDROM; break; default: return 0; } // Get device interface info set handle for all devices attached to system HDEVINFO hDevInfo = SetupDiGetClassDevs(guid,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == INVALID_HANDLE_VALUE) { return 0; } // Retrieve a context structure for a device interface of a device information set DWORD dwIndex = 0; long res; BYTE Buf[1024]; PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf; SP_DEVICE_INTERFACE_DATA spdid; SP_DEVINFO_DATA spdd; DWORD dwSize; spdid.cbSize = sizeof(spdid); while ( true ) { res = SetupDiEnumDeviceInterfaces(hDevInfo,guid,dwIndex,&spdid); if ( !res ) { break; } dwSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo,&spdid,&dwSize,NULL); // check the buffer size if ( dwSize!=0 && dwSize<=sizeof(Buf) ) { pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes! ZeroMemory(&spdd,sizeof(spdd)); spdd.cbSize = sizeof(spdd); long res = SetupDiGetDeviceInterfaceDetail(hDevInfo,pspdidd,dwSize,&spdd); if ( res ) { // in case you are interested in the USB serial number: // the device id string contains the serial number if the device has one,// otherwise a generated id that contains the '&' char... /* DEVINST DevInstParent = 0; CM_Get_Parent(&DevInstParent,spdd.DevInst,0); char szDeviceIdString[MAX_PATH]; CM_Get_Device_ID(DevInstParent,szDeviceIdString,0); printf("DeviceId=%s\n",szDeviceIdString); */ // open the disk or cdrom or floppy HANDLE hDrive = CreateFile(pspdidd->DevicePath,NULL); if ( hDrive != INVALID_HANDLE_VALUE ) { // get its device number STORAGE_DEVICE_NUMBER sdn; DWORD dwBytesReturned = 0; res = DeviceIoControl(hDrive,NULL); if ( res ) { if ( DeviceNumber == (long)sdn.DeviceNumber ) { // match the given device number with the one of the current device CloseHandle(hDrive); SetupDiDestroyDeviceInfoList(hDevInfo); return spdd.DevInst; } } CloseHandle(hDrive); } } } dwIndex++; } SetupDiDestroyDeviceInfoList(hDevInfo); return 0; } //-----------------------------------------------------------
该计划返回:
array(2) ( [0] => (string) D:\D:\.\D:Failed [1] => (string)
Result=0x33 )
有人提出建议吗?
如果您在安全模式下运行PHP,则只允许运行safe_mode_exec_dir中的文件.
您似乎正在Windows环境中运行.您可能需要考虑使用Windows shell执行此操作,这样可以更好地控制外部执行程序,如果失败则可能返回其他信息,并帮助诊断exec()函数的基本问题.
在后台启动Notepad.exe最小化:
<?PHP $WshShell = new COM("WScript.Shell"); $oExec = $WshShell->Run("notepad.exe",7,false); ?>
在后台启动一个不可见的shell命令:
<?PHP $WshShell = new COM("WScript.Shell"); $oExec = $WshShell->Run("cmd /C dir /S %windir%",false); ?>
启动MSPaint最大化并等待您关闭它然后继续脚本:
<?PHP $WshShell = new COM("WScript.Shell"); $oExec = $WshShell->Run("mspaint.exe",3,true); ?>
有关Run()方法的更多信息,请访问:
https://msdn.microsoft.com/en-us/subscriptions/d5fk67ky(v=vs.84).aspx