{"id":36634364,"url":"https://github.com/creativechain/php-graphene-node-client","last_synced_at":"2026-01-12T09:44:42.425Z","repository":{"id":56958867,"uuid":"162739360","full_name":"creativechain/php-graphene-node-client","owner":"creativechain","description":null,"archived":false,"fork":false,"pushed_at":"2020-07-07T08:56:18.000Z","size":175,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-04T02:04:05.571Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/creativechain.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}},"created_at":"2018-12-21T17:10:03.000Z","updated_at":"2024-05-04T02:04:05.572Z","dependencies_parsed_at":"2022-08-21T09:50:20.939Z","dependency_job_id":null,"html_url":"https://github.com/creativechain/php-graphene-node-client","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/creativechain/php-graphene-node-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creativechain%2Fphp-graphene-node-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creativechain%2Fphp-graphene-node-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creativechain%2Fphp-graphene-node-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creativechain%2Fphp-graphene-node-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creativechain","download_url":"https://codeload.github.com/creativechain/php-graphene-node-client/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creativechain%2Fphp-graphene-node-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337755,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":[],"created_at":"2026-01-12T09:44:41.787Z","updated_at":"2026-01-12T09:44:42.412Z","avatar_url":"https://github.com/creativechain.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# php-graphene-node-client\nPHP client for connection to [CREA](https://gitlab.com/creativechain) node\n\n\n## Install Via Composer\n#### For readonly, without broadcast\n```\ncomposer require crea/php-graphene-node-client\n```\n#### with broadcast (sending transactions to blockchain)\n\\(details are [here](https://golos.io/ru--otkrytyij-kod/@php-node-client/podklyuchenie-secp256k1-php-k-php-dockerfile)\\) and actual dockerfile and requests examples see in branch [\"debug\"](https://github.com/crea/php-graphene-node-client/tree/debug)\n\ninstall components\n- automake\n- libtool\n- libgmp-dev\n\ninstall extensions\n- Bit-Wasp/secp256k1-php v0.2.1 \\(how to install [secp256k1-php](https://github.com/Bit-Wasp/secp256k1-php)\\)\n- gmp\n\n\n\n## Basic Usage\n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Commands\\CommandQueryData;\nuse GrapheneNodeClient\\Commands\\Commands;\nuse GrapheneNodeClient\\Commands\\Single\\GetDiscussionsByCreatedCommand;\nuse GrapheneNodeClient\\Connectors\\WebSocket\\CreaWSConnector;\nuse GrapheneNodeClient\\Connectors\\WebSocket\\CreaWSConnector;\n\n\n//Set params for query\n$commandQuery = new CommandQueryData();\n$data = [\n    [\n        'limit'       =\u003e $limit,\n        'tag'         =\u003e 'crea', // for CREA     \n    ]\n];\n$commandQuery-\u003esetParams($data);\n\n//OR \n$commandQuery = new CommandQueryData();\n$commandQuery-\u003esetParamByKey('0:limit', $limit);\n$commandQuery-\u003esetParamByKey('0:select_tags', [$tag]);\n$commandQuery-\u003esetParamByKey('0:tag', $tag);\n\n\n//and use single command\n$command = new GetDiscussionsByCreatedCommand(new CreaWSConnector());\n$golosPosts = $command-\u003eexecute(\n    $commandQuery\n);\n\n//or commands aggregator class\n$commands = new Commands(new CreaWSConnector());\n$golosPosts = $commands-\u003eget_discussions_by_created()\n    -\u003eexecute(\n       $commandQuery\n);\n\n\n// will return\n// [\n//      \"id\" =\u003e 1,\n//      \"result\" =\u003e [\n//            [\n//                \"id\": 466628,\n//                \"author\": \"piranya\",\n//                \"permlink\": \"devyatyi-krug\",\n//                ...\n//            ],\n//            ...\n//      ]\n// ]\n  \n  \n//single command  \n$command = new GetDiscussionsByCreatedCommand(new CreaWSConnector());\n$steemitPosts = $command-\u003eexecute(\n    $commandQuery,\n    'result',\n    CreaWSConnector::ANSWER_FORMAT_ARRAY // or CreaWSConnector::ANSWER_FORMAT_OBJECT\n);\n\n//or commands aggregator class\n$commands = new Commands(new CreaWSConnector());\n$golosPosts = $commands-\u003eget_discussions_by_created()\n    -\u003eexecute(\n        $commandQuery,\n        'result',\n        CreaWSConnector::ANSWER_FORMAT_ARRAY // or CreaWSConnector::ANSWER_FORMAT_OBJECT\n);\n\n\n// will return\n// [\n//      [\n//          \"id\": 466628,\n//          \"author\": \"piranya\",\n//          \"permlink\": \"devyatyi-krug\",\n//          ...\n//      ],\n//      ...\n// ]\n\n\n```\n  \n   \n\n## Implemented Commands List\n\n### Single Commands\n- BroadcastTransactionCommand\n- BroadcastTransactionSynchronousCommand\n- GetAccountCountCommand\n- GetAccountHistoryCommand\n- GetAccountsCommand\n- GetAccountVotesCommand\n- GetActiveWitnessesCommand\n- GetApiByNameCommand //ONLY STEEM/whaleshares\n- GetBlockCommand\n- GetBlockHeaderCommand\n- GetConfigCommand\n- GetContentCommand\n- GetContentRepliesCommand\n- GetCurrentMedianHistoryPriceCommand //STEEM/GOLOS\n- GetDiscussionsByAuthorBeforeDateCommand\n- GetDiscussionsByBlogCommand\n- GetDiscussionsByCreatedCommand\n- GetDiscussionsByFeedCommand\n- GetDiscussionsByTrendingCommand\n- GetDynamicGlobalPropertiesCommand\n- GetFollowersCommand\n- GetOpsInBlock\n- GetTrendingCategoriesCommand //only steem/whaleshares\n- GetVersionCommand\n- GetWitnessesByVoteCommand\n- LoginCommand //ONLY for STEEM/whaleshares\n\nAll single commands can be called through Commands Class as methods (example: (new Commands)-\u003eget_block()-\u003eexecute(...) )\n\n\n### broadcast operations templates\n\nnamespace GrapheneNodeClient\\Tools\\ChainOperations\n\n- vote\n- transfer\n- comment // crea\n\n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Tools\\ChainOperations\\OpVote;\nuse GrapheneNodeClient\\Connectors\\Http\\CreaHttpConnector;\nuse GrapheneNodeClient\\Connectors\\WebSocket\\CreaWSConnector;\n\n$connector = new CreaHttpConnector();\n//$connector = new CreaWSConnector();\n//$connector = new VizWSConnector();\n\n$answer = OpVote::doSynchronous(\n    $connector,\n    'guest123',\n    '5JRaypasxMx1L97ZUX7YuC5Psb5EAbF821kkAGtBj7xCJFQcbLg',\n    'firepower',\n    'steemit-veni-vidi-vici-steemfest-2016-together-we-made-it-happen-thank-you-steemians',\n    10000\n);\n\n// example of answer\n//Array\n//(\n//    [id] =\u003e 5\n//    [result] =\u003e Array\n//        (\n//            [id] =\u003e a2c52988ea870e446480782ff046994de2666e0d\n//            [block_num] =\u003e 17852337\n//            [trx_num] =\u003e 1\n//            [expired] =\u003e\n//        )\n//\n//)\n\n```\n\n## Implemented Connectors List\n\nnamespace: GrapheneNodeClient\\Connectors\\WebSocket OR GrapheneNodeClient\\Connectors\\Http;\n\n- CreaWSConnector\n- CreaHttpJsonRpcConnector\n\n\n#### Switching between connectors \n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Commands\\CommandQueryData;\nuse GrapheneNodeClient\\Commands\\Single\\GetContentCommand;\nuse GrapheneNodeClient\\Connectors\\InitConnector;\n\n$command = new GetContentCommand(InitConnector::getConnector(InitConnector::PLATFORM_CREA));\n\n$commandQuery = new CommandQueryData();\n$commandQuery-\u003esetParamByKey('0', 'author');\n$commandQuery-\u003esetParamByKey('1', 'permlink');\n\n//OR\n$commandQuery = new CommandQueryData();\n$commandQuery-\u003esetParams(\n    [\n        0 =\u003e \"author\",\n        1 =\u003e \"permlink\"\n    ]\n);\n\n$content = $command-\u003eexecute(\n    $commandQuery\n);\n// will return\n// [\n//      \"id\" =\u003e 1,\n//      \"result\" =\u003e [\n//            ...\n//      ]\n// ]\n\n\n```\n\n   \n\n## Creating Own Connector\n```php\n\u003c?php\n\nnamespace My\\App\\Connectors;\n\nuse GrapheneNodeClient\\Connectors\\ConnectorInterface;\n\nclass MyConnector implements ConnectorInterface \n{\n    public function setConnectionTimeoutSeconds($timeoutSeconds) {\n     // TODO: Implement setConnectionTimeoutSeconds() method.\n    }\n    \n    public function setMaxNumberOfTriesToReconnect($triesN) {\n     // TODO: Implement setMaxNumberOfTriesToReconnect() method.\n    }\n    \n    /**\n    * platform name for witch connector is. steemit or golos.\n    */\n    public function getPlatform() {\n     // TODO: Implement getPlatform() method.\n    }\n    \n    /**\n    * @param string $apiName calling api name - follow_api, database_api and ect.\n    * @param array  $data    options and data for request\n    * @param string $answerFormat\n    *\n    * @return array|object return answer data\n    */\n    public function doRequest($apiName, array $data, $answerFormat = self::ANSWER_FORMAT_ARRAY) {\n     // TODO: Implement doRequest() method.\n    }\n\n}\n\n\n```\nOr use GrapheneNodeClient\\Connectors\\WebSocket\\WSConnectorAbstract for extending\n\n```php\n\u003c?php\n\nnamespace My\\App\\Commands;\n\nuse GrapheneNodeClient\\Commands\\Single\\CommandAbstract;\nuse GrapheneNodeClient\\Connectors\\ConnectorInterface;\n\nclass CreaWSConnector extends WSConnectorAbstract\n{\n    /**\n     * @var string\n     */\n    protected $platform = self::PLATFORM_CREA;\n\n    /**\n     * waiting answer from Node during $wsTimeoutSeconds seconds\n     *\n     * @var int\n     */\n    protected $wsTimeoutSeconds = 5;\n\n    /**\n     * max number of tries to get answer from the node\n     *\n     * @var int\n     */\n    protected $maxNumberOfTriesToCallApi = 3;\n\n    /**\n     * wss or ws servers, can be list. First node is default, other are reserve.\n     * After $maxNumberOfTriesToCallApi tries connects to default it is connected to reserve node.\n     *\n     * @var string|array\n     */\n    protected $nodeURL = ['wss://ws.creary.net'];\n}\n\n\n```  \n\n   \n  \n   \n\n## Creating Own Command\n\nYou have to update $map properties in CreaApiMethods classes as shown below\n\n```php\n\u003c?php\n\n\nnamespace GrapheneNodeClient\\Commands;\n\nclass CreaApiMethods\n{\n    //...\n    //protected $projectApi = [ 'method_name' =\u003e [ 'apiName' =\u003e 'api_name', 'fields'=\u003e['массив с полями из команды']]];\n    protected static $map = [\n        //...\n        'broadcast_transaction'                 =\u003e [\n            'apiName' =\u003e 'network_broadcast_api',\n            'fields'  =\u003e [\n                '0:ref_block_num'    =\u003e ['integer'],\n                '0:ref_block_prefix' =\u003e ['integer'],\n                '0:expiration'       =\u003e ['string'],\n                '0:operations:*:0'   =\u003e ['string'],\n                '0:operations:*:1'   =\u003e ['array'],\n                '0:extensions'       =\u003e ['array'],\n                '0:signatures'       =\u003e ['array']\n            ]\n        ],\n        //...\n        'broadcast_transaction'                 =\u003e [\n            'apiName' =\u003e 'your_method',\n            'fields'  =\u003e [\n                //your fields\n            ]\n        ]\n    ];\n}\n\n\n```  \n\n# Tools\n## Transliterator\n\n\n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Tools\\Transliterator;\n\n\n//Encode tags\n$tag = Transliterator::encode('пол', Transliterator::LANG_RU); // return 'pol';\n\n\n//Decode tags\n$tag = Transliterator::encode('ru--pol', Transliterator::LANG_RU); // return 'пол';\n\n```\n\n\n## Reputation viewer\n\n\n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Tools\\Reputation;\n\n$rep = Reputation::calculate($account['reputation']);\n\n```\n\n## Bandwidth\n\nSometimes you can't send transaction to blockchain because your account has not enough bandwidth. Now you can check this before sending transaction to blockchain as shown below\n\n\n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Connectors\\Http\\CreaHttpConnector;\nuse GrapheneNodeClient\\Commands\\CommandQueryData;\nuse GrapheneNodeClient\\Tools\\Bandwidth;\nuse GrapheneNodeClient\\Tools\\Transaction;\n\n\n$connector = new CreaHttpConnector();\n/** @var CommandQueryData $tx */\n$tx = Transaction::init($connector, 'PT4M');\n$tx-\u003esetParamByKey(\n    '0:operations:0',\n    [\n        'vote',\n        [\n            'voter'    =\u003e $voter,\n            'author'   =\u003e $author,\n            'permlink' =\u003e $permlink,\n            'weight'   =\u003e $weight\n        ]\n    ]\n);\n$command = new BroadcastTransactionSynchronousCommand($connector);\nTransaction::sign($chainName, $tx, ['posting' =\u003e $publicWif]);\n\n$trxString = mb_strlen(json_encode($tx-\u003egetParams()), '8bit');\nif (Bandwidth::isEnough($connector, $voter, 'market', $trxString)) {\n\t$answer = $command-\u003eexecute(\n\t\t$tx\n\t);\n}\n\n//or other way\n\n$bandwidth = Bandwidth::getBandwidthByAccountName($voter, 'market', $connector);\n\n//Array\n//(\n//    [used] =\u003e 3120016\n//    [available] =\u003e 148362781\n//)\n\nif ($trxString * 10 + $bandwidth['used'] \u003c $bandwidth['available']) {\n\t$answer = $command-\u003eexecute(\n\t\t$tx\n\t);\n}\n\n// \n\n```\n\n\n## Transaction for blockchain (broadcast)\n\n\n```php\n\u003c?php\n\nuse GrapheneNodeClient\\Tools\\Transaction;\nuse GrapheneNodeClient\\Connectors\\Http\\CreaHttpConnector;\nuse GrapheneNodeClient\\Connectors\\WebSocket\\CreaWSConnector;\n\n$connector = new CreaHttpConnector();\n//$connector = new CreaWSConnector();\n\n/** @var CommandQueryData $tx */\n$tx = Transaction::init($connector, 'PT4M');\n$tx-\u003esetParamByKey(\n    '0:operations:0',\n    [\n        'vote',\n        [\n            'voter'    =\u003e $voter,\n            'author'   =\u003e $author,\n            'permlink' =\u003e $permlink,\n            'weight'   =\u003e $weight\n        ]\n    ]\n);\n\n$command = new BroadcastTransactionSynchronousCommand($connector);\nTransaction::sign($chainName, $tx, ['posting' =\u003e $publicWif]);\n\n$answer = $command-\u003eexecute(\n    $tx\n);\n\n```\n\n\n** WARNING**\n\nTransactions are signing with spec256k1-php with function secp256k1_ecdsa_sign_recoverable($context, $signatureRec, $msg32, $privateKey) and if it is not canonical from first time, you have to make transaction for other block. For searching canonical sign function have to implement two more parameters, but spec256k1-php library does not have it.\nIt is was solved with php-hack in Transaction::sign()\n```php\n...\n//becouse spec256k1-php canonical sign trouble will use php hack.\n//If sign is not canonical, we have to chang msg (we will add 1 sec to tx expiration time) and try to sign again\n$nTries = 0;\nwhile (true) {\n    $nTries++;\n    $msg = self::getTxMsg($chainName, $trxData);\n    echo '\u003cpre\u003e' . print_r($trxData-\u003egetParams(), true) . '\u003cpre\u003e'; //FIXME delete it\n\n    try {\n        foreach ($privateWIFs as $keyName =\u003e $privateWif) {\n            $index = count($trxData-\u003egetParams()[0]['signatures']);\n\n            /** @var CommandQueryData $trxData */\n            $trxData-\u003esetParamByKey('0:signatures:' . $index, self::signOperation($msg, $privateWif));\n        }\n        break;\n    } catch (TransactionSignException $e) {\n        if ($nTries \u003e 200) {\n            //stop tries to find canonical sign\n            throw $e;\n            break;\n        } else {\n            /** @var CommandQueryData $trxData */\n            $params = $trxData-\u003egetParams();\n            foreach ($params as $key =\u003e $tx) {\n                $tx['expiration'] = (new \\DateTime($tx['expiration']))\n                    -\u003eadd(new \\DateInterval('PT0M1S'))\n                    -\u003eformat('Y-m-d\\TH:i:s\\.000');\n                $params[$key] = $tx;\n            }\n            $trxData-\u003esetParams($params);\n        }\n    }\n...\n```\n\n## Tests\nYou need to install PhpUnit in your system (https://phpunit.de/manual/3.7/en/installation.html)\n```\ncd Tests\nphpunit CommandsTest.php \nphpunit CommandsTest.php --filter=testGetBlock // test only one command\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreativechain%2Fphp-graphene-node-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreativechain%2Fphp-graphene-node-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreativechain%2Fphp-graphene-node-client/lists"}