dimer47/simplemdm-php-sdk 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

dimer47/simplemdm-php-sdk

Composer 安装命令:

composer require dimer47/simplemdm-php-sdk

包简介

PHP SDK for the SimpleMDM API - Manage Apple devices programmatically

README 文档

README

PHP Guzzle Laravel License Tests Beta

⚠️ This SDK is in beta. It has not been extensively tested in production environments. Unit and integration tests are included in the source code and can be run with your own API key and SimpleMDM environment. Use in production at your own risk.

A PHP SDK for the SimpleMDM API to programmatically manage Apple devices. Compatible with Laravel and any PHP 8.1+ project. 🍎

🎉 Features

  • 📱 Full device management — CRUD, lock, wipe, restart, bluetooth, lost mode, etc.
  • 📦 20 API resources covering the entire SimpleMDM v1 API
  • 🔄 Automatic rate limiting — smart retry on 429 errors
  • 🧩 Laravel ready — Service provider, facade and dependency injection
  • Async-friendly — Guzzle HTTP under the hood
  • 🧪 200 tests (unit + integration) with VCR cassettes

📍 Installation

composer require dimer47/simplemdm-php-sdk

🚀 Quick Start

use SimpleMDM\SimpleMDM;

$mdm = new SimpleMDM('your-api-key');

// List all devices
$devices = $mdm->devices->list();

// Get a specific device
$device = $mdm->devices->get(123);

// Lock a device
$mdm->devices->lock(123, [
    'message' => 'This device has been locked.',
    'phone_number' => '555-0123',
]);

🔧 Laravel Integration

⚙️ Configuration

The package auto-discovers the service provider and facade. Publish the config file:

php artisan vendor:publish --tag=simplemdm-config

Add your API key to .env:

SIMPLEMDM_API_KEY=your-api-key

🏷️ Usage with Facade

use SimpleMDM\Laravel\Facades\SimpleMDM;

$devices = SimpleMDM::devices->list();
$account = SimpleMDM::account->get();

💉 Usage with Dependency Injection

use SimpleMDM\SimpleMDM;

class DeviceController extends Controller
{
    public function index(SimpleMDM $mdm)
    {
        return $mdm->devices->list();
    }
}

📚 Available Resources

🏢 Account

$mdm->account->get();
$mdm->account->update(['name' => 'My Company']);

📱 Devices

$mdm->devices->list();
$mdm->devices->get($id);
$mdm->devices->create('Device Name', $groupId);
$mdm->devices->update($id, ['name' => 'New Name']);
$mdm->devices->delete($id);

// Actions
$mdm->devices->lock($id, ['message' => '...', 'phone_number' => '...']);
$mdm->devices->wipe($id);
$mdm->devices->restart($id);
$mdm->devices->shutdown($id);
$mdm->devices->refresh($id);
$mdm->devices->pushApps($id);
$mdm->devices->clearPasscode($id);
$mdm->devices->clearFirmwarePassword($id);
$mdm->devices->clearRestrictionsPassword($id);
$mdm->devices->updateOS($id);

// Firmware & Recovery passwords
$mdm->devices->rotateFirmwarePassword($id);
$mdm->devices->clearRecoveryLockPassword($id);
$mdm->devices->rotateRecoveryLockPassword($id);
$mdm->devices->rotateFileVaultKey($id);

// Admin password
$mdm->devices->setAdminPassword($id, ['password' => '...']);
$mdm->devices->rotateAdminPassword($id);

// Bluetooth & Remote Desktop
$mdm->devices->enableBluetooth($id);
$mdm->devices->disableBluetooth($id);
$mdm->devices->enableRemoteDesktop($id);
$mdm->devices->disableRemoteDesktop($id);

// Related data
$mdm->devices->listInstalledApps($id);
$mdm->devices->listProfiles($id);
$mdm->devices->listUsers($id);
$mdm->devices->deleteUser($deviceId, $userId);

// Custom attributes
$mdm->devices->listCustomAttributes($id);
$mdm->devices->setCustomAttribute($id, 'attribute_name', 'value');
$mdm->devices->setCustomAttributes($id, ['attr1' => 'val1', 'attr2' => 'val2']); // bulk

