name: soap-bin-script description: Creates a new synchronous SOAP operation script in bin/ following the exact boilerplate from bin/GetVM.php, bin/DeleteVM.php, etc. Use when user says 'add a bin script', 'new SOAP operation', 'create a hyperv command', or adds a new HyperVService method. Generates the ini_set block, argc check, get_service_master() call, getSoapClientParams(), SoapClient instantiation, and exception handler. Do NOT use for async variants (use async-soap-script instead) and do NOT use for Plugin.php method additions.
soap-bin-script
Critical
- Never use PDO —
$mastercredentials come exclusively fromget_service_master(), never from raw DB queries or env vars. - Never skip the full
ini_setblock — all 6ini_setcalls must appear verbatim in every script. - Always place
hyperVAdminandadminPasswordinside the SOAP params array — never as separate constructor args. - Result key must match the method name —
$response->GetVMResultforGetVM,$response->RebootResultforReboot, etc. (exception:CreateVMand similar create operations useprint_r($response)directly). - Do NOT create async variants here — async scripts belong in
bin/async/and use a different pattern entirely.
Instructions
Step 1 — Identify method signature
Determine:
- SOAP method name (e.g.,
SetCPUCount) - Extra parameters beyond
<id>(e.g.,<vps>,<cpuCount>) - Whether the response has a typed
Resultproperty (query/action ops) or returns the raw object (create ops)
Verify the method exists in https://{host}/HyperVService/HyperVService.asmx?WSDL before writing the script. Check bin/WsdlInfo.php for discovery.
Step 2 — Create the script file in bin/
File name must be the PascalCase SOAP method name inside bin/ — for example bin/GetVMState.php for the GetVMState method, or bin/TurnON.php for TurnON.
Start with the fixed shebang + include + ini_set block. This block is identical in every script — do not modify it:
#!/usr/bin/env php
<?php
include_once __DIR__.'/../../../../include/functions.inc.php';
ini_set('soap.wsdl_cache_enabled', '0');
ini_set('default_socket_timeout', 1000);
ini_set('max_input_time', '0');
ini_set('max_execution_time', '0');
ini_set('display_errors', '1');
ini_set('error_reporting', E_ALL);
Step 3 — Add argc check
Count is 1 (script) + number of positional args. <id> is always first.
- Host only (no vps param):
argc < 2 - Host + vps:
argc < 3 - Host + vps + 1 extra:
argc < 4 - Host + vps + 2 extras:
argc < 5
Usage die message format (match exactly):
// Host only (e.g. GetVMList):
if ($_SERVER['argc'] < 2) {
die("Call like {$_SERVER['argv'][0]} <id>\nwhere <id> is the VPS Master / Host Server ID\nuse 423 for Hyperv-dev and 440 for Hyperv1\n");
}
// Host + vps (most common):
if ($_SERVER['argc'] < 3) {
die("Call like {$_SERVER['argv'][0]} <id> <vps>\nwhere <id> is the VPS Master / Host Server ID\nuse 423 for Hyperv-dev and 440 for Hyperv1\n and <vps> is the id of a vps\n");
}
// Host + additional named params:
if ($_SERVER['argc'] < 5) {
die("Call like {$_SERVER['argv'][0]} <id> <name> <hdsize> <ramsize> [template]\nwhere <id> is the VPS Master / Host Server ID\nuse 423 for Hyperv-dev and 440 for Hyperv1\n");
}
Step 4 — Add host lookup and SOAP call
This output from Step 3 feeds into the try block:
$master = get_service_master($_SERVER['argv'][1], 'vps', true);
try {
$params = \Detain\MyAdminHyperv\Plugin::getSoapClientParams();
$soap = new SoapClient("https://{$master['vps_ip']}/HyperVService/HyperVService.asmx?WSDL", $params);
$response = $soap->MethodName(
[
'vmId' => $_SERVER['argv'][2],
'hyperVAdmin' => 'Administrator',
'adminPassword' => $master['vps_root']
]
);
print_r($response->MethodNameResult);
} catch (Exception $e) {
echo 'Caught exception: '.$e->getMessage().PHP_EOL;
}
Rules for the params array:
vmIdmaps to$_SERVER['argv'][2](the vps arg)- Additional params use
$_SERVER['argv'][3],[4], etc. in order hyperVAdminis always'Administrator'— hardcoded, never from argvadminPasswordis always$master['vps_root']- For operations with no vmId (e.g.,
GetVMList): omitvmId, keep onlyhyperVAdmin+adminPassword
Result printing:
- Query/action operations:
print_r($response->{MethodName}Result); - Create operations that return the full object:
print_r($response);
Step 5 — Verify the script
Run against dev host (id 423) — using bin/GetVMState.php as the example:
php bin/GetVMState.php 423
# Should print usage die message
php bin/GetVMState.php 423 <vmId>
# Should print SOAP response or 'Caught exception: ...'
Verify no PHP parse errors: php -l bin/GetVMState.php
Examples
User says: "Add a bin script for the GetVMState SOAP method that takes a host id and vps id"
Actions:
- Method name:
GetVMState, params:<id> <vps>, result key:GetVMStateResult - argc check:
< 3(host + vps) - Create
bin/GetVMState.php:
#!/usr/bin/env php
<?php
include_once __DIR__.'/../../../../include/functions.inc.php';
ini_set('soap.wsdl_cache_enabled', '0');
ini_set('default_socket_timeout', 1000);
ini_set('max_input_time', '0');
ini_set('max_execution_time', '0');
ini_set('display_errors', '1');
ini_set('error_reporting', E_ALL);
if ($_SERVER['argc'] < 3) {
die("Call like {$_SERVER['argv'][0]} <id> <vps>\nwhere <id> is the VPS Master / Host Server ID\nuse 423 for Hyperv-dev and 440 for Hyperv1\n and <vps> is the id of a vps\n");
}
$master = get_service_master($_SERVER['argv'][1], 'vps', true);
try {
$params = \Detain\MyAdminHyperv\Plugin::getSoapClientParams();
$soap = new SoapClient("https://{$master['vps_ip']}/HyperVService/HyperVService.asmx?WSDL", $params);
$response = $soap->GetVMState(
[
'vmId' => $_SERVER['argv'][2],
'hyperVAdmin' => 'Administrator',
'adminPassword' => $master['vps_root']
]
);
print_r($response->GetVMStateResult);
} catch (Exception $e) {
echo 'Caught exception: '.$e->getMessage().PHP_EOL;
}
- Verify:
php -l bin/GetVMState.php→ no errors,php bin/GetVMState.php 423→ prints usage.
Result: bin/GetVMState.php created, identical in structure to bin/GetVM.php.
Common Issues
PHP Fatal error: Uncaught SoapFault: WSDL
- The host is unreachable or the WSDL URL is wrong. Confirm
$master['vps_ip']is set: addvar_dump($master);before the try block. - Confirm
ini_set('soap.wsdl_cache_enabled', '0')is present — missing it causes stale WSDL cache failures.
PHP Fatal error: Call to undefined function get_service_master()
- The
include_oncepath is wrong. Script must be inbin/(four levels from project root). If placed elsewhere, adjust the relative path tofunctions.inc.php.
Notice: Undefined property: stdClass::$MethodNameResult
- The result key doesn't match. Run
bin/WsdlInfo.phpto inspect exact property names, or useprint_r($response)temporarily to dump the full response object.
Caught exception: Could not connect to host
default_socket_timeouttoo low for slow hosts — it is set to1000seconds in the boilerplate, which is correct. If still failing, verify the host server id (423= Hyperv-dev,440= Hyperv1).
argc check never triggers / script runs with missing args
- Ensure the comparison is
< Nnot<= N. For 2 positional args (<id> <vps>), the count is 3 (including script name), so use$_SERVER['argc'] < 3.
Next.js App Router Expert
Development
A skill that turns Claude into a Next.js App Router expert.
README Generator
Development
Creates professional and comprehensive README.md files for your projects.
API Documentation Writer
Development
Generates comprehensive API documentation in OpenAPI/Swagger format.