{"id":41256521,"url":"https://github.com/gmajor-encrypt/php-substrate-api","last_synced_at":"2026-01-23T01:51:53.201Z","repository":{"id":41837442,"uuid":"255213176","full_name":"gmajor-encrypt/php-substrate-api","owner":"gmajor-encrypt","description":"substrate rpc php lib","archived":false,"fork":false,"pushed_at":"2024-10-17T03:23:32.000Z","size":623,"stargazers_count":7,"open_issues_count":3,"forks_count":9,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-14T03:51:36.051Z","etag":null,"topics":["blockchain","php","rpc","substrate"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gmajor-encrypt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-13T02:30:21.000Z","updated_at":"2024-10-17T03:23:18.000Z","dependencies_parsed_at":"2024-08-05T09:04:45.945Z","dependency_job_id":null,"html_url":"https://github.com/gmajor-encrypt/php-substrate-api","commit_stats":{"total_commits":64,"total_committers":3,"mean_commits":"21.333333333333332","dds":0.125,"last_synced_commit":"e28e90202c25f6426e60ff9ef98ab5fb0a8306b7"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/gmajor-encrypt/php-substrate-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmajor-encrypt%2Fphp-substrate-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmajor-encrypt%2Fphp-substrate-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmajor-encrypt%2Fphp-substrate-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmajor-encrypt%2Fphp-substrate-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gmajor-encrypt","download_url":"https://codeload.github.com/gmajor-encrypt/php-substrate-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmajor-encrypt%2Fphp-substrate-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28677714,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T01:00:35.747Z","status":"ssl_error","status_checked_at":"2026-01-23T01:00:19.529Z","response_time":144,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","php","rpc","substrate"],"created_at":"2026-01-23T01:51:52.686Z","updated_at":"2026-01-23T01:51:53.184Z","avatar_url":"https://github.com/gmajor-encrypt.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# php-substrate-api\n\n---\nPHP Substrate RPC Api\n\n## Requirement\n\n* php \u003e=8.0 (install ffi https://www.php.net/manual/en/intro.ffi.php)\n* curl (https://www.php.net/manual/en/curl.installation.php) \n* json (https://www.php.net/manual/en/json.installation.php) \n* sodium (https://www.php.net/manual/en/sodium.installation.php) \n* gmp (https://www.php.net/manual/en/gmp.installation.php)\n* dom (https://www.php.net/manual/en/dom.installation.php)\n* mbstring (https://www.php.net/manual/en/mbstring.installation.php)\n\n\n## Installation\n\nIf you want to install php-substrate-api in an existing project\n```sh\ncomposer require gmajor/php-substrate-api\n```\n\nif it is a new project\n```sh\nmkdir new_project \u0026\u0026 cd new_project  \u0026\u0026 composer init --stability=dev \u0026\u0026 composer require gmajor/php-substrate-api\n```\n\n## Basic Usage\n\n### Autoloading\n\nCodec supports `PSR-4` autoloaders.\n\n```php\n\u003c?php\n# When installed via composer\nrequire_once 'vendor/autoload.php';\n```\n\n### RPC\n\n* Generate HTTP|Websocket Client\n\n```php\n\u003c?php\nuse Rpc\\SubstrateRpc;\n// http client\n$httpClient = new SubstrateRpc(\"https://kusama-rpc.polkadot.io/\");\n// websocket client \n$websocketClient = new SubstrateRpc(\"wss://kusama-rpc.polkadot.io/\");\n$websocketClient-\u003eclose(); // close websocket connection\n```\n\n* Read RPC Data\n\n```php\n\u003c?php\nuse Rpc\\SubstrateRpc;\n$client = new SubstrateRpc(\"wss://kusama-rpc.polkadot.io/\");\n\n// call any json rpc you can use $client-\u003erpc-\u003e{$pallet_name}-\u003e{$method}, like\n// call rpc system_health \n$res = $client-\u003erpc-\u003esystem-\u003ehealth(); \nvar_dump($res); #{\"peers\": 31, \"isSyncing\": false, \"shouldHavePeers\": true}\n// or call rpc chain_getFinalizedHead\n$client-\u003erpc-\u003echain-\u003egetFinalizedHead(); \n\n$client-\u003eclose(); // do not forget close websocket connection !\n```\n\n* Hasher\n\nWe currently support 6 hash methods, including Blake2_128，Blake2_256，Twox128，Twox256，Twox64Concat，Blake2_128Concat。\n\n```php\n\u003c?php\nuse Rpc\\Hasher\\Hasher;\n\n$hasher = new Hasher();\n// Blake2_128\n$hasher-\u003eByHasherName(\"Blake2_128\", \"20be52a5a80cad065651ec35fcb1a212bc669aabb52d68d8780a41e29ec9c83e\");\n// Blake2_256\n$hasher-\u003eByHasherName(\"Blake2_256\", \"20be52a5a80cad065651ec35fcb1a212bc669aabb52d68d8780a41e29ec9c83e\")\n// Twox128\n$hasher-\u003eTwoxHash(\"Key\", 128)\n// Twox128\n$hasher-\u003eTwoxHash(\"Sudo\", 256)\n// XXHash64\n$hasher-\u003eXXHash64(0, \"test\");\n// Twox64Concat\n$hasher-\u003eByHasherName(\"Twox64Concat\", \"0xad2ecd66275a1ded\")\n//  Blake2_128Concat\n$hasher-\u003eByHasherName(\"Blake2_128Concat\", \"20be\")\n````\n\n* Storage key\n\nWhen you access storage using Substrate RPC(like\nrpc [state_getStorage](https://polkadot.js.org/docs/substrate/rpc#getstoragechildkey-prefixedstoragekey-key-storagekey-at-hash-optionstoragedata)\n, you need to provide the key associated with the item,\n\n```php\n\u003c?php\nuse Rpc\\StorageKey;\n\nuse Codec\\Base;\nuse Codec\\ScaleBytes;\nuse Codec\\Types\\ScaleInstance;\nuse Rpc\\StorageKey;\n\n$codec = new ScaleInstance(Base::create());\n$metadataV14RawValue = \"....\" //  from json rpc state_getMetadata\n$metadata = $codec-\u003eprocess(\"metadata\", new ScaleBytes($metadataV14RawValue))[\"metadata\"];\n// Timestamp.now storage key\n$hasher = new Hasher();\nprint_r(StorageKey::encode($hasher,\"Timestamp\", \"now\", $metadata, []));\n// Staking.Bonded storage key with param accountId\nprint_r(StorageKey::encode($hasher,\"System\", \"Account\", $metadata, [\"0x1c79a5ada2ff0d55aaa65dfeaf0cba667babf312f9bf100444279b34cd769e49\"]))\n\n```\n\n* Json RPC\n\nRPC methods that are Remote Calls available by default and allow you to interact with the actual node, query, and\nsubmit.\n\n```php\n// On the api, these are exposed via \u003cclient\u003e.rpc.\u003cmodule\u003e.\u003cmethod\u003e, like this \n$client-\u003erpc-\u003esystem-\u003ehealth(); // for rpc system_health\n$client-\u003erpc-\u003eauthor-\u003erotateKeys(); // for rpc author_rotateKeys\n$client-\u003erpc-\u003estate-\u003egetMetadata(\"hash\"); // for rpc state_getMetadata\n```\n\nAll rpc interface has been declare at https://github.com/gmajor-encrypt/php-substrate-api/tree/master/src/Rpc/JsonRpc\n\nMore detailed RPC documentation can be found at https://polkadot.js.org/docs/substrate/rpc\n\n* Send extrinsics\n\nBelow is a simple example of sending a token, you can use tx.\u003cmodule\u003e.\u003cmethod\u003e to send any transaction\n\n```php\n\u003c?php\nuse Rpc\\KeyPair\\KeyPair;\nuse Rpc\\SubstrateRpc;\n$AliceSeed = \"0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a\";\n$BobId = [\"Id\" =\u003e \"8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48\"];\n$wsClient = new SubstrateRpc($endpoint);\n$hasher = new Hasher();\n$wsClient-\u003esetSigner(KeyPair::initKeyPair(\"sr25519\", $AliceSeed, $hasher),$hasher);\n$tx = $wsClient-\u003etx;\n$result = $tx-\u003eBalances-\u003etransfer($BobId, 12345);\nvar_dump($result); // transaction hash\n\n// if you want waiting transaction exec, you can set tx with option\n$tx-\u003ewithOpt([\"subscribe\" =\u003e true]);\n$result = $tx-\u003eBalances-\u003etransfer($BobId, 12345);\nvar_dump($result); // Will not return until execution is complete\n$wsClient-\u003eclose()\n````\n\n### Keyring\n\nThe Keyring allows you to perform operations on these keys (such as sign/verify) and never exposes the secretKey\n\nto the outside world. Support ed25519(Edwards https://ed25519.cr.yp.to/) or sr25519(\nschnorrkel https://github.com/w3f/schnorrkel)\n\n```php\n\u003c?php\nuse Rpc\\KeyPair\\KeyPair;\n$keyPair = KeyPair::initKeyPair(\"sr25519|ed25519\", {$secretKey}, new Hasher());\n// signed msg\n$signature = $keyPair-\u003esign(\"msg\");\n// verify this message\n$keyPair-\u003everify($signature, \"123\");\n```\n\n### Contract\n\n#### Metadata support\n\nThe metadata is used to describe a contract in a language agnostic way. Metadata can declare the storage and executable\nmethods and types contained in the contract\n\nWe currently support ink metadata v0,v1,v2,v3,v4.\n\n```php\n\u003c?php\nuse Rpc\\Contract\\Abi\\Convert;\nuse Codec\\Base;\nuse Codec\\Types\\ScaleInstance;\n$content = json_decode(file_get_contents(__DIR__ . '/ink/ink_v0.json'), true);\n$metadata = Convert::toLatest($content); // convert metadata to latest version\n// reg metadata types\n$scale = new ScaleInstance(Base::create());\n$metadata-\u003eregister_type($scale-\u003egetGenerator(), \"some_prefix\");\n```\n\n#### Deploy contract\n\nAfter declaring a Contract class, you can call the new method to create a contract.\n\nAbout how to build ink contract, you can refer to\nthis https://docs.substrate.io/tutorials/smart-contracts/prepare-your-first-contract/\n\nBelow is an example.\n\n```php\n\u003c?php\nuse Rpc\\KeyPair\\KeyPair;\nuse Rpc\\SubstrateRpc;\nuse Rpc\\Contract;\n\n$wsClient = new SubstrateRpc($endpoint);\n// set deployer keyring\n$hasher = new Hasher();\n$wsClient-\u003esetSigner(KeyPair::initKeyPair(\"sr25519\",$seed, $hasher),$hasher);\n$contract = new Contract($wsClient-\u003etx);\n// $inputData = constructor_selector + encode(args...)\n$result = $contract-\u003enew($contract_code, $inputData); // with default option\n\n# If you need to additionally set the gas limit and storageDepositLimit, you can set it like this\n$result = $contract-\u003enew($contract_code, $inputData,[], [\"gasLimit\"=\u003e100000,\"storageDepositLimit\"=\u003e50000]); // with default option\n```\n\n#### Read Contract state\n\nReading the storage on the contract does not consume any gas, so anyone can read the contract.\n\nYou can simply read the contract through ```$contract-\u003estate-\u003e{$method}($param1,$param2)```\n\n```php\n\u003c?php\nuse Rpc\\KeyPair\\KeyPair;\nuse Rpc\\SubstrateRpc;\nuse Rpc\\Contract;\nuse Rpc\\Contract\\ContractExecResult;\n\n$wsClient = new SubstrateRpc($endpoint);\n// set signer\n$hasher = new Hasher();\n$wsClient-\u003esetSigner(KeyPair::initKeyPair(\"sr25519\", $seed, $hash),$hash);\n// get abi\n$v4 = ContractMetadataV4::to_obj(json_decode(file_get_contents(__DIR__ . '/ink/ink_v4.json'), true));\n// register contract type\n$v4-\u003eregister_type($wsClient-\u003etx-\u003ecodec-\u003egetGenerator(), \"testAbiMetadataV4Parse\");\n\n// read contract\n$contract = new Contract($wsClient-\u003etx, $contractAddress, $v4);\n// call get method\n$execResult = $contract-\u003estate-\u003eget();\n// parse exec Result\n$result =ContractExecResult::getDecodeResult($execResult, $wsClient-\u003etx-\u003ecodec)\nprint_r($result);\n```\n\n#### Send Contract transaction\n\nSending contract transactions is very similar to executing extrinsic. You can simply exec the contract through\n```$contract-\u003ecall-\u003e{$method}($param1,$param2,$option=[])```\n\n```php\n\u003c?php\nuse Rpc\\KeyPair\\KeyPair;\nuse Rpc\\SubstrateRpc;\nuse Rpc\\Contract;\n$wsClient = new SubstrateRpc($endpoint);\n// set signer\n$hasher = new Hasher();\n$wsClient-\u003esetSigner(KeyPair::initKeyPair(\"sr25519\", $this-\u003eAliceSeed, $hasher),$hasher);\n\n// register contract type\n$v4 = ContractMetadataV4::to_obj(json_decode(file_get_contents(__DIR__ . '/ink/ink_v4.json'), true));\n$v4-\u003eregister_type($wsClient-\u003etx-\u003ecodec-\u003egetGenerator(), \"testAbiMetadataV4Parse\");\n\n// send contract transaction\n$contract = new Contract($wsClient-\u003etx, $contractAddress, $v4);\n$result = $contract-\u003ecall-\u003eflip([]); // with default option\n\n// If you need to additionally set the gas limit and storageDepositLimit, you can set it like this\n$result = $contract-\u003ecall-\u003eflip([\"storageDepositLimit\"=\u003e$limit,[\"gasLimit\"=\u003e[\"refTime\"=\u003e$refTime,\"proofSize\"=\u003e$proofSize]] ]); \nprint_r($result);// extrinsic_hash\n```\n\n#### Generate contract address\n\nSince the address algorithm of the contract is fixed, it is easy to calculate the deployed contract address\n\n```php\n\u003c?php\nuse Rpc\\Hasher\\Hasher;\nuse Rpc\\Contract\\Address;\nuse Codec\\Base;\nuse Codec\\Types\\ScaleInstance;\n$hasher = new Hasher();\n$codec = new ScaleInstance(Base::create());\n$bytes = $codec-\u003ecreateTypeByTypeString(\"bytes\");\nAddress::GenerateAddress($hasher, $deployer, $codeHash, $bytes-\u003eencode($inputData), $bytes-\u003eencode($salt)));\n\n```\n\n### Example\n\nMore examples can refer to the test file https://github.com/gmajor-encrypt/php-substrate-api/tree/master/test/Rpc\n\n## Test\n\n```bash\nmake test\n```\n\n## Troubleshooting\n\n### FFI error FFI\\Exception: Failed loading '../php-substrate-api/vendor/gmajor/sr25519-bindings/src/Crypto/sr25519.so'\n\nThe current default sr25519-bindings FFI is for mac. Unfortunately, php composer currently does not support automatic\ncompilation after install, so manual compilation is required. You can run this script\n\n```bash\n## For darwin\ncd vendor/gmajor/sr25519-bindings/go \u0026\u0026 go build -buildmode=c-shared -o ../src/Crypto/sr25519.dylib .\n## For linux \ncd vendor/gmajor/sr25519-bindings/go \u0026\u0026 go build -buildmode=c-shared -o ../src/Crypto/sr25519.so . \n```\n\n### WebSocket\\ConnectionException: Could not open socket to \"127.0.0.1:9944\"\n\nIn the test,The keyPair used in the test process is //Alice, **ws://127.0.0.1:9944** is used by default as the node for\ntesting SendTransaction. This node can start any private network settings by itself. You can also set the node address\nthrough environment variables.\n\n```base\nexport RPC_URL=ws://....\n```\n\n### gmajor/php-substrate-api v0.1.0 requires textalk/websocket dev-master -\u003e found ``xxxx`` but it does not match your minimum-stability\n\nYou need set [minimum-stability](https://getcomposer.org/doc/04-schema.md#minimum-stability) like this ``\"minimum-stability\": \"dev\"`` in composer. \n\n\n## Resources\n\n- [sr25519](https://github.com/gmajor-encrypt/sr25519-bindings)\n- [polkadot.js](http://polkadot.js.org/)\n- [substrate.dev](https://docs.substrate.io/v3/runtime/custom-rpcs/)\n- [substrate-api-sidecar](https://github.com/paritytech/substrate-api-sidecar)\n\n## License\n\nThe package is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmajor-encrypt%2Fphp-substrate-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgmajor-encrypt%2Fphp-substrate-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmajor-encrypt%2Fphp-substrate-api/lists"}