// Other
$mdm->devices->setTimeZone($id, 'Europe/Paris');
$mdm->devices->unenroll($id);

📦 Apps

$mdm->apps->list();
$mdm->apps->get($id);
$mdm->apps->create('/path/to/app.ipa', 'App Name');           // Upload binary
$mdm->apps->createFromAppStore('899247664', 'App Name');       // From App Store ID
$mdm->apps->createFromBundleId('com.example.app', 'App Name'); // From Bundle ID
$mdm->apps->update($id, ['name' => 'Updated Name']);
$mdm->apps->delete($id);

// Munki
$mdm->apps->uploadMunkiPkgInfo($id, '/path/to/pkginfo.plist');
$mdm->apps->deleteMunkiPkgInfo($id);

📋 Assignment Groups

$mdm->assignmentGroups->list();
$mdm->assignmentGroups->get($id);
$mdm->assignmentGroups->create('Group Name');
$mdm->assignmentGroups->update($id, ['name' => 'New Name']);
$mdm->assignmentGroups->delete($id);

// Apps
$mdm->assignmentGroups->assignApp($groupId, $appId);
$mdm->assignmentGroups->unassignApp($groupId, $appId);
$mdm->assignmentGroups->pushApps($id);
$mdm->assignmentGroups->updateApps($id);

// Devices
$mdm->assignmentGroups->assignDevice($groupId, $deviceId);
$mdm->assignmentGroups->unassignDevice($groupId, $deviceId);

// Device Groups
$mdm->assignmentGroups->assignDeviceGroup($groupId, $deviceGroupId);
$mdm->assignmentGroups->unassignDeviceGroup($groupId, $deviceGroupId);

// Profiles
$mdm->assignmentGroups->assignProfile($groupId, $profileId);
$mdm->assignmentGroups->unassignProfile($groupId, $profileId);
$mdm->assignmentGroups->syncProfiles($id);

// Other
$mdm->assignmentGroups->clone($id);
$mdm->assignmentGroups->getCustomAttributes($id);
$mdm->assignmentGroups->setCustomAttribute($id, 'attr_name', 'value');

🏷️ Custom Attributes

$mdm->customAttributes->list();
$mdm->customAttributes->get($id);
$mdm->customAttributes->create('Attribute Name', 'default_value');
$mdm->customAttributes->update($id, ['name' => 'New Name']);
$mdm->customAttributes->delete($id);

📄 Custom Configuration Profiles

$mdm->customConfigurationProfiles->list();
$mdm->customConfigurationProfiles->get($id);
$mdm->customConfigurationProfiles->create('/path/to/profile.mobileconfig');
$mdm->customConfigurationProfiles->update($id, ['name' => 'New Name']);
$mdm->customConfigurationProfiles->delete($id);
$mdm->customConfigurationProfiles->download($id);

// Per-device assignment
$mdm->customConfigurationProfiles->pushToDevice($profileId, $deviceId);
$mdm->customConfigurationProfiles->removeFromDevice($profileId, $deviceId);

// Device group assignment
$mdm->customConfigurationProfiles->assignToDeviceGroup($profileId, $deviceGroupId);
$mdm->customConfigurationProfiles->unassignFromDeviceGroup($profileId, $deviceGroupId);

📜 Custom Declarations (DDM)

$mdm->customDeclarations->list();
$mdm->customDeclarations->get($id);
$mdm->customDeclarations->create('com.apple.configuration.management.test', '/path/to/payload.json', 'Declaration Name');
$mdm->customDeclarations->update($id, ['name' => 'New Name']);
$mdm->customDeclarations->delete($id);
$mdm->customDeclarations->download($id);

// Per-device
$mdm->customDeclarations->pushToDevice($declarationId, $deviceId);
$mdm->customDeclarations->removeFromDevice($declarationId, $deviceId);

🔗 DEP Servers

$mdm->depServers->list();
$mdm->depServers->get($id);
$mdm->depServers->listDevices($id);
$mdm->depServers->getDevice($serverId, $depDeviceId);
$mdm->depServers->sync($id);

