{"id":20282293,"url":"https://github.com/ne-lexa/php-crossplane","last_synced_at":"2025-08-26T08:08:56.037Z","repository":{"id":57024828,"uuid":"378232164","full_name":"Ne-Lexa/php-crossplane","owner":"Ne-Lexa","description":"An unofficial PHP port of the NGINX config/JSON converter crossplane ","archived":false,"fork":false,"pushed_at":"2022-10-03T12:59:10.000Z","size":87,"stargazers_count":20,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-18T12:56:57.849Z","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":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ne-Lexa.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":"2021-06-18T18:14:56.000Z","updated_at":"2025-02-19T09:55:26.000Z","dependencies_parsed_at":"2022-08-23T14:21:05.369Z","dependency_job_id":null,"html_url":"https://github.com/Ne-Lexa/php-crossplane","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/Ne-Lexa/php-crossplane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ne-Lexa%2Fphp-crossplane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ne-Lexa%2Fphp-crossplane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ne-Lexa%2Fphp-crossplane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ne-Lexa%2Fphp-crossplane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ne-Lexa","download_url":"https://codeload.github.com/Ne-Lexa/php-crossplane/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ne-Lexa%2Fphp-crossplane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272192669,"owners_count":24889452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-26T02:00:07.904Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":"2024-11-14T14:08:50.134Z","updated_at":"2025-08-26T08:08:56.016Z","avatar_url":"https://github.com/Ne-Lexa.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.svg\" alt=\"crossplane\"/\u003e\n\u003c/p\u003e\n\n# php-crossplane\n**Reliable and fast NGINX configuration file parser and builder**\n\n:information_source: This is a PHP port of the Nginx Python crossplane package which can be found [here](https://github.com/nginxinc/crossplane).\n\n[![Packagist Version](https://img.shields.io/packagist/v/nelexa/crossplane.svg)](https://packagist.org/packages/nelexa/crossplane)\n![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/nelexa/crossplane)\n[![Build Status](https://github.com/Ne-Lexa/php-crossplane/workflows/build/badge.svg)](https://github.com/Ne-Lexa/php-crossplane/actions)\n[![License](https://img.shields.io/github/license/Ne-Lexa/php-crossplane)](https://github.com/Ne-Lexa/php-crossplane/blob/master/LICENSE)\n\n* [Install](#install)\n* [Use in PHP](#use-in-php)\n  * [Parse config](#parse-config)\n  * [Build config from payload](#build-config-from-payload)\n  * [Lex config](#lex-config)\n    * [Register custom Lexer / Builder directives](#register-custom-lexer--builder-directives)\n* [Command Line Interface](#command-line-interface)\n  * [crossplane parse](#crossplane-parse)\n    * [Schema](#schema)\n    * [Example](#example)\n    * [crossplane parse (advanced)](#crossplane-parse-advanced)\n  * [crossplane build](#crossplane-build)\n  * [crossplane lex](#crossplane-lex)\n    * [Example](#example-1)\n  * [crossplane format](#crossplane-format)\n  * [crossplane minify](#crossplane-minify)\n\n## Install\nInstall in project\n```bash\ncomposer require nelexa/crossplane\n```\nGlobal install\n```bash\ncomposer require --global nelexa/crossplane\n```\n\n## Use in PHP\n\n```php\n$crossplane = new \\Nelexa\\NginxParser\\Crossplane();\n\n$lexer = $crossplane-\u003elexer(); // gets \\Nelexa\\NginxParser\\Lexer instance\n$builder = $crossplane-\u003ebuilder(); // gets \\Nelexa\\NginxParser\\Builder instance\n$parser = $crossplane-\u003eparser(); // gets \\Nelexa\\NginxParser\\Parser instance\n$analyzer = $crossplane-\u003eanalyzer(); // gets \\Nelexa\\NginxParser\\Analyzer instance\n$formatter = $crossplane-\u003eformatter(); // gets \\Nelexa\\NginxParser\\Formatter instance\n```\n\n### Parse config\n```php\n$nginxConfigFile = '/etc/nginx/nginx.conf';\n$crossplane = new \\Nelexa\\NginxParser\\Crossplane();\n$payload = $crossplane-\u003eparser()-\u003eparse($nginxConfigFile, $parseOptions = [\n    \\Nelexa\\NginxParser\\Parser::OPTION_COMMENTS =\u003e true,\n    \\Nelexa\\NginxParser\\Parser::OPTION_COMBINE =\u003e true,\n    // etc...\n]);\n```\nThis will return the same payload as described in the [crossplane\nparse](#crossplane-parse) section.\n\n### Build config from payload\n\n```php\n$crossplane = new \\Nelexa\\NginxParser\\Crossplane();\n$config = $crossplane-\u003ebuilder()-\u003ebuild(\n    [[\n        'directive' =\u003e 'events',\n        'args' =\u003e [],\n        'block' =\u003e [[\n            'directive' =\u003e 'worker_connections',\n            'args' =\u003e ['1024'],\n        ]],\n    ]]\n);\n```\n\nThis will return a single string that contains an entire NGINX config\nfile.\n```\nevents {\n    worker_connections 1024;\n}\n```\n\n### Lex config\n\n```php\n$crossplane = new \\Nelexa\\NginxParser\\Crossplane();\n$tokensIterator = $crossplane-\u003elexer()-\u003elex('/etc/nginx/nginx.conf');\n$tokensArray = iterator_to_array($tokensIterator);\n```\n\n`$crossplane-\u003elexer()-\u003elex()` generates 3-tuples.\n```php\n[\n    [\n        'user', // token\n        1,      // line\n        false,  // quote\n    ],\n    [\n        'www-data',\n        1,\n        false,\n    ],\n    [\n        ';',\n        1,\n        false,\n    ],\n    [\n        'worker_processes',\n        2,\n        false,\n    ],\n    [\n        'auto',\n        2,\n        false,\n    ],\n    [\n        ';',\n        2,\n        false,\n    ],\n    [\n        'pid',\n        3,\n        false,\n    ],\n    [\n        '/run/nginx.pid',\n        3,\n        false,\n    ],\n    [\n        ';',\n        3,\n        false,\n    ],\n    // etc\n]\n```\n#### Register custom Lexer / Builder directives\n```php\n$crossplane-\u003eregisterExtension(new class() implements \\Nelexa\\NginxParser\\Ext\\CrossplaneExtension {\npublic function registerExtension(\\Nelexa\\NginxParser\\Crossplane $crossplane): void\n{\n$crossplane-\u003elexer()-\u003eregisterExternalLexer(/* args */);\n$crossplane-\u003ebuilder()-\u003eregisterExternalBuilder(/* args */);\n}\n\n    public function lex(\\Iterator $charIterator, string $directive): ?\\Generator\n    {\n    }\n\n    public function build(array $stmt, string $padding, int $indent = 4, bool $tabs = false): string\n    {\n    }\n});\n```\n\n## Command Line Interface\nTo invoke commands in the command line interface, use `vendor/bin/crossplane` if you have installed the package locally in the project, and `crossplane` if you have installed the package globally.\n\n```\nUsage:\n  vendor/bin/crossplane command [options] [arguments]\n\nOptions:\n  -h, --help            Display this help message\n  -q, --quiet           Do not output any message\n  -V, --version         Display this application version\n      --ansi            Force ANSI output\n      --no-ansi         Disable ANSI output\n  -n, --no-interaction  Do not ask any interactive question\n  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\n\nAvailable commands:\n  build   builds an nginx config from a json payload\n  format  formats an nginx config file\n  help    Display help for a command\n  lex     lexes tokens from an nginx config file\n  minify  removes all whitespace from an nginx config\n  parse   parses a json payload for an nginx config\n```\n\n### crossplane parse\n\nThis command will take a path to a main NGINX config file as input, then\nparse the entire config into the schema defined below, and dumps the\nentire thing as a JSON payload.\n\n```\nDescription:\n  parses a json payload for an nginx config\n\nUsage:\n  vendor/bin/crossplane parse [options] [--] \u003cfilename\u003e\n\nArguments:\n  filename                the nginx config file\n\nOptions:\n  -o, --out[=OUT]         write output to a file\n  -i, --indent[=INDENT]   number of spaces to indent output [default: 0]\n      --ignore[=IGNORE]   ignore directives (comma-separated) (multiple values allowed)\n      --no-catch          only collect first error in file\n      --tb-onerror        include tracebacks in config errors\n      --combine           use includes to create one single file\n      --single-file       do not include other config files\n      --include-comments  include comments in json\n      --strict            raise errors for unknown directives\n  -h, --help              Display this help message\n  -q, --quiet             Do not output any message\n  -V, --version           Display this application version\n      --ansi              Force ANSI output\n      --no-ansi           Disable ANSI output\n  -n, --no-interaction    Do not ask any interactive question\n  -v|vv|vvv, --verbose    Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\n```\n\n**Privacy and Security**\n\nSince `crossplane` is usually used to create payloads that are sent to\ndifferent servers, it's important to keep security in mind. For that\nreason, the `--ignore` option was added. It can be used to keep certain\nsensitive directives out of the payload output entirely.\n\nFor example, we always use the equivalent of this flag in the [NGINX Amplify\nAgent](https://github.com/nginxinc/nginx-amplify-agent/) out of respect\nfor our users'\nprivacy:\n\n    --ignore=auth_basic_user_file,secure_link_secret,ssl_certificate_key,ssl_client_certificate,ssl_password_file,ssl_stapling_file,ssl_trusted_certificate\n\n#### Schema\n\n**Response Object**\n\n```js\n{\n    \"status\": String, // \"ok\" or \"failed\" if \"errors\" is not empty\n    \"errors\": Array,  // aggregation of \"errors\" from Config objects\n    \"config\": Array   // Array of Config objects\n}\n```\n\n**Config Object**\n\n```js\n{\n    \"file\": String,   // the full path of the config file\n    \"status\": String, // \"ok\" or \"failed\" if errors is not empty array\n    \"errors\": Array,  // Array of Error objects\n    \"parsed\": Array   // Array of Directive objects\n}\n```\n\n**Directive Object**\n\n```js\n{\n    \"directive\": String, // the name of the directive\n    \"line\": Number,      // integer line number the directive started on\n    \"args\": Array,       // Array of String arguments\n    \"includes\": Array,   // Array of integers (included iff this is an include directive)\n    \"block\": Array       // Array of Directive Objects (included iff this is a block)\n}\n```\n\n\u003cdiv class=\"note\"\u003e\n\n\u003cdiv class=\"admonition-title\"\u003e\n\nNote\n\n\u003c/div\u003e\n\nIf this is an `include` directive and the `--single-file` flag was not\nused, an `\"includes\"` value will be used that holds an Array of indices\nof the configs that are included by this directive.\n\nIf this is a block directive, a `\"block\"` value will be used that holds\nan Array of more Directive Objects that define the block context.\n\n\u003c/div\u003e\n\n**Error Object**\n\n```js\n{\n    \"file\": String,     // the full path of the config file\n    \"line\": Number,     // integer line number the directive that caused the error\n    \"error\": String,    // the error message\n    \"callback\": Object  // only included iff an \"onerror\" function was passed to parse()\n}\n```\n\n\u003cdiv class=\"note\"\u003e\n\n\u003cdiv class=\"admonition-title\"\u003e\n\nNote\n\n\u003c/div\u003e\n\nIf the `--tb-onerror` flag was used by crossplane parse, `\"callback\"`\nwill contain a string that represents the traceback that the error\ncaused.\n\n\u003c/div\u003e\n\n#### Example\n\nThe main NGINX config file is at `/etc/nginx/nginx.conf`:\n\n```nginx\nevents {\n    worker_connections 1024;\n}\n\nhttp {\n    include conf.d/*.conf;\n}\n```\n\nAnd this config file is at `/etc/nginx/conf.d/servers.conf`:\n\n```nginx\nserver {\n    listen 8080;\n    location / {\n        try_files 'foo bar' baz;\n    }\n}\n\nserver {\n    listen 8081;\n    location / {\n        return 200 'success!';\n    }\n}\n```\n\nSo then if you run this:\n\n    vendor/bin/crossplane parse --indent=4 /etc/nginx/nginx.conf\n\nThe prettified JSON output would look like this:\n\n```js\n{\n    \"status\": \"ok\",\n    \"errors\": [],\n    \"config\": [\n        {\n            \"file\": \"/etc/nginx/nginx.conf\",\n            \"status\": \"ok\",\n            \"errors\": [],\n            \"parsed\": [\n                {\n                    \"directive\": \"events\",\n                    \"line\": 1,\n                    \"args\": [],\n                    \"block\": [\n                        {\n                            \"directive\": \"worker_connections\",\n                            \"line\": 2,\n                            \"args\": [\n                                \"1024\"\n                            ]\n                        }\n                    ]\n                },\n                {\n                    \"directive\": \"http\",\n                    \"line\": 5,\n                    \"args\": [],\n                    \"block\": [\n                        {\n                            \"directive\": \"include\",\n                            \"line\": 6,\n                            \"args\": [\n                                \"conf.d/*.conf\"\n                            ],\n                            \"includes\": [\n                                1\n                            ]\n                        }\n                    ]\n                }\n            ]\n        },\n        {\n            \"file\": \"/etc/nginx/conf.d/servers.conf\",\n            \"status\": \"ok\",\n            \"errors\": [],\n            \"parsed\": [\n                {\n                    \"directive\": \"server\",\n                    \"line\": 1,\n                    \"args\": [],\n                    \"block\": [\n                        {\n                            \"directive\": \"listen\",\n                            \"line\": 2,\n                            \"args\": [\n                                \"8080\"\n                            ]\n                        },\n                        {\n                            \"directive\": \"location\",\n                            \"line\": 3,\n                            \"args\": [\n                                \"/\"\n                            ],\n                            \"block\": [\n                                {\n                                    \"directive\": \"try_files\",\n                                    \"line\": 4,\n                                    \"args\": [\n                                        \"foo bar\",\n                                        \"baz\"\n                                    ]\n                                }\n                            ]\n                        }\n                    ]\n                },\n                {\n                    \"directive\": \"server\",\n                    \"line\": 8,\n                    \"args\": [],\n                    \"block\": [\n                        {\n                            \"directive\": \"listen\",\n                            \"line\": 9,\n                            \"args\": [\n                                \"8081\"\n                            ]\n                        },\n                        {\n                            \"directive\": \"location\",\n                            \"line\": 10,\n                            \"args\": [\n                                \"/\"\n                            ],\n                            \"block\": [\n                                {\n                                    \"directive\": \"return\",\n                                    \"line\": 11,\n                                    \"args\": [\n                                        \"200\",\n                                        \"success!\"\n                                    ]\n                                }\n                            ]\n                        }\n                    ]\n                }\n            ]\n        }\n    ]\n}\n```\n\n#### crossplane parse (advanced)\n\nThis tool uses two flags that can change how `crossplane` handles\nerrors.\n\nThe first, `--no-catch`, can be used if you'd prefer that crossplane\nquit parsing after the first error it finds.\n\nThe second, `--tb-onerror`, will add a `\"callback\"` key to all error\nobjects in the JSON output, each containing a string representation of\nthe traceback that would have been raised by the parser if the exception\nhad not been caught. This can be useful for logging purposes.\n\n### crossplane build\n\nThis command will take a path to a file as input. The file should\ncontain a JSON representation of an NGINX config that has the structure\ndefined above. Saving and using the output from `crossplane parse` to\nrebuild your config files should not cause any differences in content\nexcept for the formatting.\n\n```\nDescription:\n  builds an nginx config from a json payload\n\nUsage:\n  vendor/bin/crossplane build [options] [--] \u003cfilename\u003e\n\nArguments:\n  filename               the file with the config payload\n\nOptions:\n  -d, --dir[=DIR]        the base directory to build in [default: $PWD]\n  -f, --force            overwrite existing files\n  -i, --indent[=INDENT]  number of spaces to indent output [default: 4]\n  -t, --tabs             indent with tabs instead of spaces\n      --no-headers       do not write header to configs\n      --stdout           write configs to stdout instead\n  -h, --help             Display this help message\n  -q, --quiet            Do not output any message\n  -V, --version          Display this application version\n      --ansi             Force ANSI output\n      --no-ansi          Disable ANSI output\n  -n, --no-interaction   Do not ask any interactive question\n  -v|vv|vvv, --verbose   Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\n```\n\n### crossplane lex\n\nThis command takes an NGINX config file, splits it into tokens by\nremoving whitespace and comments, and dumps the list of tokens as a JSON\narray.\n\n```\nDescription:\n  lexes tokens from an nginx config file\n\nUsage:\n  vendor/bin/crossplane lex [options] [--] \u003cfilename\u003e\n\nArguments:\n  filename               the nginx config file\n\nOptions:\n  -o, --out[=OUT]        write output to a file\n  -i, --indent[=INDENT]  number of spaces to indent output [default: 0]\n  -l, --line-numbers     include line numbers in json payload\n  -h, --help             Display this help message\n  -q, --quiet            Do not output any message\n  -V, --version          Display this application version\n      --ansi             Force ANSI output\n      --no-ansi          Disable ANSI output\n  -n, --no-interaction   Do not ask any interactive question\n  -v|vv|vvv, --verbose   Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\n```\n\n#### Example\n\nPassing in this NGINX config file at `/etc/nginx/nginx.conf`:\n\n```nginx\nevents {\n    worker_connections 1024;\n}\n\nhttp {\n    include conf.d/*.conf;\n}\n```\n\nBy running:\n\n    vendor/bin/crossplane lex /etc/nginx/nginx.conf\n\nWill result in this JSON\noutput:\n\n```js\n[\"events\",\"{\",\"worker_connections\",\"1024\",\";\",\"}\",\"http\",\"{\",\"include\",\"conf.d/*.conf\",\";\",\"}\"]\n```\n\nHowever, if you decide to use the `--line-numbers` flag, your output\nwill look\nlike:\n\n```js\n[[\"events\",1],[\"{\",1],[\"worker_connections\",2],[\"1024\",2],[\";\",2],[\"}\",3],[\"http\",5],[\"{\",5],[\"include\",6],[\"conf.d/*.conf\",6],[\";\",6],[\"}\",7]]\n```\n\n### crossplane format\n\nThis is a quick and dirty tool that uses [crossplane\nparse](#crossplane-parse) internally to format an NGINX config file.\nIt serves the purpose of demonstrating what you can do with `crossplane`'s\nparsing abilities. It is not meant to be a fully fleshed out, feature-rich\nformatting tool. If that is what you are looking for, then you may want to\nlook writing your own using crossplane's PHP API.\n\n```\nDescription:\n  formats an nginx config file\n\nUsage:\n  vendor/bin/crossplane format [options] [--] \u003cfilename\u003e\n\nArguments:\n  filename               the nginx config file\n\nOptions:\n  -o, --out[=OUT]        write output to a file\n  -i, --indent[=INDENT]  number of spaces to indent output [default: 4]\n  -t, --tabs             indent with tabs instead of spaces\n  -h, --help             Display this help message\n  -q, --quiet            Do not output any message\n  -V, --version          Display this application version\n      --ansi             Force ANSI output\n      --no-ansi          Disable ANSI output\n  -n, --no-interaction   Do not ask any interactive question\n  -v|vv|vvv, --verbose   Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\n```\n\n### crossplane minify\n\nThis is a simple and fun little tool that uses [crossplane\nlex](#crossplane-lex) internally to remove as much whitespace from an\nNGINX config file as possible without affecting what it does. It can't\nimagine it will have much of a use to most people, but it demonstrates\nthe kinds of things you can do with `crossplane`'s lexing abilities.\n\n```\nDescription:\n  removes all whitespace from an nginx config\n\nUsage:\n  vendor/bin/crossplane minify [options] [--] \u003cfilename\u003e\n\nArguments:\n  filename              the nginx config file\n\nOptions:\n  -o, --out[=OUT]       write output to a file\n  -h, --help            Display this help message\n  -q, --quiet           Do not output any message\n  -V, --version         Display this application version\n      --ansi            Force ANSI output\n      --no-ansi         Disable ANSI output\n  -n, --no-interaction  Do not ask any interactive question\n  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fne-lexa%2Fphp-crossplane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fne-lexa%2Fphp-crossplane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fne-lexa%2Fphp-crossplane/lists"}