📧 Enrollments

$mdm->enrollments->list();
$mdm->enrollments->get($id);
$mdm->enrollments->delete($id);
$mdm->enrollments->sendInvitation($id, 'user@example.com');

📲 Installed Apps

$mdm->installedApps->get($id);
$mdm->installedApps->update($id);
$mdm->installedApps->delete($id);

📝 Logs

$mdm->logs->list(['namespace' => 'device']);
$mdm->logs->get($id);

📍 Lost Mode

$mdm->lostMode->enable($deviceId, [
    'message' => 'Please return this device.',
    'phone_number' => '555-0123',
]);
$mdm->lostMode->disable($deviceId);
$mdm->lostMode->playSound($deviceId);
$mdm->lostMode->updateLocation($deviceId);

⚙️ Managed App Configs

$mdm->managedAppConfigs->list($appId);
$mdm->managedAppConfigs->create($appId, 'config_key', 'config_value', 'string');
$mdm->managedAppConfigs->push($appId);
$mdm->managedAppConfigs->delete($appId, $configId);
$mdm->managedAppConfigs->deleteAll($appId);

🛡️ Profiles

$mdm->profiles->list();
$mdm->profiles->get($id);
$mdm->profiles->assignToDevice($profileId, $deviceId);
$mdm->profiles->unassignFromDevice($profileId, $deviceId);
$mdm->profiles->assignToDeviceGroup($profileId, $deviceGroupId);
$mdm->profiles->unassignFromDeviceGroup($profileId, $deviceGroupId);

🔐 Push Certificate

$mdm->pushCertificate->get();
$mdm->pushCertificate->update('/path/to/cert.pem', 'apple-id@example.com');
$mdm->pushCertificate->getSignedCsr();

📜 Scripts

$mdm->scripts->list();
$mdm->scripts->get($id);
$mdm->scripts->create('Script Name', '/path/to/script.sh', variableSupport: true);
$mdm->scripts->update($id, ['name' => 'New Name']);
$mdm->scripts->delete($id);

▶️ Script Jobs

$mdm->scriptJobs->list();
$mdm->scriptJobs->get($id);
$mdm->scriptJobs->create($scriptId, [
    'device_ids' => [1, 2, 3],
    'assignment_group_ids' => [10],
]);
$mdm->scriptJobs->cancel($id);

❌ Error Handling

use SimpleMDM\Exceptions\ApiException;
use SimpleMDM\Exceptions\AuthenticationException;
use SimpleMDM\Exceptions\RateLimitException;

try {
    $devices = $mdm->devices->list();
} catch (AuthenticationException $e) {
    // Invalid API key (401)
} catch (RateLimitException $e) {
    // Too many requests (429)
    $retryAfter = $e->getRetryAfter(); // seconds until rate limit resets
} catch (ApiException $e) {
    // Other API error
    $statusCode = $e->getStatusCode();
    $responseBody = $e->getResponseBody();
}

🧪 Testing

# Unit tests only
vendor/bin/pest tests/Unit/

# Full suite (unit + integration)
vendor/bin/pest

# With Docker
docker compose run --rm php vendor/bin/pest

Integration tests use a VCR cassette system that records real API responses and replays them. To record new cassettes, set SIMPLEMDM_API_KEY in .env and delete the corresponding cassette in tests/Fixtures/cassettes/.

📊 API Coverage

🧪 200 tests | ✅ 404 assertions | ⏭️ 17 skipped

Tests were run against the real SimpleMDM API with a supervised iPad (iOS 12.5).

Resource Method Endpoint Unit Integration
🏢 Account get() GET /account
update() PATCH /account
📦 Apps list() GET /apps
get() GET /apps/{id}
create() POST /apps (binary) 🔶
createFromAppStore() POST /apps (App Store)
createFromBundleId() POST /apps (Bundle ID) 🔶
update() PATCH /apps/{id} 🔶
delete() DELETE /apps/{id}
listInstalls() GET /apps/{id}/installs
uploadMunkiPkgInfo() POST .../munki_pkginfo 🔶
deleteMunkiPkgInfo() DELETE .../munki_pkginfo 🔶
📋 Assignment Groups list() GET /assignment_groups
get() GET /assignment_groups/{id}
create() POST /assignment_groups
update() PATCH /assignment_groups/{id}
delete() DELETE /assignment_groups/{id}
assignApp() POST .../apps/{appId}
unassignApp() DELETE .../apps/{appId}
assignDevice() POST .../devices/{deviceId}
unassignDevice() DELETE .../devices/{deviceId}
assignDeviceGroup() POST .../device_groups/{id} ⏭️
unassignDeviceGroup() DELETE .../device_groups/{id} ⏭️
pushApps() POST .../push_apps
updateApps() POST .../update_apps
syncProfiles() POST .../sync_profiles ⏭️
clone() POST .../clone
assignProfile() POST .../profiles/{id} ⏭️
unassignProfile() DELETE .../profiles/{id} ⏭️
getCustomAttributes() GET .../custom_attribute_values
setCustomAttribute() PUT .../custom_attribute_values/{n}
🏷️ Custom Attributes list() GET /custom_attributes
get() GET /custom_attributes/{id}
create() POST /custom_attributes
update() PATCH /custom_attributes/{id}
delete() DELETE /custom_attributes/{id}
📄 Custom Config Profiles list() GET /custom_configuration_profiles
create() POST /custom_configuration_profiles
update() PATCH .../{id}
delete() DELETE .../{id}
download() GET .../download
pushToDevice() POST .../devices/{deviceId}
removeFromDevice() DELETE .../devices/{deviceId}
assignToDeviceGroup() POST .../device_groups/{id} 🔶
unassignFromDeviceGroup() DELETE .../device_groups/{id} 🔶
📜 Custom Declarations list() GET /custom_declarations
create() POST /custom_declarations
update() PATCH /custom_declarations/{id}
delete() DELETE /custom_declarations/{id}
download() GET .../download
pushToDevice() POST .../devices/{deviceId} ⏭️ iOS 15+
removeFromDevice() DELETE .../devices/{deviceId} ⏭️ iOS 15+
🔗 DEP Servers list() GET /dep_servers
get() GET /dep_servers/{id} ⏭️
listDevices() GET .../dep_devices ⏭️
getDevice() GET .../dep_devices/{id} ⏭️
sync() POST .../sync ⏭️
📱 Device Groups list() GET /device_groups
get() GET /device_groups/{id} ⏭️
assignDevice() POST .../devices/{deviceId} ⏭️
clone() POST .../clone ⏭️
getCustomAttributes() GET .../custom_attribute_values 🔶
setCustomAttribute() PUT .../custom_attribute_values/{n} 🔶
📱 Devices list() GET /devices
get() GET /devices/{id}
create() POST /devices
update() PATCH /devices/{id}
delete() DELETE /devices/{id}
listInstalledApps() GET .../installed_apps
listProfiles() GET .../profiles
listUsers() GET .../users
listCustomAttributes() GET .../custom_attribute_values
setCustomAttribute() PUT .../custom_attribute_values/{n}
setCustomAttributes() PUT .../custom_attribute_values
refresh() POST .../refresh
lock() POST .../lock
clearPasscode() POST .../clear_passcode
clearRestrictionsPassword() POST .../clear_restrictions_password
updateOS() POST .../update_os
restart() POST .../restart
shutdown() POST .../shutdown
pushApps() POST .../push_apps
setTimeZone() POST .../set_time_zone
enableBluetooth() POST .../bluetooth
disableBluetooth() DELETE .../bluetooth
wipe() POST .../wipe
unenroll() POST .../unenroll
deleteUser() DELETE .../users/{userId} 🔶
enableRemoteDesktop() POST .../remote_desktop 🖥️
disableRemoteDesktop() DELETE .../remote_desktop 🖥️
rotateFirmwarePassword() POST .../rotate_firmware_password 🖥️
clearFirmwarePassword() POST .../clear_firmware_password 🖥️
clearRecoveryLockPassword() POST .../clear_recovery_lock_password 🖥️
rotateRecoveryLockPassword() POST .../rotate_recovery_lock_password 🖥️
rotateFileVaultKey() POST .../rotate_filevault_key 🖥️
setAdminPassword() POST .../set_admin_password 🖥️
rotateAdminPassword() POST .../rotate_admin_password 🖥️
📧 Enrollments list() GET /enrollments
get() GET /enrollments/{id}
delete() DELETE /enrollments/{id}
sendInvitation() POST .../invitations
📲 Installed Apps get() GET /installed_apps/{id} ⏭️
update() POST .../update 🔶
delete() DELETE /installed_apps/{id} 🔶
📝 Logs list() GET /logs
get() GET /logs/{id}
📍 Lost Mode enable() POST .../lost_mode
disable() DELETE .../lost_mode
playSound() POST .../play_sound
updateLocation() POST .../update_location
⚙️ Managed App Configs list() GET /apps/{id}/managed_configs
create() POST .../managed_configs
push() POST .../managed_configs/push
delete() DELETE .../managed_configs/{id}
🛡️ Profiles list() GET /profiles
get() GET /profiles/{id} ⏭️
assignToDevice() POST .../devices/{deviceId} ⏭️
unassignFromDevice() DELETE .../devices/{deviceId} ⏭️
assignToDeviceGroup() POST .../device_groups/{id} ⏭️
unassignFromDeviceGroup() DELETE .../device_groups/{id} ⏭️
🔐 Push Certificate get() GET /push_certificate
update() PUT /push_certificate
getSignedCsr() GET .../scsr
📜 Scripts list() GET /scripts
get() GET /scripts/{id}
create() POST /scripts
update() PATCH /scripts/{id}
delete() DELETE /scripts/{id}
▶️ Script Jobs list() GET /script_jobs
get() GET /script_jobs/{id} ⏭️
create() POST /script_jobs ⏭️ 🖥️
cancel() DELETE /script_jobs/{id} ⏭️ 🖥️

🔑 Legend

Icon Meaning
Tested and validated against the real SimpleMDM API
⏭️ Skipped — resource not available in the test environment or missing prerequisites
🔶 Not integration tested — covered by unit tests only (HTTP mocks)
🖥️ macOS only — requires an enrolled macOS device, unit tested only
Intentionally not tested — destructive/irreversible action (wipe, unenroll, push certificate)

⚠️ Limitations and Warnings

🔴 This SDK is in beta. Integration tests were run against a limited SimpleMDM environment (a single supervised iPad running iOS 12.5, no macOS device). While 100% of endpoints are covered by unit tests and the majority are validated through integration tests, some production scenarios could not be verified.

Endpoints not integration tested:

  • 🖥️ macOS only — Remote desktop, firmware/recovery/admin passwords, FileVault, script jobs. Require an enrolled macOS device.
  • 📜 DDM (Declarative Device Management) — Assigning custom declarations to a device requires iOS 15+. The test iPad runs iOS 12.
  • Wipe / Unenroll — Not tested as a precaution (destructive and irreversible).
  • Push Certificate update — Not tested (risk of breaking MDM communications).
  • 🛡️ Profiles / Device Groups — Skipped if no profile or group is configured in the account.

💡 Running tests with your own environment:

# 1. Copy the environment file
cp .env.example .env

# 2. Set your SimpleMDM API key
# SIMPLEMDM_API_KEY=your-api-key

# 3. Delete cassettes to re-record with your environment
rm -rf tests/Fixtures/cassettes/*.json

# 4. Run tests
vendor/bin/pest

💡 Tip: VCR cassettes record real API responses. Once recorded, tests can be re-run without an API connection. Delete a cassette to force re-recording for that endpoint.

📖 OpenAPI Specification

An OpenAPI 3.0 specification file is available at openapi.yaml. It covers all SimpleMDM API v1 endpoints documented in this SDK (~130 endpoints). This file can be used with AI CLI tools, Swagger UI, or any OpenAPI-compatible tool to explore and interact with the API.

Note: This specification has been generated from the SDK source code and has not been extensively tested against the live API. Use it as a reference, not as a guaranteed contract.

📋 Requirements

  • PHP 8.1+
  • Guzzle HTTP 7.0+

📄 License

MIT

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 6
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-15

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固