├── .github ├── FUNDING.yml └── ISSUE_TEMPLATES │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── docs ├── LibSQL.md ├── Providers │ └── HttpClient.md ├── Quickstart.md ├── README.md ├── Traits │ ├── Logging.md │ └── MapResults.md ├── Types │ ├── Authoriy.md │ ├── Config.md │ ├── ExpandedConfig.md │ ├── ExpandedScheme.md │ ├── HeirPart.md │ ├── HttpResponse.md │ ├── HttpResultSets.md │ ├── HttpStatement.md │ ├── KeyValue.md │ ├── LibSQLResult.md │ ├── Query.md │ ├── TransactionMode.md │ ├── Uri.md │ └── UserInfo.md └── Utils │ ├── Exceptions │ └── LibsqlError.md │ ├── constants.md │ └── helpers.md ├── examples ├── .gitkeep ├── local-file │ ├── check-version.php │ ├── execute.php │ └── placeholders.php ├── remote-http │ ├── batch-query.php │ ├── sequence-query.php │ ├── simple-query.php │ └── transaction-query.php └── remote-replica │ └── connection.php └── src ├── LibSQL.php ├── Providers ├── HttpClient.php ├── LocalClient.php └── RemoteReplicaClient.php ├── Traits ├── Logging.php └── MapResults.php ├── Types ├── Authority.php ├── Config.php ├── ExpandedConfig.php ├── ExpandedScheme.php ├── HierPart.php ├── HttpResponse.php ├── HttpResultSets.php ├── HttpStatement.php ├── HttpTransaction.php ├── KeyValue.php ├── LibSQLResult.php ├── Query.php ├── TransactionMode.php ├── Uri.php └── UserInfo.php └── Utils ├── Exceptions └── LibsqlError.php ├── Mods.php └── helpers.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: darkterminal # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: https://paypal.me/lazarusalhambra # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATES/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATES/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATES/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | playground/ 2 | vendor/ 3 | .vscode/ 4 | taggen 5 | .env 6 | libsql-php 7 | examples/*.db 8 | *.log 9 | *.db 10 | _intelephense_helper.php 11 | orchestrators/ 12 | *.db* 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Imam Ali Mustofa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

🚨 THIS REPOSITORY IS READ-ONLY 🚨

2 |

This repository is no longer under maintenance and has been moved to
the official Turso Database repository under the name Turso Client PHP

3 | 4 |

5 | 6 | Turso + TypeScript 7 |

Turso + PHP

8 | 9 |

10 | 11 |

12 | SQLite for Production. Powered by libSQL. 13 |

14 | 15 |

16 | Turso · 17 | Quickstart · 18 | Examples · 19 | Docs · 20 | Discord · 21 | Blog & Tutorials 22 |

23 | 24 | --- 25 | 26 | ## Documentation 27 | 28 | 1. [Turso Quickstart](https://docs.turso.tech/quickstart) — Learn how create and connect your first database. 29 | 2. [SDK Quickstart](/docs/Quickstart.md) — Learn how to install and execute queries using the libSQL client. 30 | 3. [SDK Reference](/docs/LibSQL.md) — Dive deeper with the libSQL SDK reference and examples. 31 | 32 | ### What is Turso? 33 | 34 | [Turso](https://turso.tech) is a SQLite-compatible database built on [libSQL](https://docs.turso.tech/libsql), the Open Contribution fork of SQLite. It enables scaling to hundreds of thousands of databases per organization and supports replication to any location, including your own servers, for microsecond-latency access. 35 | 36 | Learn more about what you can do with Turso: 37 | 38 | - [Embedded Replicas](https://docs.turso.tech/features/embedded-replicas) 39 | - [Platform API](https://docs.turso.tech/features/platform-api) 40 | - [Data Edge](https://docs.turso.tech/features/data-edge) 41 | - [Branching](https://docs.turso.tech/features/branching) 42 | - [Point-in-Time Recovery](https://docs.turso.tech/features/point-in-time-recovery) 43 | - [Scale to Zero](https://docs.turso.tech/features/scale-to-zero) 44 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "darkterminal/libsql-client-php", 3 | "description": "PHP client API for libSQL", 4 | "license": "MIT", 5 | "autoload": { 6 | "psr-4": { 7 | "Darkterminal\\LibSQL\\": "src/" 8 | }, 9 | "files": [ 10 | "src/Utils/helpers.php" 11 | ] 12 | }, 13 | "authors": [ 14 | { 15 | "name": "Imam Ali Mustofa", 16 | "email": "darkterminal@duck.com" 17 | } 18 | ], 19 | "scripts": { 20 | "post-install-cmd": ["./vendor/bin/build"], 21 | "post-update-cmd": ["./vendor/bin/build"] 22 | }, 23 | "require": { 24 | "guzzlehttp/guzzle": "^7.0", 25 | "darkterminal/libsql-php-ext": "^1.0" 26 | }, 27 | "funding": [ 28 | { 29 | "type": "github", 30 | "url": "https://github.com/sponsors/darkterminal" 31 | }, 32 | { 33 | "type": "other", 34 | "url": "https://paypal.me/lazarusalhambra" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "a5cab5b0a3322cb4d3ef17c4d608e4ae", 8 | "packages": [ 9 | { 10 | "name": "darkterminal/libsql-php-ext", 11 | "version": "v1.0.1", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/darkterminal/libsql-php-ext.git", 15 | "reference": "00bea7e8bfdcd55ba353bb3dfc41bdbe5b39baef" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/darkterminal/libsql-php-ext/zipball/00bea7e8bfdcd55ba353bb3dfc41bdbe5b39baef", 20 | "reference": "00bea7e8bfdcd55ba353bb3dfc41bdbe5b39baef", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=8.3" 25 | }, 26 | "bin": [ 27 | "build" 28 | ], 29 | "type": "library", 30 | "autoload": { 31 | "files": [ 32 | "php-src/constants.php", 33 | "php-src/helpers.php" 34 | ], 35 | "psr-4": { 36 | "Darkterminal\\LibSQLPHPExtension\\": "php-src/" 37 | } 38 | }, 39 | "notification-url": "https://packagist.org/downloads/", 40 | "license": [ 41 | "MIT" 42 | ], 43 | "authors": [ 44 | { 45 | "name": "Imam Ali Mustofa", 46 | "email": "darkterminal@duck.com" 47 | } 48 | ], 49 | "description": "LibSQL Native Extension for PHP", 50 | "support": { 51 | "issues": "https://github.com/darkterminal/libsql-php-ext/issues", 52 | "source": "https://github.com/darkterminal/libsql-php-ext/tree/v1.0.1" 53 | }, 54 | "funding": [ 55 | { 56 | "url": "https://paypal.me/lazarusalhambra", 57 | "type": "custom" 58 | }, 59 | { 60 | "url": "https://github.com/darkterminal", 61 | "type": "github" 62 | } 63 | ], 64 | "time": "2024-05-19T05:14:23+00:00" 65 | }, 66 | { 67 | "name": "guzzlehttp/guzzle", 68 | "version": "7.8.1", 69 | "source": { 70 | "type": "git", 71 | "url": "https://github.com/guzzle/guzzle.git", 72 | "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" 73 | }, 74 | "dist": { 75 | "type": "zip", 76 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", 77 | "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", 78 | "shasum": "" 79 | }, 80 | "require": { 81 | "ext-json": "*", 82 | "guzzlehttp/promises": "^1.5.3 || ^2.0.1", 83 | "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", 84 | "php": "^7.2.5 || ^8.0", 85 | "psr/http-client": "^1.0", 86 | "symfony/deprecation-contracts": "^2.2 || ^3.0" 87 | }, 88 | "provide": { 89 | "psr/http-client-implementation": "1.0" 90 | }, 91 | "require-dev": { 92 | "bamarni/composer-bin-plugin": "^1.8.2", 93 | "ext-curl": "*", 94 | "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", 95 | "php-http/message-factory": "^1.1", 96 | "phpunit/phpunit": "^8.5.36 || ^9.6.15", 97 | "psr/log": "^1.1 || ^2.0 || ^3.0" 98 | }, 99 | "suggest": { 100 | "ext-curl": "Required for CURL handler support", 101 | "ext-intl": "Required for Internationalized Domain Name (IDN) support", 102 | "psr/log": "Required for using the Log middleware" 103 | }, 104 | "type": "library", 105 | "extra": { 106 | "bamarni-bin": { 107 | "bin-links": true, 108 | "forward-command": false 109 | } 110 | }, 111 | "autoload": { 112 | "files": [ 113 | "src/functions_include.php" 114 | ], 115 | "psr-4": { 116 | "GuzzleHttp\\": "src/" 117 | } 118 | }, 119 | "notification-url": "https://packagist.org/downloads/", 120 | "license": [ 121 | "MIT" 122 | ], 123 | "authors": [ 124 | { 125 | "name": "Graham Campbell", 126 | "email": "hello@gjcampbell.co.uk", 127 | "homepage": "https://github.com/GrahamCampbell" 128 | }, 129 | { 130 | "name": "Michael Dowling", 131 | "email": "mtdowling@gmail.com", 132 | "homepage": "https://github.com/mtdowling" 133 | }, 134 | { 135 | "name": "Jeremy Lindblom", 136 | "email": "jeremeamia@gmail.com", 137 | "homepage": "https://github.com/jeremeamia" 138 | }, 139 | { 140 | "name": "George Mponos", 141 | "email": "gmponos@gmail.com", 142 | "homepage": "https://github.com/gmponos" 143 | }, 144 | { 145 | "name": "Tobias Nyholm", 146 | "email": "tobias.nyholm@gmail.com", 147 | "homepage": "https://github.com/Nyholm" 148 | }, 149 | { 150 | "name": "Márk Sági-Kazár", 151 | "email": "mark.sagikazar@gmail.com", 152 | "homepage": "https://github.com/sagikazarmark" 153 | }, 154 | { 155 | "name": "Tobias Schultze", 156 | "email": "webmaster@tubo-world.de", 157 | "homepage": "https://github.com/Tobion" 158 | } 159 | ], 160 | "description": "Guzzle is a PHP HTTP client library", 161 | "keywords": [ 162 | "client", 163 | "curl", 164 | "framework", 165 | "http", 166 | "http client", 167 | "psr-18", 168 | "psr-7", 169 | "rest", 170 | "web service" 171 | ], 172 | "support": { 173 | "issues": "https://github.com/guzzle/guzzle/issues", 174 | "source": "https://github.com/guzzle/guzzle/tree/7.8.1" 175 | }, 176 | "funding": [ 177 | { 178 | "url": "https://github.com/GrahamCampbell", 179 | "type": "github" 180 | }, 181 | { 182 | "url": "https://github.com/Nyholm", 183 | "type": "github" 184 | }, 185 | { 186 | "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", 187 | "type": "tidelift" 188 | } 189 | ], 190 | "time": "2023-12-03T20:35:24+00:00" 191 | }, 192 | { 193 | "name": "guzzlehttp/promises", 194 | "version": "2.0.2", 195 | "source": { 196 | "type": "git", 197 | "url": "https://github.com/guzzle/promises.git", 198 | "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" 199 | }, 200 | "dist": { 201 | "type": "zip", 202 | "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", 203 | "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", 204 | "shasum": "" 205 | }, 206 | "require": { 207 | "php": "^7.2.5 || ^8.0" 208 | }, 209 | "require-dev": { 210 | "bamarni/composer-bin-plugin": "^1.8.2", 211 | "phpunit/phpunit": "^8.5.36 || ^9.6.15" 212 | }, 213 | "type": "library", 214 | "extra": { 215 | "bamarni-bin": { 216 | "bin-links": true, 217 | "forward-command": false 218 | } 219 | }, 220 | "autoload": { 221 | "psr-4": { 222 | "GuzzleHttp\\Promise\\": "src/" 223 | } 224 | }, 225 | "notification-url": "https://packagist.org/downloads/", 226 | "license": [ 227 | "MIT" 228 | ], 229 | "authors": [ 230 | { 231 | "name": "Graham Campbell", 232 | "email": "hello@gjcampbell.co.uk", 233 | "homepage": "https://github.com/GrahamCampbell" 234 | }, 235 | { 236 | "name": "Michael Dowling", 237 | "email": "mtdowling@gmail.com", 238 | "homepage": "https://github.com/mtdowling" 239 | }, 240 | { 241 | "name": "Tobias Nyholm", 242 | "email": "tobias.nyholm@gmail.com", 243 | "homepage": "https://github.com/Nyholm" 244 | }, 245 | { 246 | "name": "Tobias Schultze", 247 | "email": "webmaster@tubo-world.de", 248 | "homepage": "https://github.com/Tobion" 249 | } 250 | ], 251 | "description": "Guzzle promises library", 252 | "keywords": [ 253 | "promise" 254 | ], 255 | "support": { 256 | "issues": "https://github.com/guzzle/promises/issues", 257 | "source": "https://github.com/guzzle/promises/tree/2.0.2" 258 | }, 259 | "funding": [ 260 | { 261 | "url": "https://github.com/GrahamCampbell", 262 | "type": "github" 263 | }, 264 | { 265 | "url": "https://github.com/Nyholm", 266 | "type": "github" 267 | }, 268 | { 269 | "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", 270 | "type": "tidelift" 271 | } 272 | ], 273 | "time": "2023-12-03T20:19:20+00:00" 274 | }, 275 | { 276 | "name": "guzzlehttp/psr7", 277 | "version": "2.6.2", 278 | "source": { 279 | "type": "git", 280 | "url": "https://github.com/guzzle/psr7.git", 281 | "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" 282 | }, 283 | "dist": { 284 | "type": "zip", 285 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", 286 | "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", 287 | "shasum": "" 288 | }, 289 | "require": { 290 | "php": "^7.2.5 || ^8.0", 291 | "psr/http-factory": "^1.0", 292 | "psr/http-message": "^1.1 || ^2.0", 293 | "ralouphie/getallheaders": "^3.0" 294 | }, 295 | "provide": { 296 | "psr/http-factory-implementation": "1.0", 297 | "psr/http-message-implementation": "1.0" 298 | }, 299 | "require-dev": { 300 | "bamarni/composer-bin-plugin": "^1.8.2", 301 | "http-interop/http-factory-tests": "^0.9", 302 | "phpunit/phpunit": "^8.5.36 || ^9.6.15" 303 | }, 304 | "suggest": { 305 | "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" 306 | }, 307 | "type": "library", 308 | "extra": { 309 | "bamarni-bin": { 310 | "bin-links": true, 311 | "forward-command": false 312 | } 313 | }, 314 | "autoload": { 315 | "psr-4": { 316 | "GuzzleHttp\\Psr7\\": "src/" 317 | } 318 | }, 319 | "notification-url": "https://packagist.org/downloads/", 320 | "license": [ 321 | "MIT" 322 | ], 323 | "authors": [ 324 | { 325 | "name": "Graham Campbell", 326 | "email": "hello@gjcampbell.co.uk", 327 | "homepage": "https://github.com/GrahamCampbell" 328 | }, 329 | { 330 | "name": "Michael Dowling", 331 | "email": "mtdowling@gmail.com", 332 | "homepage": "https://github.com/mtdowling" 333 | }, 334 | { 335 | "name": "George Mponos", 336 | "email": "gmponos@gmail.com", 337 | "homepage": "https://github.com/gmponos" 338 | }, 339 | { 340 | "name": "Tobias Nyholm", 341 | "email": "tobias.nyholm@gmail.com", 342 | "homepage": "https://github.com/Nyholm" 343 | }, 344 | { 345 | "name": "Márk Sági-Kazár", 346 | "email": "mark.sagikazar@gmail.com", 347 | "homepage": "https://github.com/sagikazarmark" 348 | }, 349 | { 350 | "name": "Tobias Schultze", 351 | "email": "webmaster@tubo-world.de", 352 | "homepage": "https://github.com/Tobion" 353 | }, 354 | { 355 | "name": "Márk Sági-Kazár", 356 | "email": "mark.sagikazar@gmail.com", 357 | "homepage": "https://sagikazarmark.hu" 358 | } 359 | ], 360 | "description": "PSR-7 message implementation that also provides common utility methods", 361 | "keywords": [ 362 | "http", 363 | "message", 364 | "psr-7", 365 | "request", 366 | "response", 367 | "stream", 368 | "uri", 369 | "url" 370 | ], 371 | "support": { 372 | "issues": "https://github.com/guzzle/psr7/issues", 373 | "source": "https://github.com/guzzle/psr7/tree/2.6.2" 374 | }, 375 | "funding": [ 376 | { 377 | "url": "https://github.com/GrahamCampbell", 378 | "type": "github" 379 | }, 380 | { 381 | "url": "https://github.com/Nyholm", 382 | "type": "github" 383 | }, 384 | { 385 | "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", 386 | "type": "tidelift" 387 | } 388 | ], 389 | "time": "2023-12-03T20:05:35+00:00" 390 | }, 391 | { 392 | "name": "psr/http-client", 393 | "version": "1.0.3", 394 | "source": { 395 | "type": "git", 396 | "url": "https://github.com/php-fig/http-client.git", 397 | "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" 398 | }, 399 | "dist": { 400 | "type": "zip", 401 | "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", 402 | "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", 403 | "shasum": "" 404 | }, 405 | "require": { 406 | "php": "^7.0 || ^8.0", 407 | "psr/http-message": "^1.0 || ^2.0" 408 | }, 409 | "type": "library", 410 | "extra": { 411 | "branch-alias": { 412 | "dev-master": "1.0.x-dev" 413 | } 414 | }, 415 | "autoload": { 416 | "psr-4": { 417 | "Psr\\Http\\Client\\": "src/" 418 | } 419 | }, 420 | "notification-url": "https://packagist.org/downloads/", 421 | "license": [ 422 | "MIT" 423 | ], 424 | "authors": [ 425 | { 426 | "name": "PHP-FIG", 427 | "homepage": "https://www.php-fig.org/" 428 | } 429 | ], 430 | "description": "Common interface for HTTP clients", 431 | "homepage": "https://github.com/php-fig/http-client", 432 | "keywords": [ 433 | "http", 434 | "http-client", 435 | "psr", 436 | "psr-18" 437 | ], 438 | "support": { 439 | "source": "https://github.com/php-fig/http-client" 440 | }, 441 | "time": "2023-09-23T14:17:50+00:00" 442 | }, 443 | { 444 | "name": "psr/http-factory", 445 | "version": "1.1.0", 446 | "source": { 447 | "type": "git", 448 | "url": "https://github.com/php-fig/http-factory.git", 449 | "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" 450 | }, 451 | "dist": { 452 | "type": "zip", 453 | "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", 454 | "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", 455 | "shasum": "" 456 | }, 457 | "require": { 458 | "php": ">=7.1", 459 | "psr/http-message": "^1.0 || ^2.0" 460 | }, 461 | "type": "library", 462 | "extra": { 463 | "branch-alias": { 464 | "dev-master": "1.0.x-dev" 465 | } 466 | }, 467 | "autoload": { 468 | "psr-4": { 469 | "Psr\\Http\\Message\\": "src/" 470 | } 471 | }, 472 | "notification-url": "https://packagist.org/downloads/", 473 | "license": [ 474 | "MIT" 475 | ], 476 | "authors": [ 477 | { 478 | "name": "PHP-FIG", 479 | "homepage": "https://www.php-fig.org/" 480 | } 481 | ], 482 | "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", 483 | "keywords": [ 484 | "factory", 485 | "http", 486 | "message", 487 | "psr", 488 | "psr-17", 489 | "psr-7", 490 | "request", 491 | "response" 492 | ], 493 | "support": { 494 | "source": "https://github.com/php-fig/http-factory" 495 | }, 496 | "time": "2024-04-15T12:06:14+00:00" 497 | }, 498 | { 499 | "name": "psr/http-message", 500 | "version": "2.0", 501 | "source": { 502 | "type": "git", 503 | "url": "https://github.com/php-fig/http-message.git", 504 | "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" 505 | }, 506 | "dist": { 507 | "type": "zip", 508 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", 509 | "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", 510 | "shasum": "" 511 | }, 512 | "require": { 513 | "php": "^7.2 || ^8.0" 514 | }, 515 | "type": "library", 516 | "extra": { 517 | "branch-alias": { 518 | "dev-master": "2.0.x-dev" 519 | } 520 | }, 521 | "autoload": { 522 | "psr-4": { 523 | "Psr\\Http\\Message\\": "src/" 524 | } 525 | }, 526 | "notification-url": "https://packagist.org/downloads/", 527 | "license": [ 528 | "MIT" 529 | ], 530 | "authors": [ 531 | { 532 | "name": "PHP-FIG", 533 | "homepage": "https://www.php-fig.org/" 534 | } 535 | ], 536 | "description": "Common interface for HTTP messages", 537 | "homepage": "https://github.com/php-fig/http-message", 538 | "keywords": [ 539 | "http", 540 | "http-message", 541 | "psr", 542 | "psr-7", 543 | "request", 544 | "response" 545 | ], 546 | "support": { 547 | "source": "https://github.com/php-fig/http-message/tree/2.0" 548 | }, 549 | "time": "2023-04-04T09:54:51+00:00" 550 | }, 551 | { 552 | "name": "ralouphie/getallheaders", 553 | "version": "3.0.3", 554 | "source": { 555 | "type": "git", 556 | "url": "https://github.com/ralouphie/getallheaders.git", 557 | "reference": "120b605dfeb996808c31b6477290a714d356e822" 558 | }, 559 | "dist": { 560 | "type": "zip", 561 | "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", 562 | "reference": "120b605dfeb996808c31b6477290a714d356e822", 563 | "shasum": "" 564 | }, 565 | "require": { 566 | "php": ">=5.6" 567 | }, 568 | "require-dev": { 569 | "php-coveralls/php-coveralls": "^2.1", 570 | "phpunit/phpunit": "^5 || ^6.5" 571 | }, 572 | "type": "library", 573 | "autoload": { 574 | "files": [ 575 | "src/getallheaders.php" 576 | ] 577 | }, 578 | "notification-url": "https://packagist.org/downloads/", 579 | "license": [ 580 | "MIT" 581 | ], 582 | "authors": [ 583 | { 584 | "name": "Ralph Khattar", 585 | "email": "ralph.khattar@gmail.com" 586 | } 587 | ], 588 | "description": "A polyfill for getallheaders.", 589 | "support": { 590 | "issues": "https://github.com/ralouphie/getallheaders/issues", 591 | "source": "https://github.com/ralouphie/getallheaders/tree/develop" 592 | }, 593 | "time": "2019-03-08T08:55:37+00:00" 594 | }, 595 | { 596 | "name": "symfony/deprecation-contracts", 597 | "version": "v3.5.0", 598 | "source": { 599 | "type": "git", 600 | "url": "https://github.com/symfony/deprecation-contracts.git", 601 | "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" 602 | }, 603 | "dist": { 604 | "type": "zip", 605 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", 606 | "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", 607 | "shasum": "" 608 | }, 609 | "require": { 610 | "php": ">=8.1" 611 | }, 612 | "type": "library", 613 | "extra": { 614 | "branch-alias": { 615 | "dev-main": "3.5-dev" 616 | }, 617 | "thanks": { 618 | "name": "symfony/contracts", 619 | "url": "https://github.com/symfony/contracts" 620 | } 621 | }, 622 | "autoload": { 623 | "files": [ 624 | "function.php" 625 | ] 626 | }, 627 | "notification-url": "https://packagist.org/downloads/", 628 | "license": [ 629 | "MIT" 630 | ], 631 | "authors": [ 632 | { 633 | "name": "Nicolas Grekas", 634 | "email": "p@tchwork.com" 635 | }, 636 | { 637 | "name": "Symfony Community", 638 | "homepage": "https://symfony.com/contributors" 639 | } 640 | ], 641 | "description": "A generic function and convention to trigger deprecation notices", 642 | "homepage": "https://symfony.com", 643 | "support": { 644 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" 645 | }, 646 | "funding": [ 647 | { 648 | "url": "https://symfony.com/sponsor", 649 | "type": "custom" 650 | }, 651 | { 652 | "url": "https://github.com/fabpot", 653 | "type": "github" 654 | }, 655 | { 656 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 657 | "type": "tidelift" 658 | } 659 | ], 660 | "time": "2024-04-18T09:32:20+00:00" 661 | } 662 | ], 663 | "packages-dev": [], 664 | "aliases": [], 665 | "minimum-stability": "stable", 666 | "stability-flags": [], 667 | "prefer-stable": false, 668 | "prefer-lowest": false, 669 | "platform": [], 670 | "platform-dev": [], 671 | "plugin-api-version": "2.6.0" 672 | } 673 | -------------------------------------------------------------------------------- /docs/LibSQL.md: -------------------------------------------------------------------------------- 1 | # LibSQL 2 | 3 | The main class for interacting with the LibSQL service. This class provides functionality for creating an HTTP client and Local client based on the provided configuration. It supports different URL schemes such as "file:", "libsql:", "https:", and "http:". It also handles errors related to unsupported URL schemes and TLS configurations. 4 | 5 | ## Instanciated 6 | 7 | This constructor initializes a new instance of LibSQL based on the provided configuration. It supports both local and remote connections. 8 | 9 | For a **local connection**, an example configuration includes specifying a file URL along with flags for opening the database file. Encryption key can also be provided if needed. 10 | 11 | For a **remote connection**, the configuration includes the URL of the remote server, an authentication token, and an optional TLS flag. 12 | 13 | For a **remote replica connection**, need to configure with associative array that includes the `url` which is the path to the database file, `authToken`, `syncUrl` is remote server url / turso url, and two optional value is `syncInterval` default is 5 second and `read_your_writes` default is true. 14 | 15 | The constructor throws a `LibsqlError` if there's an issue creating the HTTP client or if the provided URL scheme is not supported. It distinguishes between remote and local connections and sets up the appropriate provider accordingly. 16 | 17 | ```php 18 | public function __construct(array $config) 19 | ``` 20 | 21 | **Parameters:** 22 | 23 | - `$config`: The configuration array for the LibSQL service. 24 | 25 | **Example Local Connection** 26 | 27 | ```php 28 | "file:database.db", 31 | "flags" => LIBSQLPHP_OPEN_READWRITE | LIBSQLPHP_OPEN_CREATE, 32 | "encryptionKey" => "" 33 | ]; 34 | 35 | $db = new LibSQL($config); 36 | ``` 37 | 38 | **Example Remote Connection** 39 | 40 | ```php 41 | 'libsql://127.0.0.1:8001', // libsql://database-origanization.turso.io 44 | 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), 45 | 'tls' => false 46 | ]; 47 | 48 | $db = new LibSQL($config); 49 | ``` 50 | 51 | **Example Remote Replica Connection** 52 | 53 | ```php 54 | $config = [ 55 | "url" => "file:database.db", 56 | "authToken" => getenv('TURSO_DATABASE_TOKEN'), 57 | "syncUrl" => getenv('TURSO_DATABASE_URL'), 58 | "syncInterval" => 5, 59 | "read_your_writes" => true 60 | ]; 61 | 62 | $db = new LibSQL($config); 63 | ``` 64 | 65 | ## Connection 66 | 67 | This method `connect()` establishes a connection to the database based on the mode set during the initialization of the LibSQL instance. It throws a `LibsqlError` if the connection mode is not recognized. 68 | 69 | For a remote connection, it delegates the connection task to the HTTP provider's `connect()` method. For a local connection, it uses the local provider's `connect()` method. 70 | 71 | If the connection mode is neither remote nor local, it throws an error indicating that the connection mode is not found. 72 | 73 | **Return** 74 | - `bool` - If `true` connection is establish, `false` connection failed. 75 | 76 | ```php 77 | public function connect(): bool 78 | ``` 79 | 80 | ## Version 81 | 82 | This method `version()` retrieves the version information of the database based on the connection mode set during the initialization of the LibSQL instance. If the connection mode is not recognized, it throws a `LibsqlError`. 83 | 84 | For a remote connection, it delegates the task to the HTTP provider's `version()` method. For a local connection, it uses the local provider's `version()` method. 85 | 86 | If the connection mode is neither remote nor local, it throws an error indicating that the connection mode is not found. 87 | 88 | ```php 89 | public function version(): string 90 | ``` 91 | 92 | **Return** 93 | - `string` The version information of the database. 94 | 95 | ## Executes a Query 96 | 97 | This method `execute()` allows you to execute a query either locally or remotely based on the connection mode set during the initialization of the LibSQL instance. It supports both local and remote execution. 98 | 99 | For a remote execution, you can provide an instance of `HttpStatement` representing the query along with an optional baton value. The method returns an instance of `HttpResponse` containing the result of the execution. 100 | 101 | For a local execution, you provide the query as a string and optionally an array of parameters. It returns true if the execution is successful. 102 | 103 | If the connection mode is neither remote nor local, it throws an error indicating that the connection mode is not found. 104 | 105 | ```php 106 | public function execute(string|HttpStatement $query, string $baton = '', array $params = []): LibSQLPHPClientResult|HttpResponse 107 | ``` 108 | 109 | > **NOTE: Use _Named Paramaters_ is recommended** 110 | 111 | **Remote Parameters** 112 | 113 | - `$query` 114 | - `HttpStatement` - **[Remote Only]** Parameter used for Remote connection only - [Ref:HttpStatement](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpStatement.php) / Doc: [Doc:HttpStatement](https://github.com/darkterminal/libsql-client-php/blob/main/docs/Types/HttpStatement.md) 115 | - `$baton` 116 | - `string` - **[Remote Only]** The baton value for the query. 117 | 118 | **Remote Return** 119 | 120 | - `HttpResponse` - **[Remote Only]** instance of `HttpResponse` for remote mode - [Ref:HttpResponse](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpResponse.php) / Doc: [Doc:HttpResponse](https://github.com/darkterminal/libsql-client-php/blob/main/docs/Types/HttpResponse.md) 121 | 122 | **Remote Usage Example** 123 | 124 | ```php 125 | $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 126 | $results = $db->execute(query: $query); 127 | echo $results->fetch(type: LibSQLResult::FETCH_OBJ) . PHP_EOL; 128 | ``` 129 | 130 | **Local Paramaters** 131 | 132 | - `$query` 133 | - `string` - **[Local only]** Parameter used for Local connection only 134 | - `$params` 135 | - `array` - **[Local Only]** Parameters for the query. 136 | 137 | **Local Return** 138 | 139 | - `LibSQLPHPClientResult` - **[Local Only]** Parameters for the query. - [Ref:LibSQLPHPClientResult](https://github.com/darkterminal/libsql-php-ext/blob/main/src/Responses/LibSQLPHPClientResult.php) 140 | 141 | **Local Usage Example** 142 | 143 | ```php 144 | $result = $db->execute(query: "INSERT INTO users (name) VALUES (?)", params: ['Belina Bogge']); 145 | var_dump($result); 146 | ``` 147 | 148 | ## (Remote) Executes a batch of queries 149 | 150 | > 💡 **NOTE: THIS INTERACTIVE TRANSACTIONS HAVE HIGHER LATENCY**

151 | > _In this operation, you will send as many HTTP Requests as the total array you defined. If the batch array has 2 rows of values as in the example, then this operation will send 2 HTTP Requests._ 152 | 153 | This method `batch()` executes a batch of queries **exclusively for remote connections**. It supports different transaction behavior modes such as deferred (default), write, and read. 154 | 155 | The method expects an array of HTTP statements representing the queries to execute. Each HTTP statement should be created using the `HttpStatement::create()` method, specifying the SQL query and any parameters. 156 | 157 | An optional `$mode` parameter allows you to specify the transaction behavior mode, with the default being "deferred". You can use lowercase mode names or constants from the `TransactionMode` class. 158 | 159 | It's important to note that this method is only available for remote (HTTP) connections. If called for a local connection, it will throw a `LibsqlError`. 160 | 161 | The method returns an HTTP response containing the result of the batch execution. You can refer to the [Ref:HttpResponse](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpResponse.php) class for more information on the structure of the response. 162 | 163 | ```php 164 | public function batch(array $queries, string $mode = "deferred"): HttpResponse 165 | ``` 166 | 167 | > 💡 **NOTE: Remote Only** 168 | 169 | **Parameters** 170 | - `$querys` - The array of queries to execute. 171 | - `$mode` - (Optional) The transaction behavior mode. Default is "deferred" 172 | 173 | Mode Options Available: 174 | - deferred (default) 175 | - write 176 | - read 177 | 178 | Everyting is in lower-case or you can use `TransactionMode` Class Constants 179 | 180 | **Return** 181 | - `HttpResponse` - The HTTP response containing the result of the batch execution. - [Ref:HttpResponse](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpResponse.php) 182 | 183 | **Example - [Ref:Example](https://docs.turso.tech/sdk/http/reference#interactive-query)** 184 | 185 | ```php 186 | $stmts = [ 187 | HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Ramons", 32]), 188 | HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Georgia", 43]) 189 | ]; 190 | $results = $db->batch(queries: $stmts); 191 | print_r($results); 192 | ``` 193 | 194 | ## (Local / Remote Replica) Executes a batch of queries 195 | 196 | This method `execute_batch()` executes a batch of queries exclusively for local (file) connections. It allows you to execute multiple SQL statements in a single batch. 197 | 198 | The method expects a string parameter `$query`, which represents the batch query to execute. This query can contain multiple SQL statements separated by semicolons. 199 | 200 | It's important to note that this method is only available for local (file) connections. If called for a remote connection, it will throw a `LibsqlError`. 201 | 202 | The method does not return any value (void), as it simply executes the batch query. 203 | 204 | ```php 205 | public function execute_batch(string $query): void 206 | ``` 207 | 208 | 209 | **Example** 210 | 211 | ```php 212 | execute_batch(" 214 | BEGIN; 215 | CREATE TABLE foo(x INTEGER); 216 | CREATE TABLE bar(y TEXT); 217 | COMMIT; 218 | "); 219 | ``` 220 | 221 | ## Executes multiple SQL queries in a single HTTP request 222 | 223 | This method `executeMultiple()` allows you to execute multiple SQL queries in a single HTTP request, specifically designed for remote connections only. 224 | 225 | The method expects a string parameter `$query`, which represents the SQL queries to execute. These queries should be separated by semicolons. 226 | 227 | It's important to note that this method is only available for remote (HTTP) connections. If called for a local connection, it will throw a `LibsqlError`. 228 | 229 | The method returns a string containing the response from executing the queries. 230 | 231 | ```php 232 | public function executeMultiple(string $query): string 233 | ``` 234 | 235 | **Example** 236 | 237 | ```php 238 | executeMultiple($query); 244 | print_r($result); 245 | ``` 246 | Refs: 247 | - [Ref:http.ts Implementation](https://github.com/tursodatabase/libsql-client-ts/blob/main/packages/libsql-client/src/http.ts#L124-L140) 248 | - [Ref:HRANA_3_SPEC](https://github.com/tursodatabase/libsql/blob/main/docs/HRANA_3_SPEC.md#L844) 249 | 250 | ## Initiates a transaction for executing SQL queries either remotely or locally 251 | 252 | This method `transaction()` initiates a transaction for executing SQL queries either remotely or locally, depending on the connection mode set during initialization. It supports different transaction modes such as deferred, write, and read. 253 | 254 | For **remote usage**, you can start a new transaction using `$db->transaction()`, then add SQL statements using `addTransaction()`, and finally end the transaction using `endTransaction()`. 255 | 256 | For **local usage**, you can specify the transaction mode (defaulting to 'deferred') and then execute SQL statements using `exec()`. You can then commit the changes using `commit()` or rollback using `rollback()` based on the success of the operations. 257 | 258 | Here's an example of both remote and local usage: 259 | 260 | ```php 261 | // Remote Usage 262 | $transaction = $db->transaction(); 263 | $transaction->addTransaction(HttpStatement::create("UPDATE users SET name = 'Turso DB' WHERE id = 1")); 264 | $transaction->addTransaction(HttpStatement::create("UPDATE users SET name = 'darkterminal' WHERE id = 2")); 265 | $result = $transaction->endTransaction(); 266 | print_r($result); 267 | 268 | // Local / Remote Replica Usage 269 | $tx = $db->transaction(TransactionBehavior::Deferred); 270 | $tx->exec("INSERT INTO users (name) VALUES (?)", ["Emanuel"]); 271 | $tx->exec("INSERT INTO users (name) VALUES (?)", ["Darren"]); 272 | 273 | if ($operations_successful) { 274 | $tx->commit(); 275 | echo "Commit the changes" . PHP_EOL; 276 | } else { 277 | $tx->rollback(); 278 | echo "Rollback the changes" . PHP_EOL; 279 | } 280 | ``` 281 | 282 | The method returns an instance of `HttpTransaction` for remote connections and `Transaction` for local connections. 283 | 284 | ## Synchronizes the database 285 | 286 | This method `sync()` synchronizes the database, but it's only supported for **RemoteReplica** and **LocalReplica**. If called in Remote (HTTP) or Local (FILE) mode, it will throw a `LibsqlError`. 287 | 288 | ## Close the database connection 289 | 290 | This method `close()` is responsible for closing the database connection, whether it's a remote (HTTP) connection or a local (FILE) connection. If the connection mode is not recognized, it throws a `LibsqlError`. 291 | 292 | -------------------------------------------------------------------------------- /docs/Providers/HttpClient.md: -------------------------------------------------------------------------------- 1 | # HttpClient 2 | 3 | The `HttpClient` trait provides functionality to interact with HTTP resources, including executing HTTP requests and handling responses. 4 | 5 | ## Namespace: 6 | - `Darkterminal\LibSQL\Providers` 7 | 8 | ## Uses: 9 | - `Darkterminal\LibSQL\Types\HttpResponse` 10 | - `Darkterminal\LibSQL\Types\HttpStatement` 11 | - `Darkterminal\LibSQL\Types\TransactionMode` 12 | - `Darkterminal\LibSQL\Utils\Exceptions\LibsqlError` 13 | - `GuzzleHttp\Client` 14 | - `GuzzleHttp\Exception\RequestException` 15 | - `GuzzleHttp\Psr7\Request` 16 | - `Psr\Http\Message\ResponseInterface` 17 | 18 | ## Properties: 19 | - `$http`: Client 20 | - `$timeout`: int|float 21 | - `$url`: string 22 | - `$authToken`: string|null 23 | - `$headers`: array 24 | - `$baton`: string 25 | - `$collectors`: array 26 | 27 | ## Methods: 28 | 29 | ### protected function setup(string $url, string|null $authToken = null, int|float $timeout = 2.0) 30 | **Description:** Initializes a new HttpClient instance. 31 | 32 | **Link:** N/A 33 | 34 | **Parameters:** 35 | - `$url`: The base URL for HTTP requests. 36 | - `$authToken` (Optional): The authentication token for accessing the URL. 37 | - `$timeout`: The timeout duration for HTTP requests. 38 | 39 | ### public function connect(): bool|LibsqlError 40 | **Description:** Connects to the HTTP server. 41 | 42 | **Link:** N/A 43 | 44 | ### public function execute(HttpStatement $query, string $baton = ''): HttpResponse 45 | **Description:** Executes an HTTP statement. 46 | 47 | **Link:** [Turso - Simple Query](https://docs.turso.tech/sdk/http/reference#simple-query) 48 | 49 | **Parameters:** 50 | - `$query`: The HTTP statement to execute. 51 | - `$baton` (Optional): The baton string. 52 | 53 | ### public function batch(array $queries, string $mode = 'deferred'): HttpResponse 54 | **Description:** Executes a batch of HTTP statements. 55 | 56 | **Link:** [Turso - Interactive Query](https://docs.turso.tech/sdk/http/reference#interactive-query) 57 | 58 | **Parameters:** 59 | - `$queries`: The array of HTTP statements to execute. 60 | - `$mode` (Optional): The transaction mode (read, write, or deferred). 61 | 62 | ### public function executeMultiple(string $sql): void 63 | **Description:** Executes multiple SQL statements in sequence. 64 | 65 | **Link:** [Hrana Over HTTP - Sequence](https://github.com/tursodatabase/libsql/blob/main/docs/HRANA_3_SPEC.md#execute-a-sequence-of-sql-statements-1) 66 | 67 | **Parameters:** 68 | - `$sql`: The SQL statements to execute. 69 | 70 | ### public function startTransaction(string $mode = 'write'): self 71 | **Description:** Starts a transaction with the specified mode. 72 | 73 | **Link:** N/A 74 | 75 | **Parameters:** 76 | - `$mode` (Optional): The transaction mode (read, write, or deferred). 77 | 78 | ### public function addTransaction(HttpStatement $query): self 79 | **Description:** Adds a transaction to the transaction batch. 80 | 81 | **Link:** N/A 82 | 83 | **Parameters:** 84 | - `$query`: The HTTP statement to add to the transaction. 85 | 86 | ### public function endTransaction(): HttpResponse 87 | **Description:** Ends the current transaction batch and commits the transactions. 88 | 89 | **Link:** N/A 90 | 91 | ### public function rollback(): void 92 | **Description:** Rolls back the current transaction. 93 | 94 | **Link:** N/A 95 | 96 | ### public function commit(): void 97 | **Description:** Commits the current transaction. 98 | 99 | **Link:** N/A 100 | 101 | ### public function close(): void 102 | **Description:** Closes the HTTP client connection. 103 | 104 | **Link:** N/A 105 | 106 | ### public function version(): string 107 | **Description:** Retrieves the version from the HTTP server. 108 | 109 | **Link:** N/A 110 | 111 | ### protected function runQuery(array $payload, bool $trace = false): HttpResponse|ResponseInterface 112 | **Description:** Runs an HTTP query with the provided payload. 113 | 114 | **Link:** N/A 115 | 116 | **Parameters:** 117 | - `$payload`: The payload for the HTTP query. 118 | - `$trace` (Optional): Whether to return the raw response without mapping results. 119 | 120 | ### private function _makeRequest(array $data, bool $close = true, string $baton = ''): array 121 | **Description:** Creates a payload for making a request. 122 | 123 | **Link:** N/A 124 | 125 | **Parameters:** 126 | - `$data`: The data to include in the payload. 127 | - `$close` (Optional): Whether to include a close request. 128 | - `$baton` (Optional): The baton string. 129 | 130 | ### private function _close(): array 131 | **Description:** Creates a request array for closing the connection. 132 | 133 | **Link:** N/A 134 | 135 | ### private function _createRequest(string $type = \LIBSQL_EXECUTE, string $sql, ?array $args = [], ?bool $named_args = false): array 136 | **Description:** Creates a request array for execution with the provided SQL statement and arguments. 137 | 138 | **Link:** N/A 139 | 140 | **Parameters:** 141 | - `$type`: The type statement to execute. 142 | - `$sql`: The SQL statement to execute. 143 | - `$args` (Optional): The arguments for the SQL statement. 144 | - `$named_args` (Optional): Whether the arguments are named or positional. 145 | 146 | ### private function _argumentsGenerator($args): array 147 | **Description:** Generates arguments array for the HTTP request payload. 148 | 149 | **Link:** N/A 150 | 151 | **Parameters:** 152 | - `$args`: The arguments to be processed. 153 | 154 | ### private function _namedArgumentsGenerator(array $args): array 155 | **Description:** Generates named arguments array for the HTTP request payload. 156 | 157 | **Link:** N/A 158 | 159 | **Parameters:** 160 | - `$args`: The named arguments to be processed. 161 | 162 | ### private function _typeParser(mixed $value): string 163 | **Description:** Parses the type of the value. 164 | 165 | **Link:** N/A 166 | 167 | **Parameters:** 168 | - `$value`: The value to determine the type for. 169 | -------------------------------------------------------------------------------- /docs/Quickstart.md: -------------------------------------------------------------------------------- 1 | # SDK Quickstart Guide 2 | 3 | ## Installation 4 | 5 | ```bash 6 | composer require darkterminal/libsql-client-php 7 | ``` 8 | 9 | ## Local Usage 10 | 11 | ```php 12 | "file:database.db", // use in-memory database with :memory: 20 | "flags" => LIBSQLPHP_OPEN_READWRITE | LIBSQLPHP_OPEN_CREATE, 21 | "encryptionKey" => "" // optional 22 | ]; 23 | 24 | $db = new LibSQL($config); 25 | 26 | if ($db->connect()) { 27 | echo "Connection Establised!" . PHP_EOL; 28 | echo "--- ". $db->version() ." ---" . PHP_EOL; 29 | } 30 | $db->close(); 31 | ``` 32 | 33 | ## Remote Usage 34 | 35 | ```php 36 | getenv('TURSO_DATABASE_URL'), // libsql://database-org.turso.io 46 | 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), // your turso db token here 47 | ]; 48 | 49 | $db = new LibSQL($config); 50 | 51 | if ($db->connect()) { 52 | echo "Connection Establised!" . PHP_EOL; 53 | echo "--- ". $db->version() ." ---" . PHP_EOL; 54 | } 55 | 56 | 57 | // Simple Query 58 | $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 59 | $results = $db->execute(query: $query); 60 | echo $results->fetch(type: LibSQLResult::FETCH_OBJ) . PHP_EOL; 61 | ``` 62 | 63 | ## Remote Replica Connection 64 | 65 | ```php 66 | $config = [ 67 | "url" => "file:database.db", 68 | "authToken" => getenv('TURSO_DATABASE_TOKEN'), 69 | "syncUrl" => getenv('TURSO_DATABASE_URL'), 70 | "syncInterval" => 5, // optional, default is 5 second 71 | "read_your_writes" => true // optional, default is true 72 | ]; 73 | 74 | $db = new LibSQL($config); 75 | ``` 76 | 77 | ## Read more 78 | - [LibSQL PHP SDK](LibSQL.md) 79 | - [Local Example](https://github.com/darkterminal/libsql-client-php/tree/main/examples/local-file) 80 | - [Remote Example](https://github.com/darkterminal/libsql-client-php/tree/main/examples/remote-http) 81 | - [Remote Replica Example](https://github.com/darkterminal/libsql-client-php/tree/main/examples/remote-http) 82 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction LibSQL Client PHP 2 | 3 | > _Keywords: Doc, Ref the link tags that will redirect you into (Doc) documentation and (Ref) the code._ 4 | 5 | This is the first **LibSQL Client for PHP** that can interact with **LibSQL** server natively via the **LibSQL PHP Extension** which is written with Rust C Binding and communicates with PHP via FFI. 6 | 7 | The **LibSQL Client PHP** is a versatile library designed to facilitate interactions with both local and remote **LibSQL** databases from **PHP** applications. It abstracts the complexities of establishing connections, executing queries, managing transactions, and synchronizing databases, providing a unified API that supports various URL schemes including "`file:`", "`libsql:`", "`https:`", and "`http:`". The library caters to different operational modes, namely Remote and Local, allowing for seamless database operations across different environments. 8 | 9 | For remote connections, it leverages HTTP clients to communicate with LibSQL servers, supporting functionalities like executing batch queries, managing transactions with different behaviors (e.g., deferred, write, read), and executing multiple SQL queries in a single HTTP request. For local connections, it interfaces with local database files, offering capabilities to execute queries, perform batch operations, and manage transactions directly on the local file system. 10 | 11 | The library ensures robust error handling, throwing LibsqlError exceptions for unsupported URL schemes, TLS configuration issues, and other operational errors. It also provides a sync method for database synchronization in specific configurations, although this feature is not supported in basic Remote (HTTP) or Local (FILE) modes. 12 | 13 | Here's a quick overview of its key features: 14 | 15 | - **Connection Management**: Establishes connections to both local and remote databases with flexible configuration options. 16 | - **Query Execution**: Supports executing SQL queries, with special considerations for named parameters in remote connections. 17 | - **Batch Operations**: Enables executing a batch of queries in a single operation, particularly useful for remote connections. 18 | - **Transaction Management**: Facilitates starting, managing, and committing transactions with customizable behaviors. 19 | - **Synchronization**: Offers a synchronization mechanism for databases configured for replication, though with mode-specific limitations. 20 | - **Error Handling**: Robustly handles errors and operational exceptions, ensuring clear feedback on issues like unsupported configurations or operational failures. 21 | 22 | This library stands out for its adaptability and ease of use, making it a valuable tool for PHP developers working with LibSQL databases in varied environments. 23 | 24 | ## Table of Contents 25 | 26 | This table of contents is sorted hierarchically based on the _Main Class_ to its derivatives to make it easier for readers to understand the process that runs the **LibSQL Client PHP**. 27 | 28 | 1. [LibSQL](LibSQL.md) - The main class for interacting with the **LibSQL** service 29 | - 1.1 - [Instanciated](LibSQL.md#instanciated) - Initializes a new instance of **LibSQL** 30 | - 1.2 - [Connection](LibSQL.md#connection) - Establishes a connection to the database 31 | - 1.3 - [Version](LibSQL.md#version) - Retrieves the version information of the database 32 | - 1.4 - [Executes a Query](LibSQL.md#executes-a-query) - Allows you to execute a query either locally or remotely 33 | - 1.5 - [(Remote) Executes a Batch of Queries](LibSQL.md#remote-executes-a-batch-of-queries) - Executes a batch of queries **exclusively for remote connections** 34 | - 1.6 - [(Local) Executes a Batch of Queries](LibSQL.md#local-executes-a-batch-of-queries) - Executes a batch of queries exclusively for local (file) connections 35 | - 1.7 - [Executes Multiple](LibSQL.md#executes-multiple-sql-queries-in-a-single-http-request) - Allows you to execute multiple SQL queries in a single HTTP request 36 | - 1.8 - [Transaction](LibSQL.md#initiates-a-transaction-for-executing-sql-queries-either-remotely-or-locally) - Initiates a transaction for executing SQL queries either remotely or locally 37 | - 1.9 - [Sync](LibSQL.md#synchronizes-the-database) - Synchronizes the database 38 | - 1.0.1 - [Close](LibSQL.md#close-the-database-connection) - Close the database connection 39 | 2. Providers 40 | - 2.1 - [HttpClient](Providers/HttpClient.md) - The `HttpClient` class provides functionality to interact with HTTP resources 41 | - 2.2 - [LocalClient](Providers/LocalClient.md) - The `LocalClient` class provides functionality to interact with Local file database 42 | -------------------------------------------------------------------------------- /docs/Traits/Logging.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | 3 | This trait provides logging functionality for error messages. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Traits 7 | 8 | ## Methods: 9 | - public - log 10 | Description: Log a message to the error log file. 11 | Link: [None] 12 | Parameters: 13 | - $message (mixed): The message to log. 14 | - protected - checkAndCreateDirectoryAndFile 15 | Description: Check and create the directory and error log file if they don't exist. 16 | Link: [None] 17 | Parameters: 18 | - None 19 | 20 | --- 21 | 22 | ## Overview: 23 | The `Logging` trait provides two methods: 24 | - **log**: Logs a message to the error log file. It takes a message as input and appends it to the log file along with a timestamp. 25 | - **checkAndCreateDirectoryAndFile**: Checks if the directory and error log file exist. If they don't exist, it creates them. It returns the path to the error log file. 26 | 27 | This trait is used for logging error messages within the `LibSQL` library. 28 | -------------------------------------------------------------------------------- /docs/Traits/MapResults.md: -------------------------------------------------------------------------------- 1 | # MapResults 2 | 3 | This trait provides methods to map results from JSON data to arrays or JSON objects. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Traits 7 | 8 | ## Uses: 9 | - Darkterminal\LibSQL\Types\HttpResultSets 10 | 11 | ## Methods: 12 | - protected - fetchArray 13 | Description: Fetch the results as an array. 14 | Link: [None] 15 | Parameters: 16 | - $data (string|array|HttpResultSets): The JSON data containing the results. 17 | - protected - fetchObject 18 | Description: Fetch the results as a JSON object. 19 | Link: [None] 20 | Parameters: 21 | - $data (string|array|HttpResultSets): The JSON data containing the results. 22 | - private - _results 23 | Description: Parse the JSON data and extract the results. 24 | Link: [None] 25 | Parameters: 26 | - $data (string|array|HttpResultSets): The JSON data containing the results. 27 | 28 | --- 29 | 30 | ## Overview: 31 | The `MapResults` trait provides methods to fetch the results from JSON data either as an array or a JSON object. It includes the following methods: 32 | 33 | - **fetchArray**: Fetches the results as an array. 34 | - **fetchObject**: Fetches the results as a JSON object. 35 | - **_results**: Private method to parse the JSON data and extract the results. 36 | 37 | The trait is used for mapping results within the `LibSQL` library and depends on the `HttpResultSets` type. 38 | -------------------------------------------------------------------------------- /docs/Types/Authoriy.md: -------------------------------------------------------------------------------- 1 | # Authority 2 | 3 | Represents the authority part of a URI. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - UserInfo 10 | 11 | ## Properties: 12 | - **host** (string) - The host part of the authority. 13 | - **port** (int|null) - The port part of the authority, or null if not specified. 14 | - **userInfo** (UserInfo|null) - The user information part of the authority, or null if not specified. 15 | 16 | ## Methods: 17 | - **public** - `__construct` 18 | Description: Constructs a new Authority object. 19 | Parameters: 20 | - host (string) - The host part of the authority. 21 | - port (int|null) - The port part of the authority, or null if not specified. 22 | - userInfo (UserInfo|null) - The user information part of the authority, or null if not specified. 23 | 24 | - **public static** - `create` 25 | Description: Creates a new Authority object. 26 | Parameters: 27 | - host (string) - The host part of the authority. 28 | - port (int|null) - The port part of the authority, or null if not specified. 29 | - userInfo (UserInfo|null) - The user information part of the authority, or null if not specified. 30 | 31 | - **public** - `toArray` 32 | Description: Convert the Authority object to an array. 33 | Returns: An array representation of the Authority object. 34 | 35 | - **public** - `toObject` 36 | Description: Converts the Authority instance to a JSON string. 37 | Returns: The JSON representation of the Authority instance. 38 | 39 | --- 40 | 41 | ## Overview: 42 | The `Authority` class represents the authority part of a URI. It contains properties such as the host, port, and user information. This class provides methods to create an Authority object, convert it to an array, and serialize it to JSON. 43 | -------------------------------------------------------------------------------- /docs/Types/Config.md: -------------------------------------------------------------------------------- 1 | # Config 2 | 3 | Configuration object for createClient. 4 | 5 | The client supports `libsql:`, `http:`/`https`:, `ws:`/`wss:` and `file:` URL. For more information, please refer to the project README: 6 | [Supported Urls](https://github.com/libsql/libsql-client-php#supported-urls) 7 | 8 | ## Namespace: 9 | - Darkterminal\LibSQL\Types 10 | 11 | ## Uses: 12 | None 13 | 14 | ## Properties: 15 | - **url** (string) - The database URL. 16 | - **authToken** (string|null) - Authentication token for the database. 17 | - **encryptionKey** (string|null) - Encryption key for the database. 18 | - **syncUrl** (string|null) - URL of a remote server to synchronize database with. 19 | - **syncInterval** (int|null) - Sync interval in seconds. 20 | - **tls** (bool|null) - Enables or disables TLS for libsql: URLs. 21 | 22 | ## Methods: 23 | - **public** - `__construct` 24 | Description: Constructs a new Config object. 25 | Parameters: 26 | - url (string) - The database URL. 27 | - authToken (string|null) - Authentication token for the database. 28 | - encryptionKey (string|null) - Encryption key for the database. 29 | - syncUrl (string|null) - URL of a remote server to synchronize database with. 30 | - syncInterval (int|null) - Sync interval in seconds. 31 | - tls (bool|null) - Enables or disables TLS for libsql: URLs. 32 | 33 | - **public static** - `create` 34 | Description: Creates a new Config object. 35 | Parameters: 36 | - url (string) - The database URL. 37 | - authToken (string|null) - Authentication token for the database. 38 | - encryptionKey (string|null) - Encryption key for the database. 39 | - syncUrl (string|null) - URL of a remote server to synchronize database with. 40 | - syncInterval (int|null) - Sync interval in seconds. 41 | - tls (bool|null) - Enables or disables TLS for libsql: URLs. 42 | 43 | - **public** - `toArray` 44 | Description: Convert the Config object to an array. 45 | Returns: The Config properties as an array. 46 | 47 | - **public** - `toObject` 48 | Description: Converts the Config instance to a JSON string. 49 | Returns: The JSON representation of the Config instance. 50 | 51 | --- 52 | 53 | ## Overview: 54 | The `Config` class represents a configuration object for creating a client. It contains properties such as the database URL, authentication token, encryption key, synchronization URL, synchronization interval, and TLS flag. This class provides methods to create a Config object, convert it to an array, and serialize it to JSON. 55 | -------------------------------------------------------------------------------- /docs/Types/ExpandedConfig.md: -------------------------------------------------------------------------------- 1 | # ExpandedConfig 2 | 3 | Represents an expanded configuration object. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - Authority 10 | 11 | ## Properties: 12 | - **scheme** (string) - The scheme part of the configuration. 13 | - **tls** (bool) - Indicates whether TLS is enabled. 14 | - **authority** (Authority|null) - The authority part of the configuration, or null if not specified. 15 | - **path** (string) - The path part of the configuration. 16 | - **authToken** (string|null) - Authentication token for the configuration. 17 | - **syncUrl** (string|null) - URL of a remote server to synchronize configuration with. 18 | - **syncInterval** (int|null) - Sync interval in seconds. 19 | 20 | ## Methods: 21 | - **public** - `__construct` 22 | Description: Constructs a new ExpandedConfig object. 23 | Parameters: 24 | - scheme (string) - The scheme part of the configuration. 25 | - tls (bool) - Indicates whether TLS is enabled. 26 | - authority (Authority|null) - The authority part of the configuration, or null if not specified. 27 | - path (string) - The path part of the configuration. 28 | - authToken (string|null) - Authentication token for the configuration. 29 | - syncUrl (string|null) - URL of a remote server to synchronize configuration with. 30 | - syncInterval (int|null) - Sync interval in seconds. 31 | 32 | - **public static** - `create` 33 | Description: Creates a new ExpandedConfig object. 34 | Parameters: 35 | - scheme (string) - The scheme part of the configuration. 36 | - tls (bool) - Indicates whether TLS is enabled. 37 | - authority (Authority|null) - The authority part of the configuration, or null if not specified. 38 | - path (string) - The path part of the configuration. 39 | - authToken (string|null) - Authentication token for the configuration. 40 | - syncUrl (string|null) - URL of a remote server to synchronize configuration with. 41 | - syncInterval (int|null) - Sync interval in seconds. 42 | 43 | - **public** - `toArray` 44 | Description: Convert the ExpandedConfig object to an array. 45 | Returns: An array representation of the ExpandedConfig object. 46 | 47 | - **public** - `toObject` 48 | Description: Converts the ExpandedConfig instance to a JSON string. 49 | Returns: The JSON representation of the ExpandedConfig instance. 50 | 51 | --- 52 | 53 | ## Overview: 54 | The `ExpandedConfig` class represents an expanded configuration object. It contains properties such as the scheme, TLS flag, authority, path, authentication token, synchronization URL, and synchronization interval. This class provides methods to create an ExpandedConfig object, convert it to an array, and serialize it to JSON. 55 | -------------------------------------------------------------------------------- /docs/Types/ExpandedScheme.md: -------------------------------------------------------------------------------- 1 | # ExpandedScheme 2 | 3 | The ExpandedScheme class provides constants representing expanded schemes for various protocols. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | None 10 | 11 | ## Properties: 12 | None 13 | 14 | ## Methods: 15 | None 16 | 17 | ## Constants: 18 | - **wss** (string) - Represents the wss scheme. 19 | - **ws** (string) - Represents the ws scheme. 20 | - **https** (string) - Represents the https scheme. 21 | - **http** (string) - Represents the http scheme. 22 | - **file** (string) - Represents the file scheme. 23 | 24 | --- 25 | 26 | ## Overview: 27 | The `ExpandedScheme` class provides constants representing expanded schemes for various protocols such as wss, ws, https, http, and file. These constants can be used to reference these schemes throughout the application. 28 | -------------------------------------------------------------------------------- /docs/Types/HeirPart.md: -------------------------------------------------------------------------------- 1 | # HierPart 2 | 3 | Represents the hierarchical part of a URI. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - Authority 10 | 11 | ## Properties: 12 | - **authority** (Authority|null) - The authority part of the hierarchical part, or null if not specified. 13 | - **path** (string) - The path part of the hierarchical part. 14 | 15 | ## Methods: 16 | - **public** - `__construct` 17 | Description: Constructs a new HierPart object. 18 | Parameters: 19 | - authority (Authority|null) - The authority part of the hierarchical part, or null if not specified. 20 | - path (string) - The path part of the hierarchical part. 21 | 22 | - **public static** - `create` 23 | Description: Creates a new HierPart object. 24 | Parameters: 25 | - authority (Authority|null) - The authority part of the hierarchical part, or null if not specified. 26 | - path (string) - The path part of the hierarchical part. 27 | 28 | - **public** - `toArray` 29 | Description: Convert the HierPart object to an array. 30 | Returns: An array representation of the HierPart object. 31 | 32 | - **public** - `toObject` 33 | Description: Converts the HierPart instance to a JSON string. 34 | Returns: The JSON representation of the HierPart instance. 35 | 36 | --- 37 | 38 | ## Overview: 39 | The `HierPart` class represents the hierarchical part of a URI. It contains properties such as the authority and the path. This class provides methods to create a HierPart object, convert it to an array, and serialize it to JSON. 40 | -------------------------------------------------------------------------------- /docs/Types/HttpResponse.md: -------------------------------------------------------------------------------- 1 | # HttpResponse 2 | 3 | The `HttpResponse` class represents an HTTP response from LibSQL Server. It contains properties such as the baton identifier, base URL, and HTTP result sets. This class provides methods to create an HttpResponse object, convert it to an array or JSON string, fetch results, and handle errors. 4 | 5 | ## Instanciated 6 | 7 | The constructor initializes a new `HttpResponse` instance with the provided parameters - `$baton`, `$base_url`, and `$results`. It assigns these parameters to the corresponding properties of the class. _(Leave this alone!)_ 8 | 9 | ```php 10 | public function __construct( 11 | public string|null $baton, 12 | public string|null $base_url, 13 | public array|HttpResultSets $results 14 | ) 15 | ``` 16 | ## Create "static" Method 17 | 18 | Creates a new instance of the `HttpResponse` class. 19 | 20 | ```php 21 | public static function create( 22 | string|null $baton, 23 | string|null $base_url, 24 | array|HttpResultSets $results 25 | ): self 26 | ``` 27 | 28 | **Example Usage** 29 | 30 | ```php 31 | $data = map_results($response->getBody()); 32 | return HttpResponse::create($data['baton'], $data['base_url'], $data['results']); 33 | ``` 34 | 35 | ## toArray 36 | 37 | Converts the result set to an associative array representation. It includes the baton, base URL, and the results converted to an array using the `objectToArray()` function. 38 | 39 | ```php 40 | public function toArray(): array 41 | ``` 42 | 43 | ## toObject 44 | 45 | Converts the result set to a JSON-encoded string representation. It internally uses the `toArray()` method to convert the result set to an associative array before encoding it as JSON. 46 | 47 | ```php 48 | public function toObject(): string 49 | ``` 50 | 51 | ## first 52 | 53 | Retrieve the first result set from the query execution. 54 | 55 | Returns a new instance of the current class containing the first result set obtained from the executed query. It converts the internal result object to an array and extracts the first element to create a new instance. 56 | 57 | ```php 58 | public function first(): self 59 | ``` 60 | 61 | **Example Usage** 62 | 63 | ```php 64 | $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 65 | $results = $db->execute(query: $query); 66 | $results->first(); 67 | ``` 68 | 69 | ## fetch 70 | 71 | Fetch the result set from the query execution. 72 | 73 | Retrieves the result set from the executed query and returns it in the specified format. It converts the internal result object to an array and switches based on the provided type parameter to determine the format of the returned data. 74 | 75 | ```php 76 | public function fetch(int $type = LibSQLResult::FETCH_ASSOC): array|string 77 | ``` 78 | 79 | **Example Usage** 80 | 81 | ```php 82 | $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 83 | $results = $db->execute(query: $query); 84 | echo $results->fetch(type: LibSQLResult::FETCH_OBJ) . PHP_EOL; 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/Types/HttpResultSets.md: -------------------------------------------------------------------------------- 1 | # HttpResultSets 2 | 3 | Represents a set of HTTP result data. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - None 10 | 11 | ## Properties: 12 | - **cols** (array) - The columns of the result set. 13 | - **rows** (array) - The rows of the result set. 14 | - **affected_row_count** (int) - The number of affected rows. 15 | - **last_insert_rowid** (int|null) - The last inserted row ID. 16 | - **replication_index** (int|string) - The replication index. 17 | 18 | ## Methods: 19 | - **public** - `__construct` 20 | Description: Constructs a new HttpResultSets instance. 21 | Parameters: 22 | - cols (array) - The columns of the result set. 23 | - rows (array) - The rows of the result set. 24 | - affected_row_count (int) - The number of affected rows. 25 | - last_insert_rowid (int|null) - The last inserted row ID. 26 | - replication_index (int|string) - The replication index. 27 | 28 | - **public static** - `create` 29 | Description: Creates a new HttpResultSets instance. 30 | Parameters: 31 | - cols (array) - The columns of the result set. 32 | - rows (array) - The rows of the result set. 33 | - affected_row_count (int) - The number of affected rows. 34 | - last_insert_rowid (int|null) - The last inserted row ID. 35 | - replication_index (int|string) - The replication index. 36 | 37 | - **public** - `toArray` 38 | Description: Convert the HttpResultSets instance to an array. 39 | Returns: The array representation of the HttpResultSets instance. 40 | 41 | - **public** - `toObject` 42 | Description: Converts the HttpResultSets instance to a JSON string. 43 | Returns: The JSON representation of the HttpResultSets instance. 44 | 45 | --- 46 | 47 | ## Overview: 48 | The `HttpResultSets` class represents a set of HTTP result data. It contains properties such as the columns, rows, affected row count, last inserted row ID, and replication index. This class provides methods to create an HttpResultSets object, convert it to an array or JSON string. 49 | -------------------------------------------------------------------------------- /docs/Types/HttpStatement.md: -------------------------------------------------------------------------------- 1 | # HttpStatement 2 | 3 | The `HttpStatement` class represents an HTTP statement with SQL and optional arguments. It contains properties such as the SQL statement, optional arguments, and whether the arguments are named or positional. This class provides methods to create an HttpStatement object, convert it to an array or JSON string. 4 | 5 | ## Instanciated 6 | 7 | Constructs a new `HttpStatement` instance. _(Leave this alone!)_ 8 | 9 | ```php 10 | public function __construct( 11 | public string $sql, 12 | public ?array $args = [], 13 | public ?bool $named_args = false 14 | ) 15 | ``` 16 | ## Create "static" Method 17 | 18 | Creates a new `HttpStatement` instance. 19 | 20 | ```php 21 | public static function create( 22 | string $sql, 23 | ?array $args = [], 24 | ?bool $named_args = false 25 | ): self 26 | ``` 27 | 28 | **Example Usage** 29 | 30 | ```php 31 | $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 32 | 33 | // or 34 | 35 | $stmts = [ 36 | HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Ramons", 32]), 37 | HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Georgia", 43]) 38 | ]; 39 | ``` 40 | 41 | ## toArray 42 | 43 | Converts the `HttpStatement` instance to an array. 44 | 45 | ```php 46 | public function toArray(): array 47 | ``` 48 | 49 | ## toObject 50 | 51 | Converts the `HttpStatement` instance to a JSON string. 52 | 53 | ```php 54 | public function toObject(): string 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/Types/KeyValue.md: -------------------------------------------------------------------------------- 1 | # KeyValue 2 | 3 | Represents a key-value pair in a query string. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - None 10 | 11 | ## Properties: 12 | - **key** (string) - The key of the key-value pair. 13 | - **value** (string) - The value of the key-value pair. 14 | 15 | ## Methods: 16 | - **public** - `__construct` 17 | Description: Constructs a new KeyValue instance. 18 | Parameters: 19 | - key (string) - The key of the key-value pair. 20 | - value (string) - The value of the key-value pair. 21 | 22 | - **public static** - `create` 23 | Description: Creates a new KeyValue instance. 24 | Parameters: 25 | - key (string) - The key of the key-value pair. 26 | - value (string) - The value of the key-value pair. 27 | 28 | - **public** - `toArray` 29 | Description: Convert the KeyValue object to an array. 30 | Returns: An array representation of the KeyValue object. 31 | 32 | - **public** - `toObject` 33 | Description: Converts the KeyValue instance to a JSON string. 34 | Returns: The JSON representation of the KeyValue instance. 35 | 36 | --- 37 | 38 | ## Overview: 39 | The `KeyValue` class represents a key-value pair in a query string. It contains properties such as the key and value. This class provides methods to create a KeyValue object, convert it to an array or JSON string. 40 | -------------------------------------------------------------------------------- /docs/Types/LibSQLResult.md: -------------------------------------------------------------------------------- 1 | # LibSQLResult 2 | 3 | Represents different formats for fetching SQL results. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - None 10 | 11 | ## Properties: 12 | None 13 | 14 | ## Methods: 15 | None 16 | 17 | ## Constants: 18 | - **FETCH_ASSOC** (int) - Represents the associative array format for fetching SQL results. 19 | - **FETCH_OBJ** (int) - Represents the object format for fetching SQL results. 20 | - **FETCH_RAW** (int) - Represents the raw format for fetching SQL results. 21 | 22 | --- 23 | 24 | ## Overview: 25 | The `LibSQLResult` class represents different formats for fetching SQL results. It provides constants such as `FETCH_ASSOC`, `FETCH_OBJ`, and `FETCH_RAW`, which can be used to specify the format in which SQL results should be fetched. 26 | -------------------------------------------------------------------------------- /docs/Types/Query.md: -------------------------------------------------------------------------------- 1 | # Query 2 | 3 | Represents the query part of a URI. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - None 10 | 11 | ## Properties: 12 | - **pairs** (array) - An array of key-value pairs representing the query parameters. 13 | 14 | ## Methods: 15 | - **public** - `__construct` 16 | Description: Constructs a new Query instance. 17 | Parameters: 18 | - pairs (array) - An array of key-value pairs representing the query parameters. 19 | 20 | - **public static** - `create` 21 | Description: Creates a new Query instance. 22 | Parameters: 23 | - pairs (array) - An array of key-value pairs representing the query parameters. 24 | 25 | - **public** - `toArray` 26 | Description: Convert the Query object to an array. 27 | Returns: An array representation of the Query object. 28 | 29 | - **public** - `toObject` 30 | Description: Converts the Query instance to a JSON string. 31 | Returns: The JSON representation of the Query instance. 32 | 33 | --- 34 | 35 | ## Overview: 36 | The `Query` class represents the query part of a URI. It contains a property `pairs`, which is an array of key-value pairs representing the query parameters. This class provides methods to create a Query object, convert it to an array or JSON string. 37 | -------------------------------------------------------------------------------- /docs/Types/TransactionMode.md: -------------------------------------------------------------------------------- 1 | # TransactionMode 2 | 3 | The TransactionMode class provides constants representing transaction modes for database operations. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - ReflectionClass from PHP Standard Library 10 | - LibsqlError exception 11 | 12 | ## Properties: 13 | None 14 | 15 | ## Methods: 16 | - **public static** - `checker` 17 | Description: Checks if the given transaction mode is valid. 18 | Parameters: 19 | - mode (string) - The transaction mode to check. 20 | Returns: The valid transaction mode if it exists. 21 | Throws: LibsqlError if the transaction mode is not supported. 22 | 23 | ## Constants: 24 | - **write** (string) - Represents the write transaction mode. 25 | - **read** (string) - Represents the read transaction mode. 26 | - **deferred** (string) - Represents the deferred transaction mode. 27 | 28 | --- 29 | 30 | ## Overview: 31 | The `TransactionMode` class provides constants representing transaction modes for database operations, including write, read, and deferred. It also provides a `checker` method to validate transaction modes. If an invalid transaction mode is provided, it throws a `LibsqlError` exception. 32 | -------------------------------------------------------------------------------- /docs/Types/Uri.md: -------------------------------------------------------------------------------- 1 | # Uri 2 | 3 | Represents a URI object. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - None 10 | 11 | ## Properties: 12 | - **scheme** (string) - The scheme part of the URI. 13 | - **authority** (Authority|null) - The authority part of the URI. 14 | - **path** (string) - The path part of the URI. 15 | - **query** (Query|null) - The query part of the URI. 16 | - **fragment** (string|null) - The fragment part of the URI. 17 | 18 | ## Methods: 19 | - **public** - `__construct` 20 | Description: Constructs a new Uri instance. 21 | Parameters: 22 | - scheme (string) - The scheme part of the URI. 23 | - authority (Authority|null) - The authority part of the URI. 24 | - path (string) - The path part of the URI. 25 | - query (Query|null) - The query part of the URI. 26 | - fragment (string|null) - The fragment part of the URI. 27 | 28 | - **public static** - `create` 29 | Description: Creates a new Uri instance. 30 | Parameters: 31 | - scheme (string) - The scheme part of the URI. 32 | - authority (Authority|null) - The authority part of the URI. 33 | - path (string) - The path part of the URI. 34 | - query (Query|null) - The query part of the URI. 35 | - fragment (string|null) - The fragment part of the URI. 36 | 37 | - **public** - `toArray` 38 | Description: Convert the Uri object to an array. 39 | Returns: An array representation of the Uri object. 40 | 41 | - **public** - `toObject` 42 | Description: Converts the Uri instance to a JSON string. 43 | Returns: The JSON representation of the Uri instance. 44 | 45 | --- 46 | 47 | ## Overview: 48 | The `Uri` class represents a URI object. It contains properties such as the scheme, authority, path, query, and fragment parts of the URI. This class provides methods to create a Uri object, convert it to an array or JSON string. 49 | -------------------------------------------------------------------------------- /docs/Types/UserInfo.md: -------------------------------------------------------------------------------- 1 | # UserInfo 2 | 3 | Represents the userInfo part of a URI authority. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Types 7 | 8 | ## Uses: 9 | - None 10 | 11 | ## Properties: 12 | - **username** (string|null) - The username part of the userInfo. 13 | - **password** (string|null) - The password part of the userInfo. 14 | 15 | ## Methods: 16 | - **public** - `__construct` 17 | Description: Constructs a new UserInfo instance. 18 | Parameters: 19 | - username (string|null) - The username part of the userInfo. 20 | - password (string|null) - The password part of the userInfo. 21 | 22 | - **public static** - `create` 23 | Description: Creates a new UserInfo instance. 24 | Parameters: 25 | - username (string|null) - The username part of the userInfo. 26 | - password (string|null) - The password part of the userInfo. 27 | 28 | - **public** - `toArray` 29 | Description: Convert the UserInfo object to an array. 30 | Returns: An array representation of the UserInfo object. 31 | 32 | - **public** - `toObject` 33 | Description: Converts the UserInfo instance to a JSON string. 34 | Returns: The JSON representation of the UserInfo instance. 35 | 36 | --- 37 | 38 | ## Overview: 39 | The `UserInfo` class represents the userInfo part of a URI authority. It contains properties such as the username and password. This class provides methods to create a UserInfo object, convert it to an array or JSON string. 40 | -------------------------------------------------------------------------------- /docs/Utils/Exceptions/LibsqlError.md: -------------------------------------------------------------------------------- 1 | # LibsqlError 2 | 3 | Error thrown by the client. 4 | 5 | ## Namespace: 6 | - Darkterminal\LibSQL\Utils\Exceptions 7 | 8 | ## Uses: 9 | - Darkterminal\LibSQL\Traits\Logging 10 | 11 | ## Properties: 12 | - **code**: string 13 | Machine-readable error code. 14 | - **rawCode**: int|null 15 | Raw numeric error code. 16 | 17 | ## Methods: 18 | - public - __construct 19 | Description: Constructor. 20 | Link: [None] 21 | Parameters: 22 | - $message (string): The error message. 23 | - $code (string): The machine-readable error code. 24 | - $rawCode (int|null): The raw numeric error code. 25 | - $cause (Throwable|null): The cause of the error. 26 | 27 | --- 28 | 29 | ## Overview: 30 | The `LibsqlError` class represents an error thrown by the client. It extends the built-in PHP `\Exception` class and includes the trait `Logging` from the namespace `Darkterminal\LibSQL\Traits`. It provides properties to store a machine-readable error code and a raw numeric error code. The constructor initializes the error message, error code, raw code, and the cause of the error if provided. 31 | -------------------------------------------------------------------------------- /docs/Utils/constants.md: -------------------------------------------------------------------------------- 1 | ### `URI_RE` 2 | 3 | **Description:** Regular expression pattern for parsing URIs. 4 | 5 | **Value:** `'/^(?[A-Za-z][A-Za-z.+-]*):(\/\/(?[^\/?#]*))?(?[^?#]*)(\?(?[^#]*))?(#(?.*))?$/` 6 | 7 | --- 8 | 9 | ### `AUTHORITY_RE` 10 | 11 | **Description:** Regular expression pattern for parsing the authority part of a URL. 12 | 13 | **Value:** `'/^((?[^:]*)(:(?.*))?@)?((?[^:\[\]]*)|(\[(?[^\[\]]*)\]))(:(?[0-9]*))?$/` 14 | 15 | --- 16 | 17 | ### `SUPPORTED_URL_LINK` 18 | 19 | **Description:** Link to the documentation page for supported URLs. 20 | 21 | **Value:** `"https://github.com/libsql/libsql-client-php#supported-urls"` 22 | 23 | --- 24 | 25 | ### `TURSO` 26 | 27 | **Description:** A constant with the value `'turso.io'`. 28 | 29 | **Value:** `'turso.io'` 30 | 31 | --- 32 | 33 | ### `PIPE_LINE_ENDPOINT` 34 | 35 | **Description:** Endpoint for pipeline operations. 36 | 37 | **Value:** `'/v3/pipeline'` 38 | 39 | --- 40 | 41 | ### `VERSION_ENDPOINT` 42 | 43 | **Description:** Endpoint for version information. 44 | 45 | **Value:** `'/version'` 46 | 47 | --- 48 | 49 | ### `HEALTH_ENDPOINT` 50 | 51 | **Description:** Endpoint for health status. 52 | 53 | **Value:** `'/health'` 54 | 55 | --- 56 | 57 | ### `LIBSQL_CLOSE`, `LIBSQL_EXECUTE`, `LIBSQL_BATCH`, `LIBSQL_SEQUENCE`, `LIBSQL_DESCRIBE`, `LIBSQL_STORE_SQL`, `LIBSQL_GET_AUTO_COMMIT` 58 | 59 | **Description:** Constants representing different operations for LibSQL. 60 | 61 | **Values:** `'close'`, `'execute'`, `'bath'`, `'sequence'`, `'describe'`, `'store_sql'`, `'get_autocommit'` 62 | -------------------------------------------------------------------------------- /docs/Utils/helpers.md: -------------------------------------------------------------------------------- 1 | # Helpers 2 | 3 | ### `transactionModeToBegin(string $mode): string` 4 | 5 | **Description:** Converts a transaction mode to a corresponding BEGIN statement. 6 | 7 | **Parameters:** 8 | - `$mode` (string): The transaction mode. 9 | 10 | **Returns:** string 11 | 12 | **Throws:** `\RangeException` if an unknown transaction mode is provided. 13 | 14 | --- 15 | 16 | ### `expandConfig(array $config, bool $preferHttp): ExpandedConfig` 17 | 18 | **Description:** Expands the provided client configuration into an `ExpandedConfig` object. 19 | 20 | **Parameters:** 21 | - `$config` (array): The client configuration array. 22 | - `$preferHttp` (bool): Whether to prefer HTTP over WebSocket. 23 | 24 | **Returns:** `ExpandedConfig` 25 | 26 | **Throws:** `TypeError` if the provided configuration is not an array, `LibsqlError` if there is an error in the configuration or unsupported URL scheme. 27 | 28 | --- 29 | 30 | ### `parseUri(string $text): Uri` 31 | 32 | **Description:** Parses a URI string and returns a `Uri` object. 33 | 34 | **Parameters:** 35 | - `$text` (string): The URI string to parse. 36 | 37 | **Returns:** `Uri` 38 | 39 | **Throws:** `LibsqlError` if the URI is not in a valid format. 40 | 41 | --- 42 | 43 | ### `parseAuthority(string $text): Authority` 44 | 45 | **Description:** Parses the authority part of a URL and returns an `Authority` object. 46 | 47 | **Parameters:** 48 | - `$text` (string): The authority part of the URL. 49 | 50 | **Returns:** `Authority` 51 | 52 | **Throws:** `LibsqlError` if the authority part of the URL is not in a valid format. 53 | 54 | --- 55 | 56 | ### `parseQuery(string $text): Query` 57 | 58 | **Description:** Parses the query string of a URI and returns a `Query` object. 59 | 60 | **Parameters:** 61 | - `$text` (string): The query string to parse. 62 | 63 | **Returns:** `Query` 64 | 65 | --- 66 | 67 | ### `percentDecode(string $text): string` 68 | 69 | **Description:** Decodes a percent-encoded string. 70 | 71 | **Parameters:** 72 | - `$text` (string): The string to decode. 73 | 74 | **Returns:** string 75 | 76 | **Throws:** `LibsqlError` if the URL component has invalid percent encoding. 77 | 78 | --- 79 | 80 | ### `encodeBaseUrl(string $scheme, ?Authority $authority, string $path): array|string|int|false|null` 81 | 82 | **Description:** Encodes the components of a URI and returns a URL object. 83 | 84 | **Parameters:** 85 | - `$scheme` (string): The scheme of the URI. 86 | - `$authority` (Authority|null): The authority of the URI. 87 | - `$path` (string): The path of the URI. 88 | 89 | **Returns:** array|string|int|false|null 90 | 91 | **Throws:** `LibsqlError` if the URL requires authority. 92 | 93 | --- 94 | 95 | ### `encodeHost(string $host): string` 96 | 97 | **Description:** Encodes the host component of a URI. 98 | 99 | **Parameters:** 100 | - `$host` (string): The host to encode. 101 | 102 | **Returns:** string 103 | 104 | --- 105 | 106 | ### `encodePort(?int $port): string` 107 | 108 | **Description:** Encodes the port component of a URI. 109 | 110 | **Parameters:** 111 | - `$port` (int|null): The port to encode. 112 | 113 | **Returns:** string 114 | 115 | --- 116 | 117 | ### `encodeUserInfo(?UserInfo $userInfo): string` 118 | 119 | **Description:** Encodes the userInfo component of a URI. 120 | 121 | **Parameters:** 122 | - `$userInfo` (UserInfo|null): The userInfo to encode. 123 | 124 | **Returns:** string 125 | 126 | --- 127 | 128 | ### `is_base64(string $data): bool` 129 | 130 | **Description:** Checks if a string is base64 encoded. 131 | 132 | **Parameters:** 133 | - `$data` (string): The string to check. 134 | 135 | **Returns:** bool 136 | 137 | --- 138 | 139 | ### `checkColumnType(mixed $column): string` 140 | 141 | **Description:** Determines the type of a given column value. 142 | 143 | **Parameters:** 144 | - `$column` (mixed): The column value to check. 145 | 146 | **Returns:** string 147 | 148 | --- 149 | 150 | ### `map_results(string $data): array` 151 | 152 | **Description:** Maps JSON data to a structured format. 153 | 154 | **Parameters:** 155 | - `$data` (string): The JSON data to be mapped. 156 | 157 | **Returns:** array 158 | 159 | **Throws:** `LibsqlError` if there is an error in the JSON data. 160 | 161 | --- 162 | 163 | ### `objectToArray($object)` 164 | 165 | **Description:** Recursively converts an object to an array. 166 | 167 | **Parameters:** 168 | - `$object`: The object to convert. 169 | 170 | **Returns:** mixed (array) 171 | -------------------------------------------------------------------------------- /examples/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkterminal/libsql-client-php/cb61687433498c3340c5ed37b1ed33129dc9efc0/examples/.gitkeep -------------------------------------------------------------------------------- /examples/local-file/check-version.php: -------------------------------------------------------------------------------- 1 | "file:database.db", 9 | "flags" => LIBSQLPHP_OPEN_READWRITE | LIBSQLPHP_OPEN_CREATE, 10 | "encryptionKey" => "" 11 | ]; 12 | 13 | $db = new LibSQL($config); 14 | 15 | if ($db->connect()) { 16 | echo "Connection Establised!" . PHP_EOL; 17 | echo "--- ". $db->version() ." ---" . PHP_EOL; 18 | } 19 | $db->close(); 20 | -------------------------------------------------------------------------------- /examples/local-file/execute.php: -------------------------------------------------------------------------------- 1 | "file:database.db", 9 | "flags" => LIBSQLPHP_OPEN_READWRITE | LIBSQLPHP_OPEN_CREATE, 10 | "encryptionKey" => "" 11 | ]; 12 | 13 | $db = new LibSQL($config); 14 | 15 | if ($db->connect()) { 16 | echo "Connection Establised!" . PHP_EOL; 17 | echo "--- ". $db->version() ." ---" . PHP_EOL; 18 | 19 | $result = $db->execute(query: "INSERT INTO users (name) VALUES (?)", params: ['Belina Bogge']); 20 | var_dump($result); 21 | } 22 | $db->close(); 23 | -------------------------------------------------------------------------------- /examples/local-file/placeholders.php: -------------------------------------------------------------------------------- 1 | "file:database.db", 9 | "flags" => LIBSQLPHP_OPEN_READWRITE | LIBSQLPHP_OPEN_CREATE, 10 | "encryptionKey" => "" 11 | ]; 12 | 13 | $db = new LibSQL($config); 14 | 15 | if ($db->connect()) { 16 | echo "Connection Establised!" . PHP_EOL; 17 | echo "--- ". $db->version() ." ---" . PHP_EOL; 18 | 19 | $result = $db->execute(query: "SELECT * FROM users"); 20 | var_dump($result->toArray()); 21 | } 22 | $db->close(); 23 | -------------------------------------------------------------------------------- /examples/remote-http/batch-query.php: -------------------------------------------------------------------------------- 1 | 'libsql://127.0.0.1:8001', 10 | 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), 11 | 'tls' => false 12 | ]; 13 | 14 | $db = new LibSQL($config); 15 | 16 | if ($db->connect()) { 17 | echo "Connection Establised!" . PHP_EOL; 18 | echo "--- " . $db->version() . " ---" . PHP_EOL; 19 | } 20 | 21 | // Batch Query Example 22 | $stmts = [ 23 | HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Ramons", 32]), 24 | HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Georgia", 43]) 25 | ]; 26 | $results = $db->batch(queries: $stmts); 27 | print_r($results); 28 | -------------------------------------------------------------------------------- /examples/remote-http/sequence-query.php: -------------------------------------------------------------------------------- 1 | 'libsql://127.0.0.1:8001', 9 | 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), 10 | 'tls' => false 11 | ]; 12 | 13 | $db = new LibSQL($config); 14 | 15 | if ($db->connect()) { 16 | echo "Connection Establised!" . PHP_EOL; 17 | echo "--- " . $db->version() . " ---" . PHP_EOL; 18 | } 19 | 20 | 21 | // Simple Query and Parameter Binding Example 22 | $query = " 23 | UPDATE users SET name = 'Turso DB' WHERE id = 1; 24 | UPDATE users SET name = 'ducktermin; 25 | "; 26 | $result = $db->executeMultiple($query); 27 | print_r($result); 28 | -------------------------------------------------------------------------------- /examples/remote-http/simple-query.php: -------------------------------------------------------------------------------- 1 | 'libsql://127.0.0.1:8001', 11 | 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), 12 | 'tls' => false 13 | ]; 14 | 15 | $db = new LibSQL($config); 16 | 17 | if ($db->connect()) { 18 | echo "Connection Establised!" . PHP_EOL; 19 | echo "--- ". $db->version() ." ---" . PHP_EOL; 20 | } 21 | 22 | 23 | // Simple Query 24 | $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 25 | $results = $db->execute(query: $query); 26 | echo $results->fetch(type: LibSQLResult::FETCH_OBJ) . PHP_EOL; 27 | // print_r($results->fetch(type: LibSQLResult::FETCH_ASSOC)); 28 | -------------------------------------------------------------------------------- /examples/remote-http/transaction-query.php: -------------------------------------------------------------------------------- 1 | 'libsql://127.0.0.1:8001', 10 | 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), 11 | 'tls' => false 12 | ]; 13 | 14 | $db = new LibSQL($config); 15 | 16 | if ($db->connect()) { 17 | echo "Connection Establised!" . PHP_EOL; 18 | echo "--- " . $db->version() . " ---" . PHP_EOL; 19 | } 20 | 21 | // Start a new transaction 22 | $transaction = $db->transaction(); 23 | 24 | // Add the first SQL statement to the transaction 25 | if (true) { 26 | $transaction->addTransaction(HttpStatement::create("UPDATE users SET name = 'Turso DB' WHERE id = 1")); 27 | } else { 28 | // If a condition is not met, rollback the transaction and exit 29 | $transaction->rollback(); 30 | exit(); 31 | } 32 | 33 | // Add the second SQL statement to the transaction 34 | if (true) { 35 | $transaction->addTransaction(HttpStatement::create("UPDATE users SET name = 'darkterminal' WHERE id = 2")); 36 | } else { 37 | // If another condition is not met, rollback the transaction and exit 38 | $transaction->rollback(); 39 | exit(); 40 | } 41 | 42 | // End the transaction (commit changes) 43 | $result = $transaction->endTransaction(); 44 | print_r($result); 45 | -------------------------------------------------------------------------------- /examples/remote-replica/connection.php: -------------------------------------------------------------------------------- 1 | "file:database.db", 9 | "authToken" => getenv('TURSO_DATABASE_TOKEN'), 10 | "syncUrl" => getenv('TURSO_DATABASE_URL'), 11 | "syncInterval" => 5, 12 | "read_your_writes" => true 13 | ]; 14 | 15 | $db = new LibSQL($config); 16 | 17 | if ($db->connect()) { 18 | echo "Connection Establised!" . PHP_EOL; 19 | echo "--- ". $db->version() ." ---" . PHP_EOL; 20 | } 21 | $db->close(); 22 | -------------------------------------------------------------------------------- /src/LibSQL.php: -------------------------------------------------------------------------------- 1 | [A-Za-z][A-Za-z.+-]*):(\/\/(?[^\/?#]*))?(?[^?#]*)(\?(?[^#]*))?(#(?.*))?$/'; 27 | 28 | public const AUTHORITY_RE = '/^((?[^:]*)(:(?.*))?@)?((?[^:\[\]]*)|(\[(?[^\[\]]*)\]))(:(?[0-9]*))?$/'; 29 | 30 | public const SUPPORTED_URL_LINK = "https://github.com/libsql/libsql-client-php#supported-urls"; 31 | 32 | public const TURSO = 'turso.io'; 33 | 34 | public const PIPE_LINE_ENDPOINT = '/v3/pipeline'; 35 | 36 | public const VERSION_ENDPOINT = '/version'; 37 | 38 | public const HEALTH_ENDPOINT = '/health'; 39 | 40 | public const LIBSQL_CLOSE = 'close'; 41 | 42 | public const LIBSQL_EXECUTE = 'execute'; 43 | 44 | public const LIBSQL_BATCH = 'bath'; 45 | 46 | public const LIBSQL_SEQUENCE = 'sequence'; 47 | 48 | public const LIBSQL_DESCRIBE = 'describe'; 49 | 50 | public const LIBSQL_STORE_SQL = 'store_sql'; 51 | 52 | public const LIBSQL_GET_AUTO_COMMIT = 'get_autocommit'; 53 | 54 | public const REMOTE = 'Remote'; 55 | 56 | public const REMOTE_REPLICA = 'RemoteReplica'; 57 | 58 | public const LOCAL = 'Local'; 59 | 60 | /** 61 | * @var HttpClient $httpProvider The HTTP client provider. 62 | */ 63 | protected HttpClient $httpProvider; 64 | 65 | /** 66 | * @var LocalClient $localProvider The local client provider. 67 | */ 68 | protected LocalClient $localProvider; 69 | 70 | /** 71 | * @var RemoteReplicaClient $remoteReplicaProvicer The Remote Replica client provider 72 | */ 73 | protected RemoteReplicaClient $remoteReplicaProvider; 74 | 75 | /** 76 | * @var string $mode The current connection mode (either "Remote" or "Local"). 77 | */ 78 | protected string $mode; 79 | 80 | /** 81 | * Constructs a new LibSQL instance. 82 | * 83 | * **Example Local Connection** 84 | * 85 | * ``` 86 | * $config = [ 87 | * "url" => "file:database.db", 88 | * "flags" => LIBSQLPHP_OPEN_READWRITE | LIBSQLPHP_OPEN_CREATE, 89 | * "encryptionKey" => "" 90 | * ]; 91 | * 92 | * $db = new LibSQL($config); 93 | * $db->connect(); 94 | * ``` 95 | * 96 | * **Example Remote Connection** 97 | * 98 | * ``` 99 | * $config = [ 100 | * 'url' => 'libsql://127.0.0.1:8001', // libsql://database-origanization.turso.io 101 | * 'authToken' => getenv('LIBSQL_PHP_FA_TOKEN'), 102 | * 'tls' => false 103 | * ]; 104 | * 105 | * $db = new LibSQL($config); 106 | * ``` 107 | * 108 | * @param array $config The configuration array for the LibSQL service. 109 | * @throws LibsqlError If there is an error creating the HTTP client. 110 | */ 111 | public function __construct(array $config) 112 | { 113 | $configBuilder = Mods::expandConfig($config, true); 114 | 115 | if ($configBuilder->scheme === ExpandedScheme::file && !empty($configBuilder->authToken) && !empty($configBuilder->syncUrl)) { 116 | $this->remoteReplicaProvider = new RemoteReplicaClient( 117 | $configBuilder->path, 118 | $configBuilder->authToken, 119 | $configBuilder->syncUrl, 120 | $configBuilder->syncInterval, 121 | $configBuilder->read_your_writes 122 | ); 123 | $this->mode = 'RemoteReplica'; 124 | } else if (in_array($configBuilder->scheme, [ExpandedScheme::http, ExpandedScheme::https]) && !empty($configBuilder->authToken)) { 125 | if ($configBuilder->scheme !== ExpandedScheme::https && $configBuilder->scheme !== ExpandedScheme::http) { 126 | throw new LibsqlError( 127 | 'The HTTP client supports only "libsql:", "https:" and "http:" URLs, got ' . $configBuilder->scheme, 128 | "URL_SCHEME_NOT_SUPPORTED", 129 | ); 130 | } 131 | 132 | if ($configBuilder->scheme === ExpandedScheme::http && $configBuilder->tls) { 133 | throw new LibsqlError('A "http:" URL cannot opt into TLS by using ?tls=1', "URL_INVALID"); 134 | } else if ($configBuilder->scheme === ExpandedScheme::https && !$configBuilder->tls) { 135 | throw new LibsqlError('A "https:" URL cannot opt out of TLS by using ?tls=0', "URL_INVALID"); 136 | } 137 | 138 | $url = Mods::encodeBaseUrl($configBuilder->scheme, $configBuilder->authority, $configBuilder->path); 139 | $this->httpProvider = new HttpClient(); 140 | $this->httpProvider->setup($url, $configBuilder->authToken); 141 | $this->mode = 'Remote'; 142 | } else if ($configBuilder->scheme === ExpandedScheme::file && !empty($configBuilder->flags) && !empty($configBuilder->path)) { 143 | $this->localProvider = new LocalClient(); 144 | $this->localProvider->setup($configBuilder->path, $configBuilder->flags, $configBuilder->encryptionKey); 145 | $this->mode = "Local"; 146 | } else { 147 | throw new LibsqlError('Invalid Connection! Only support Remote and Local connection', 'ERR_INVALID_CONNECTION'); 148 | } 149 | } 150 | 151 | /** 152 | * Checking connection mode 153 | * 154 | * @return string 155 | */ 156 | public function connectionMode(): string 157 | { 158 | return $this->mode; 159 | } 160 | 161 | /** 162 | * Establishes a connection to the database. 163 | * 164 | * @throws LibsqlError Thrown if the connection mode is not recognized. 165 | * 166 | * @return bool True if the connection is successfully established, false otherwise. 167 | */ 168 | public function connect(): bool 169 | { 170 | switch ($this->mode) { 171 | case LibSQL::REMOTE: 172 | return $this->httpProvider->connect(); 173 | break; 174 | case LibSQL::LOCAL: 175 | return $this->localProvider->connect(); 176 | break; 177 | case LibSQL::REMOTE_REPLICA: 178 | return $this->remoteReplicaProvider->connect(); 179 | break; 180 | default: 181 | throw new LibsqlError("Connection mode is not found", "ERR_MODE_NOT_FOUND"); 182 | break; 183 | } 184 | } 185 | 186 | /** 187 | * Retrieves the version information of the database. 188 | * 189 | * @throws LibsqlError Thrown if the connection mode is not recognized. 190 | * 191 | * @return string The version information of the database. 192 | */ 193 | public function version(): string 194 | { 195 | switch ($this->mode) { 196 | case LibSQL::REMOTE: 197 | return $this->httpProvider->version(); 198 | break; 199 | case LibSQL::LOCAL: 200 | return $this->localProvider->version(); 201 | break; 202 | case LibSQL::REMOTE_REPLICA: 203 | return $this->remoteReplicaProvider->version(); 204 | break; 205 | default: 206 | throw new LibsqlError("Connection mode is not found", "ERR_MODE_NOT_FOUND"); 207 | break; 208 | } 209 | } 210 | 211 | /** 212 | * Executes a query. 213 | * 214 | * ### NOTE: Use _Named Paramaters_ is recommended 215 | * 216 | * 217 | * **Parameters** 218 | * 219 | * **$query** 220 | * - _HttpStatement_ - **[Remote Only]** Parameter used for Remote connection only - [Ref:HttpStatement](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpStatement.php) 221 | * - _string_ - **[Local only]** Parameter used for Local connection only 222 | * 223 | * **$baton** 224 | * - _string_ - **[Remote Only]** The baton value for the query. 225 | * 226 | * **$params** 227 | * - _array_ - **[Local Only]** Parameters for the query. 228 | * 229 | * **Return** 230 | * 231 | * - _HttpResponse_ - **[Remote Only]** instance of HttpResponse for remote mode - [Ref:HttpResponse](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpResponse.php) 232 | * - _bool_ - **[Local Only]** Parameters for the query. 233 | * 234 | * **Remote Usage Example** 235 | * 236 | * ``` 237 | * $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 238 | * $results = $db->execute(query: $query); 239 | * echo $results->fetch(type: LibSQLResult::FETCH_OBJ) . PHP_EOL; 240 | * ``` 241 | * 242 | * **Local Usage Example** 243 | * 244 | * ``` 245 | * $result = $db->execute(query: "INSERT INTO users (name) VALUES (?)", params: ['Belina Bogge']); 246 | * var_dump($result); 247 | * ``` 248 | * 249 | * @param string|HttpStatement $query The query to execute, either a string or an instance of HttpStatement. 250 | * @param string $baton (Optional) The baton value for the query. 251 | * @param array $params (Optional) Parameters for the query. 252 | * 253 | * @throws LibsqlError Thrown if the connection mode is not recognized. 254 | * 255 | * @return LibSQLPHPClientResult|HttpResponse True if successful for local mode; otherwise, an instance of HttpResponse for remote mode. - [Ref:Executes a Query](https://github.com/darkterminal/libsql-php-ext/blob/main/docs/LibSQL.md#executes-a-query) 256 | */ 257 | public function execute(string|HttpStatement $query, string $baton = '', ?array $params = []): LibSQLPHPClientResult|HttpResponse 258 | { 259 | switch ($this->mode) { 260 | case LibSQL::REMOTE: 261 | return $this->httpProvider->execute($query, $baton); 262 | break; 263 | case LibSQL::LOCAL: 264 | return $this->localProvider->execute($query, $params); 265 | break; 266 | case LibSQL::REMOTE_REPLICA: 267 | return $this->remoteReplicaProvider->execute($query, $params); 268 | break; 269 | default: 270 | throw new LibsqlError("Connection mode is not found", "ERR_MODE_NOT_FOUND"); 271 | break; 272 | } 273 | } 274 | 275 | /** 276 | * Executes a batch of queries. 277 | * 278 | * ### NOTE: Remote Only 279 | * 280 | * Mode Options Available: 281 | * - deferred (default) 282 | * - write 283 | * - read 284 | * 285 | * Everyting is in lower-case or you can use **TransactionMode** Class Constants 286 | * 287 | * **Example - [Ref:Example](https://docs.turso.tech/sdk/http/reference#interactive-query)** 288 | * 289 | * ``` 290 | * $stmts = [ 291 | * HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Ramons", 32]), 292 | * HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Georgia", 43]) 293 | * ]; 294 | * $results = $db->batch(queries: $stmts); 295 | * print_r($results); 296 | * ``` 297 | * 298 | * @param array $queries The array of queries to execute. 299 | * @param string $mode (Optional) The transaction behavior mode. Default is "deferred" 300 | * 301 | * @throws LibsqlError Thrown if the function is called for a local mode connection. 302 | * 303 | * @return HttpResponse The HTTP response containing the result of the batch execution. - [Ref:HttpResponse](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpResponse.php) 304 | */ 305 | public function batch(array $queries, string $mode = "deferred"): HttpResponse 306 | { 307 | if (in_array($this->mode, [LibSQL::LOCAL, LibSQL::REMOTE_REPLICA])) { 308 | throw new LibsqlError("This function only for Remote (HTTP) provider", "INVALID_FUNCTION_CALL"); 309 | } 310 | 311 | return $this->httpProvider->batch($queries, $mode); 312 | } 313 | 314 | /** 315 | * Executes a batch of queries. 316 | * 317 | * ### NOTE: Local Only 318 | * 319 | * **Example - [Ref:Execute Batch](https://github.com/tursodatabase/libsql/blob/main/libsql/src/local/connection.rs#L116-L137)** 320 | * 321 | * ``` 322 | * $db->execute_batch(" 323 | * BEGIN; 324 | * CREATE TABLE foo(x INTEGER); 325 | * CREATE TABLE bar(y TEXT); 326 | * COMMIT; 327 | * "); 328 | * ``` 329 | * 330 | * @param string $query The batch query to execute. 331 | * 332 | * @throws LibsqlError Thrown if the function is called for a remote mode connection. 333 | * 334 | * @return void 335 | */ 336 | public function execute_batch(string $query): void 337 | { 338 | if ($this->mode === LibSQL::REMOTE) { 339 | } 340 | 341 | switch ($this->mode) { 342 | case LibSQL::LOCAL: 343 | $this->localProvider->batch($query); 344 | break; 345 | case LibSQL::REMOTE_REPLICA: 346 | $this->remoteReplicaProvider->batch($query); 347 | break; 348 | default: 349 | throw new LibsqlError("This function only for Local (FILE) provider", "INVALID_FUNCTION_CALL"); 350 | break; 351 | } 352 | } 353 | 354 | /** 355 | * Executes multiple SQL queries in a single HTTP request. 356 | * 357 | * ### NOTE: Remote Only 358 | * 359 | * **Example* 360 | * 361 | * ``` 362 | * $query = " 363 | * UPDATE users SET name = 'Turso DB' WHERE id = 1; 364 | * UPDATE users SET name = 'ducktermin; 365 | * "; 366 | * $result = $db->executeMultiple($query); 367 | * print_r($result); 368 | * ``` 369 | * Refs: 370 | * - [Ref:http.ts Implementation](https://github.com/tursodatabase/libsql-client-ts/blob/main/packages/libsql-client/src/http.ts#L124-L140) 371 | * - [Ref:HRANA_3_SPEC](https://github.com/tursodatabase/libsql/blob/main/docs/HRANA_3_SPEC.md#L844) 372 | * 373 | * @param string $query The SQL queries to execute. 374 | * 375 | * @throws LibsqlError Thrown if the function is called for a local mode connection. 376 | * 377 | * @return string The response from executing the queries. 378 | */ 379 | public function executeMultiple(string $query): string 380 | { 381 | if (in_array($this->mode, [LibSQL::LOCAL, LibSQL::REMOTE_REPLICA])) { 382 | throw new LibsqlError("This function only for Remote (HTTP) provider", "INVALID_FUNCTION_CALL"); 383 | } 384 | 385 | return $this->httpProvider->executeMultiple($query); 386 | } 387 | 388 | /** 389 | * Initiates a transaction for executing SQL queries either remotely or locally. 390 | * 391 | * ### NOTE: Remote and Local Used - **Recommended Read Ref:Link below** 392 | * 393 | * Mode Options Available: 394 | * - deferred (default: in Local) 395 | * - write (default: in Remote) 396 | * - read 397 | * 398 | * **Example - Remote Usage** 399 | * 400 | * ``` 401 | * // Start a new transaction 402 | * $transaction = $db->transaction(); 403 | * 404 | * // Add the first SQL statement to the transaction 405 | * if (true) { 406 | * $transaction->addTransaction(HttpStatement::create("UPDATE users SET name = 'Turso DB' WHERE id = 1")); 407 | * } else { 408 | * // If a condition is not met, rollback the transaction and exit 409 | * $transaction->rollback(); 410 | * exit(); 411 | * } 412 | * 413 | * // Add the second SQL statement to the transaction 414 | * if (true) { 415 | * $transaction->addTransaction(HttpStatement::create("UPDATE users SET name = 'darkterminal' WHERE id = 2")); 416 | * } else { 417 | * // If another condition is not met, rollback the transaction and exit 418 | * $transaction->rollback(); 419 | * exit(); 420 | * } 421 | * 422 | * // End the transaction (commit changes) 423 | * $result = $transaction->endTransaction(); 424 | * print_r($result); 425 | * ``` 426 | * 427 | * **Example - Local Usage** 428 | * 429 | * ``` 430 | * $operations_successful = false; 431 | * $tx = $db->transaction(TransactionBehavior::Deferred); 432 | * $tx->exec("INSERT INTO users (name) VALUES (?)", ["Emanuel"]); 433 | * $tx->exec("INSERT INTO users (name) VALUES (?)", ["Darren"]); 434 | * 435 | * if ($operations_successful) { 436 | * $tx->commit(); 437 | * echo "Commit the changes" . PHP_EOL; 438 | * } else { 439 | * $tx->rollback(); 440 | * echo "Rollback the changes" . PHP_EOL; 441 | * } 442 | * ``` 443 | * 444 | * **Return** 445 | * - _**HttpTransaction**_ - The return class when using **Remote Connection** [Ref:HttpTransaction](https://github.com/darkterminal/libsql-client-php/blob/main/src/Types/HttpTransaction.php) 446 | * - _**Transaction**_ - The return class when using **Local Connection** - [Ref:Transaction](https://github.com/darkterminal/libsql-php-ext/blob/main/php-src/Responses/Transaction.php) 447 | * 448 | * @param string $mode The transaction mode. Defaults to 'write'. 449 | * 450 | * @throws LibsqlError Thrown if the connection mode is not recognized. 451 | * 452 | * @return HttpTransaction|Transaction An instance of HttpTransaction for remote connections or Transaction for local connections. 453 | */ 454 | public function transaction(string $mode = 'write'): HttpTransaction|Transaction 455 | { 456 | switch ($this->mode) { 457 | case LibSQL::REMOTE: 458 | return $this->httpProvider->transaction($mode); 459 | break; 460 | case LibSQL::LOCAL: 461 | return $this->localProvider->transaction($mode); 462 | break; 463 | case LibSQL::REMOTE_REPLICA: 464 | return $this->remoteReplicaProvider->transaction($mode); 465 | break; 466 | default: 467 | throw new LibsqlError("Connection mode is not found", "ERR_MODE_NOT_FOUND"); 468 | break; 469 | } 470 | } 471 | 472 | /** 473 | * Synchronizes the database. 474 | * 475 | * ### NOTE: This Only Support for RemoteReplica and LocalReplica - [Ref:Builder Details](https://github.com/tursodatabase/libsql/blob/main/libsql/src/database/builder.rs#L8-L25) 476 | * 477 | * @throws LibsqlError Thrown if sync is called in Remote (HTTP) or Local (FILE) mode. 478 | * 479 | * @return int 480 | */ 481 | public function sync(): int 482 | { 483 | if ($this->mode === LibSQL::LOCAL || $this->mode === LibSQL::REMOTE) { 484 | throw new LibsqlError("sync not supported in Remote (HTTP) or Local (FILE) mode", "SYNC_NOT_SUPPORTED"); 485 | } 486 | 487 | return $this->remoteReplicaProvider->sync(); 488 | } 489 | 490 | /** 491 | * Closes the database connection. 492 | * 493 | * @throws LibsqlError Thrown if the connection mode is not recognized. 494 | * 495 | * @return void 496 | */ 497 | public function close(): void 498 | { 499 | switch ($this->mode) { 500 | case LibSQL::REMOTE: 501 | $this->httpProvider->close(); 502 | break; 503 | case LibSQL::LOCAL: 504 | $this->localProvider->close(); 505 | break; 506 | case LibSQL::REMOTE_REPLICA: 507 | $this->remoteReplicaProvider->close(); 508 | break; 509 | default: 510 | throw new LibsqlError("Connection mode is not recognized", "ERR_MODE_NOT_FOUND"); 511 | break; 512 | } 513 | } 514 | } 515 | -------------------------------------------------------------------------------- /src/Providers/HttpClient.php: -------------------------------------------------------------------------------- 1 | url = $url; 94 | $this->authToken = $authToken; 95 | $this->timeout = $timeout; 96 | 97 | $this->initializeHttp(); 98 | } 99 | 100 | /** 101 | * Initializes the HTTP client with the specified headers and options. 102 | */ 103 | private function initializeHttp(): void 104 | { 105 | $this->headers = [ 106 | 'Content-Type' => 'Application/json' 107 | ]; 108 | if (!empty($this->authToken)) { 109 | $this->headers['Authorization'] = 'Bearer ' . $this->authToken; 110 | } 111 | 112 | // Initialize Guzzle HTTP client 113 | $this->http = new Client([ 114 | 'base_uri' => $this->url, 115 | 'timeout' => $this->timeout, 116 | 'headers' => $this->headers 117 | ]); 118 | } 119 | 120 | /** 121 | * Connect to the HTTP server. 122 | * 123 | * @return bool|LibsqlError True if connection is successful, otherwise a LibsqlError instance. 124 | * @throws LibsqlError If connection fails. 125 | */ 126 | public function connect(): bool|LibsqlError 127 | { 128 | try { 129 | // Send a health check request to the server 130 | $request = new Request('GET', LibSQL::HEALTH_ENDPOINT, $this->headers); 131 | $response = $this->http->send($request); 132 | return $response->getStatusCode() === 200; 133 | } catch (\Throwable $e) { 134 | // If connection fails, throw a LibsqlError 135 | throw new LibsqlError("Connection failed! " . $e->getMessage(), "CONNECTION_ERROR"); 136 | } 137 | } 138 | 139 | /** 140 | * Execute an HTTP statement. 141 | * This method follow @link [Turso - Simple Query](https://docs.turso.tech/sdk/http/reference#simple-query) 142 | * 143 | * @param HttpStatement $query The HTTP statement to execute. 144 | * @param string $baton (Optional) The baton string. 145 | * 146 | * @return HttpResponse The HTTP response containing the results of the execution. 147 | * 148 | * @throws LibsqlError If there is an error in the execution of the statement. 149 | */ 150 | public function execute(HttpStatement $query, string $baton = ''): HttpResponse 151 | { 152 | // Create request payload 153 | $payload = $this->_createRequest(LibSQL::LIBSQL_EXECUTE, $query->sql, $query->args, $query->named_args); 154 | $request = (!empty($baton)) ? $this->_makeRequest($payload, false, $baton) : $this->_makeRequest($payload); 155 | 156 | // Send POST request 157 | $response = $this->runQuery($request, true); 158 | 159 | // Process response and return HttpResponse object 160 | $data = map_results($response->getBody()); 161 | return HttpResponse::create($data['baton'], $data['base_url'], $data['results']); 162 | } 163 | 164 | /** 165 | * Execute a batch of HTTP statements. 166 | * This method follow @link [Turso - Interactive Query](https://docs.turso.tech/sdk/http/reference#interactive-query) 167 | * 168 | * @param array $queries The array of HTTP statements to execute. 169 | * @param string $mode (Optional) The transaction mode read, write, or deferred. Default is 'deferred'. 170 | * 171 | * @return HttpResponse The HTTP response containing the results of the batch execution. 172 | * 173 | * @throws LibsqlError If there is an error in the batch execution. 174 | */ 175 | public function batch(array $queries, string $mode = 'deferred'): HttpResponse 176 | { 177 | try { 178 | // Check if the transaction mode is valid 179 | TransactionMode::checker($mode); 180 | 181 | // Create the start transaction request 182 | $startTransaction = $this->_createRequest(LibSQL::LIBSQL_EXECUTE, Mods::transactionModeToBegin($mode)); 183 | 184 | // Initialize the batch payload 185 | $batchPayload = []; 186 | 187 | // Iterate through each statement and add it to the batch payload 188 | foreach ($queries as $stmt) { 189 | /** @var HttpStatement $stmt */ 190 | \array_push($batchPayload, $this->_createRequest(LibSQL::LIBSQL_EXECUTE, $stmt->sql, $stmt->args, $stmt->named_args)); 191 | } 192 | 193 | // Add a commit request to the batch payload 194 | \array_push($batchPayload, $this->_createRequest(LibSQL::LIBSQL_EXECUTE, 'COMMIT')); 195 | 196 | // Execute the batch request asynchronously 197 | return $this->http->postAsync(LibSQL::PIPE_LINE_ENDPOINT, [ 198 | 'json' => $this->_makeRequest($startTransaction, false) 199 | ])->then( 200 | function (ResponseInterface $res) use ($batchPayload) { 201 | // Handle the response from the start transaction request 202 | $beginResult = map_results($res->getBody()); 203 | $trx = HttpResponse::create($beginResult['baton'], $beginResult['base_url'], $beginResult['results']); 204 | 205 | // Execute the batch payload asynchronously 206 | return $this->http->postAsync(LibSQL::PIPE_LINE_ENDPOINT, [ 207 | 'json' => $this->_makeRequest($batchPayload, true, $trx->baton) 208 | ])->then( 209 | function (ResponseInterface $res) { 210 | // Handle the response from the batch execution 211 | $transactionResults = map_results($res->getBody()); 212 | return HttpResponse::create($transactionResults['baton'], $transactionResults['base_url'], $transactionResults['results']); 213 | }, 214 | function (RequestException $e) { 215 | // Handle request exceptions during batch execution 216 | throw new LibsqlError($e->getRequest()->getMethod() . " - " . $e->getMessage(), "INVALID_BATCH_TRANSACTION"); 217 | } 218 | )->wait(); 219 | }, 220 | function (RequestException $e) { 221 | $this->_close(); 222 | // Handle request exceptions during start transaction 223 | throw new LibsqlError($e->getRequest()->getMethod() . ' - ' . $e->getMessage(), "INVALID_START_TRANSACTION"); 224 | } 225 | )->wait(); 226 | } catch (\Throwable $e) { 227 | $this->_close(); 228 | // If execution fails, throw a LibsqlError 229 | throw new LibsqlError($e->getMessage(), "BATCH_TRANSACTION_TERMINATED"); 230 | } 231 | } 232 | 233 | /** 234 | * Execute multiple SQL statements in sequence. 235 | * This method follow @link [Hrana Over HTTP - Sequence](https://github.com/tursodatabase/libsql/blob/main/docs/HRANA_3_SPEC.md#execute-a-sequence-of-sql-statements-1) 236 | * 237 | * @param string $sql The SQL statements to execute. 238 | * 239 | * @return string 240 | * 241 | * @throws LibsqlError If execution fails. 242 | */ 243 | public function executeMultiple(string $sql): string 244 | { 245 | try { 246 | $payload = $this->_createSequenceRequest(\str_replace(["\r", "\n", "\r\n"], '', $sql)); 247 | $response = $this->http->post(LibSQL::PIPE_LINE_ENDPOINT, [ 248 | 'json' => $this->_makeRequest($payload) 249 | ]); 250 | return $response->getBody(); 251 | } catch (\Throwable $e) { 252 | $this->_close(); 253 | // If execution fails, throw a LibsqlError 254 | throw new LibsqlError($e->getMessage(), "MULTIPLE_EXEC_ERROR"); 255 | } 256 | } 257 | 258 | /** 259 | * Start a transaction with the specified mode. 260 | * 261 | * @param string $mode (Optional) The transaction mode read, write, and deferred. Default is 'write'. 262 | * 263 | * @return self The current instance of HttpClient. 264 | * 265 | * @throws LibsqlError If there is an error starting the transaction. 266 | */ 267 | public function transaction(string $mode = 'write'): HttpTransaction 268 | { 269 | TransactionMode::checker($mode); 270 | return new HttpTransaction($mode); 271 | } 272 | 273 | /** 274 | * Close the HTTP client connection. 275 | */ 276 | public function close(): void 277 | { 278 | $this->runQuery($this->_makeRequest($this->_close())); 279 | } 280 | 281 | public function version(): string 282 | { 283 | $response = $this->http->get(LibSQL::VERSION_ENDPOINT); 284 | return $response->getBody(); 285 | } 286 | 287 | /** 288 | * Run an HTTP query with the provided payload. 289 | * 290 | * @param array $payload The payload for the HTTP query. 291 | * @param bool $trace (Optional) Whether to return the raw response without mapping results. Default is false. 292 | * 293 | * @return HttpResponse|ResponseInterface The HTTP response containing the results of the query, or the raw response if trace is true. 294 | */ 295 | protected function runQuery(array $payload, bool $trace = false): HttpResponse|ResponseInterface 296 | { 297 | $response = $this->http->post(LibSQL::PIPE_LINE_ENDPOINT, [ 298 | 'json' => $payload 299 | ]); 300 | 301 | if ($trace === false) { 302 | $data = map_results($response->getBody()); 303 | return HttpResponse::create($data['baton'], $data['base_url'], $data['results']); 304 | } 305 | 306 | return $response; 307 | } 308 | 309 | /** 310 | * Create a payload for making a request. 311 | * 312 | * @param array $data The data to include in the payload. 313 | * @param bool $close (Optional) Whether to include a close request. Default is true. 314 | * @param string $baton (Optional) The baton string. 315 | * 316 | * @return array The payload for the request. 317 | */ 318 | protected function _makeRequest(array $data, bool $close = true, string $baton = ''): array 319 | { 320 | // Initialize the payload with the "requests" key 321 | $payload = [ 322 | 'requests' => \sizeof($data) >= 3 ? $data : [$data] 323 | ]; 324 | 325 | // Add the close request if needed 326 | if ($close) { 327 | $payload['requests'][] = $this->_close(); 328 | } 329 | 330 | // Add the baton if provided 331 | if (!empty($baton)) { 332 | $payload["baton"] = $baton; 333 | } 334 | 335 | return $payload; 336 | } 337 | 338 | /** 339 | * Create a request array for closing the connection. 340 | * 341 | * @return array The request array for closing the connection. 342 | */ 343 | protected function _close(): array 344 | { 345 | return ["type" => LibSQL::LIBSQL_CLOSE]; 346 | } 347 | 348 | /** 349 | * Create a request array for execution with the provided SQL statement and arguments. 350 | * 351 | * @param string $type The type statement to execute. 352 | * @param string $sql The SQL statement to execute. 353 | * @param array|null $args (Optional) The arguments for the SQL statement. 354 | * @param bool|null $named_args (Optional) Whether the arguments are named or positional. 355 | * 356 | * @return array The request array for execution. 357 | */ 358 | protected function _createRequest( 359 | string $type = LibSQL::LIBSQL_EXECUTE, 360 | string $sql, 361 | ?array $args = [], 362 | ?bool $named_args = false 363 | ): array { 364 | // Initialize the execute request array 365 | $executeRequest = [ 366 | "type" => $type, 367 | "stmt" => [ 368 | "sql" => $sql 369 | ] 370 | ]; 371 | 372 | // Determine if arguments are positional or named and set accordingly 373 | if ($named_args === false && !empty($args)) { 374 | $executeRequest["stmt"]["args"] = $this->_argumentsGenerator($args); 375 | } 376 | 377 | if ($named_args === true) { 378 | $executeRequest["stmt"]["named_args"] = $this->_namedArgumentsGenerator($args); 379 | } 380 | 381 | return $executeRequest; 382 | } 383 | 384 | protected function _createSequenceRequest( 385 | string $sql, 386 | int|null $sql_id = null 387 | ): array { 388 | // Initialize the execute request array 389 | $executeRequest = [ 390 | "type" => LibSQL::LIBSQL_SEQUENCE, 391 | "sql" => $sql 392 | ]; 393 | 394 | if (!empty($sql_id)) { 395 | $executeRequest['sql_id'] = $sql_id; 396 | } 397 | 398 | return $executeRequest; 399 | } 400 | 401 | /** 402 | * Generate arguments array for the HTTP request payload. 403 | * 404 | * @param mixed $args The arguments to be processed. 405 | * 406 | * @return array The generated arguments array. 407 | * @throws LibsqlError If an invalid argument type is encountered. 408 | */ 409 | protected function _argumentsGenerator($args): array 410 | { 411 | $argsArray = []; 412 | 413 | // Iterate through each argument and generate the appropriate representation 414 | foreach ($args as $arg) { 415 | $type = $this->_typeParser($arg); 416 | 417 | // Handle special cases for certain argument types 418 | if ($type === 'blob') { 419 | $arg = \base64_encode($arg); 420 | } else if ($type === 'float') { 421 | // Convert argument to float if it's of type 'float' 422 | \settype($arg, 'float'); 423 | } else if ($type === 'integer') { 424 | // Ensure integer values are represented as strings 425 | $arg = "$arg"; 426 | } 427 | 428 | // Add argument to the array with its type and value 429 | $argsArray[] = [ 430 | "type" => $type, 431 | "value" => $arg 432 | ]; 433 | } 434 | 435 | return $argsArray; 436 | } 437 | 438 | /** 439 | * Generate named arguments array for the HTTP request payload. 440 | * 441 | * @param array $args The named arguments to be processed. 442 | * 443 | * @return array The generated named arguments array. 444 | * @throws LibsqlError If an invalid argument type is encountered. 445 | */ 446 | protected function _namedArgumentsGenerator(array $args): array 447 | { 448 | $argsArray = []; 449 | 450 | // Iterate through each named argument and generate the appropriate representation 451 | foreach ($args as $name => $value) { 452 | $type = $this->_typeParser($value); 453 | 454 | // Handle special cases for certain argument types 455 | if ($type === 'blob') { 456 | $value = \base64_encode($value); 457 | } else if ($type === 'float') { 458 | // Convert argument to float if it's of type 'float' 459 | \settype($value, 'float'); 460 | } else if ($type === 'integer') { 461 | // Ensure integer values are represented as strings 462 | $value = "$value"; 463 | } 464 | 465 | // Add named argument to the array with its name, type, and value 466 | $argsArray[] = [ 467 | "name" => $name, 468 | "value" => [ 469 | "type" => $type, 470 | "value" => $value 471 | ] 472 | ]; 473 | } 474 | 475 | return $argsArray; 476 | } 477 | 478 | /** 479 | * Parse the type of the value. 480 | * 481 | * @param mixed $value The value to determine the type for. 482 | * 483 | * @return string The type of the value. 484 | * @throws LibsqlError If the type of the value cannot be determined or is invalid. 485 | */ 486 | protected function _typeParser(mixed $value): string 487 | { 488 | // Check the type of the value using the provided function 489 | $type = Mods::checkColumnType($value); 490 | 491 | // Throw an error if the type is unknown 492 | if ($type === 'unknown') { 493 | throw new LibsqlError( 494 | "Invalid arguments types. The type field within each arg corresponds to the column datatype and can be one of the following: null, integer, float, text, or blob.", 495 | "INVALID_TYPE_ARGUMENT" 496 | ); 497 | } 498 | 499 | return $type; 500 | } 501 | } 502 | -------------------------------------------------------------------------------- /src/Providers/LocalClient.php: -------------------------------------------------------------------------------- 1 | path = $path; 52 | $this->flags = $flags; 53 | $this->encryptionKey = $encryptionKey; 54 | $this->db = new LibSQLPHP($this->path, $this->flags, $this->encryptionKey); 55 | } 56 | 57 | /** 58 | * Establishes a connection to the local LibSQL database. 59 | * 60 | * @return bool True if the connection is successful, false otherwise. 61 | */ 62 | public function connect(): bool 63 | { 64 | return $this->db->is_connected(); 65 | } 66 | 67 | /** 68 | * Executes an SQL query on the local database. 69 | * 70 | * @param string $sql The SQL query to execute. 71 | * @param array $params Optional parameters to bind to the query. 72 | * @return LibSQLPHPClientResult The result of the query execution. 73 | */ 74 | public function execute(string $sql, array $params = []): LibSQLPHPClientResult 75 | { 76 | return $this->db->client_exec($sql, $params); 77 | } 78 | 79 | /** 80 | * Executes a batch of SQL queries on the local database. 81 | * 82 | * @param string $sql The batch of SQL queries to execute. 83 | * @return void 84 | */ 85 | public function batch(string $sql): void 86 | { 87 | $this->db->execute_batch($sql); 88 | } 89 | 90 | /** 91 | * Initiates a transaction on the local database. 92 | * 93 | * @param string $mode The transaction mode: 'write', 'read', or 'deferred'. 94 | * @return Transaction The transaction object representing the initiated transaction. 95 | */ 96 | public function transaction(string $mode): Transaction 97 | { 98 | switch ($mode) { 99 | case 'write': 100 | $mode = TransactionBehavior::Immediate; 101 | break; 102 | case 'read': 103 | $mode = TransactionBehavior::ReadOnly; 104 | break; 105 | case 'deferred': 106 | $mode = TransactionBehavior::Deferred; 107 | break; 108 | } 109 | 110 | return $this->db->transaction($mode); 111 | } 112 | 113 | /** 114 | * Closes the connection to the local LibSQL database. 115 | * 116 | * @return void 117 | */ 118 | public function close(): void 119 | { 120 | $this->db->close(); 121 | } 122 | 123 | /** 124 | * Retrieves the version of the local LibSQL database. 125 | * 126 | * @return string The version of the local LibSQL database. 127 | * @throws LibsqlError If an error occurs while retrieving the version. 128 | */ 129 | public function version(): string 130 | { 131 | try { 132 | return $this->db->version(); 133 | } catch (\Exception $e) { 134 | throw new LibsqlError($e->getMessage(), "ERR_GET_VERSION"); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Providers/RemoteReplicaClient.php: -------------------------------------------------------------------------------- 1 | path = $path; 37 | $this->authToken = $authToken; 38 | $this->syncUrl = $syncUrl; 39 | $this->syncInterval = $syncInterval; 40 | $this->read_your_writes = $read_your_writes; 41 | $this->db = new LibSQLPHP( 42 | path: $this->path, 43 | url: $this->syncUrl, 44 | token: $this->authToken, 45 | sync_interval: $this->syncInterval, 46 | read_your_writes: $this->read_your_writes 47 | ); 48 | } 49 | 50 | /** 51 | * Checks if the client is connected to the remote replica database. 52 | * 53 | * @return bool True if connected, false otherwise. 54 | */ 55 | public function connect(): bool 56 | { 57 | return $this->db->is_connected(); 58 | } 59 | 60 | /** 61 | * Executes a SQL query on the remote replica database. 62 | * 63 | * @param string $sql The SQL query to execute. 64 | * @param array $params The parameters for the SQL query. 65 | * @return LibSQLPHPClientResult The result of the query execution. 66 | */ 67 | public function execute(string $sql, array $params = []): LibSQLPHPClientResult 68 | { 69 | return $this->db->client_exec($sql, $params); 70 | } 71 | 72 | /** 73 | * Executes a batch of SQL queries on the remote replica database. 74 | * 75 | * @param string $sql The batch of SQL queries to execute. 76 | * @return void 77 | */ 78 | public function batch(string $sql): void 79 | { 80 | $this->db->execute_batch($sql); 81 | } 82 | 83 | /** 84 | * Starts a transaction on the remote replica database. 85 | * 86 | * @param string $mode The mode of the transaction ('write', 'read', or 'deferred'). 87 | * @return Transaction The transaction object. 88 | */ 89 | public function transaction(string $mode): Transaction 90 | { 91 | switch ($mode) { 92 | case 'write': 93 | $mode = TransactionBehavior::Immediate; 94 | break; 95 | case 'read': 96 | $mode = TransactionBehavior::ReadOnly; 97 | break; 98 | case 'deferred': 99 | $mode = TransactionBehavior::Deferred; 100 | break; 101 | } 102 | 103 | return $this->db->transaction($mode); 104 | } 105 | 106 | /** 107 | * Closes the connection to the remote replica database. 108 | * 109 | * @return void 110 | */ 111 | public function close(): void 112 | { 113 | $this->db->close(); 114 | } 115 | 116 | /** 117 | * Syncs data with the remote replica database. 118 | * 119 | * @return int The result of the sync operation (0 for success, non-zero for failure). 120 | */ 121 | public function sync(): int 122 | { 123 | $exec = $this->db->sync(); 124 | return $exec === 0; 125 | } 126 | 127 | /** 128 | * Retrieves the version of the remote replica database. 129 | * 130 | * @return string The version of the remote replica database. 131 | * 132 | * @throws LibsqlError If an error occurs while retrieving the version. 133 | */ 134 | public function version(): string 135 | { 136 | try { 137 | return $this->db->version(); 138 | } catch (\Exception $e) { 139 | throw new LibsqlError($e->getMessage(), "ERR_GET_VERSION"); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Traits/Logging.php: -------------------------------------------------------------------------------- 1 | checkAndCreateDirectoryAndFile(); 22 | $logMessage = '[' . date('Y-m-d H:i:s') . '] ' . $message . PHP_EOL; 23 | file_put_contents($filePath, $logMessage, FILE_APPEND); 24 | } 25 | 26 | /** 27 | * Check and create the directory and error log file if they don't exist. 28 | * 29 | * @return string The path to the error log file. 30 | */ 31 | protected function checkAndCreateDirectoryAndFile(): string 32 | { 33 | $homeDirectory = getenv('HOME'); 34 | $directoryPath = $homeDirectory . '/.libsql-php'; 35 | $filePath = $directoryPath . '/errors.log'; 36 | 37 | if (!file_exists($directoryPath)) { 38 | mkdir($directoryPath, 0777, true); 39 | } 40 | 41 | if (!file_exists($filePath)) { 42 | touch($filePath); 43 | } 44 | 45 | return $filePath; 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/Traits/MapResults.php: -------------------------------------------------------------------------------- 1 | _results($data); 24 | } 25 | 26 | /** 27 | * Fetch the results as a JSON object. 28 | * 29 | * @param string|array|HttpResultSets $data The JSON data containing the results. 30 | * 31 | * @return string The results mapped as a JSON object. 32 | */ 33 | protected function fetchObject(string|array|HttpResultSets $data): string 34 | { 35 | return \json_encode($this->_results($data), \JSON_PRETTY_PRINT); 36 | } 37 | 38 | /** 39 | * Parse the JSON data and extract the results. 40 | * 41 | * @param string|array|HttpResultSets $data The JSON data containing the results. 42 | * 43 | * @return array The extracted results. 44 | */ 45 | private function _results(string|array|HttpResultSets $data): array 46 | { 47 | $result = []; 48 | 49 | if (\is_string($data)) { 50 | $data = json_decode($data, true); 51 | } 52 | 53 | if (\is_array($data)) { 54 | 55 | foreach ($data as $dataTable) { 56 | if (isset($dataTable['rows']) && isset($dataTable['cols'])) { 57 | foreach ($dataTable['rows'] as $row) { 58 | $rowData = []; 59 | $cols = $dataTable['cols']; 60 | 61 | for ($i = 0; $i < count($cols); $i++) { 62 | switch ($row[$i]['type']) { 63 | case 'text': 64 | $value = (string) $row[$i]['value']; 65 | break; 66 | case 'integer': 67 | $value = (int) $row[$i]['value']; 68 | break; 69 | case 'float': 70 | $value = (float) $row[$i]['value']; 71 | break; 72 | case 'null': 73 | $value = null; 74 | break; 75 | } 76 | 77 | $colName = $cols[$i]['name']; 78 | $colValue = $value; 79 | $rowData[$colName] = $colValue; 80 | } 81 | 82 | $result[] = $rowData; 83 | } 84 | } 85 | } 86 | } 87 | 88 | // Iterate over each row 89 | if (isset($data['results'][0]['response']['result']['rows'])) { 90 | foreach ($data['results'][0]['response']['result']['rows'] as $row) { 91 | $rowData = []; 92 | $cols = $data['results'][0]['response']['result']['cols']; 93 | 94 | // Iterate over each column 95 | for ($i = 0; $i < count($cols); $i++) { 96 | switch ($row[$i]['type']) { 97 | case 'text': 98 | $value = (string) $row[$i]['value']; 99 | break; 100 | case 'integer': 101 | $value = (int) $row[$i]['value']; 102 | break; 103 | case 'float': 104 | $value = (float) $row[$i]['value']; 105 | break; 106 | case 'null': 107 | $value = null; 108 | break; 109 | default: 110 | $value = (string) $row[$i]['value']; 111 | break; 112 | } 113 | 114 | $colName = $cols[$i]['name']; 115 | $colValue = $value; 116 | $rowData[$colName] = $colValue; 117 | } 118 | 119 | // Use 'name' column as key and 'value' column as value 120 | $result[] = $rowData; 121 | } 122 | } 123 | 124 | return $result; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Types/Authority.php: -------------------------------------------------------------------------------- 1 | host = $host; 18 | $this->port = $port; 19 | $this->userInfo = $userInfo; 20 | } 21 | 22 | public static function create( 23 | string $host, 24 | ?int $port, 25 | ?UserInfo $userInfo 26 | ): self 27 | { 28 | return new self($host, $port, $userInfo); 29 | } 30 | 31 | /** 32 | * Convert the Authority object to an array. 33 | * 34 | * @return array An array representation of the Authority object. 35 | */ 36 | public function toArray(): array 37 | { 38 | return [ 39 | 'host' => $this->host, 40 | 'port' => !empty($this->port) ? $this->port : null, 41 | 'userInfo' => !empty($this->userInfo) ? $this->userInfo->toArray() : null 42 | ]; 43 | } 44 | 45 | /** 46 | * Converts the HttpResponse instance to a JSON string. 47 | * 48 | * @return string The JSON representation of the HttpResponse instance. 49 | */ 50 | public function toObject(): string 51 | { 52 | return \json_encode($this->toArray()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Types/Config.php: -------------------------------------------------------------------------------- 1 | url = $url; 33 | $this->authToken = $authToken; 34 | $this->encryptionKey = $encryptionKey; 35 | $this->syncUrl = $syncUrl; 36 | $this->syncInterval = $syncInterval; 37 | $this->tls = $tls; 38 | } 39 | 40 | public static function create( 41 | string $url, 42 | ?string $authToken = null, 43 | ?string $encryptionKey = null, 44 | ?string $syncUrl = null, 45 | ?int $syncInterval = null, 46 | ?bool $tls = null 47 | ): self { 48 | return new self( 49 | $url, 50 | $authToken, 51 | $encryptionKey, 52 | $syncUrl, 53 | $syncInterval, 54 | $tls 55 | ); 56 | } 57 | 58 | /** 59 | * Convert the Config to an array. 60 | * @return array The Config properties as an array. 61 | */ 62 | public function toArray(): array 63 | { 64 | return [ 65 | 'url' => $this->url, 66 | 'authToken' => $this->authToken, 67 | 'encryptionKey' => $this->encryptionKey, 68 | 'syncUrl' => $this->syncUrl, 69 | 'syncInterval' => $this->syncInterval, 70 | 'tls' => $this->tls, 71 | ]; 72 | } 73 | 74 | /** 75 | * Converts the HttpResponse instance to a JSON string. 76 | * 77 | * @return string The JSON representation of the HttpResponse instance. 78 | */ 79 | public function toObject(): string 80 | { 81 | return \json_encode($this->toArray()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Types/ExpandedConfig.php: -------------------------------------------------------------------------------- 1 | scheme = $scheme; 27 | $this->flags = $flags; 28 | $this->encryptionKey = $encryptionKey; 29 | $this->tls = $tls; 30 | $this->authority = $authority; 31 | $this->path = $path; 32 | $this->authToken = $authToken; 33 | $this->syncUrl = $syncUrl; 34 | $this->syncInterval = $syncInterval; 35 | $this->read_your_writes = $read_your_writes; 36 | } 37 | 38 | public static function create( 39 | string $scheme, 40 | ?int $flags, 41 | ?string $encryptionKey = "", 42 | ?bool $tls = false, 43 | ?Authority $authority, 44 | ?string $path, 45 | ?string $authToken = null, 46 | ?string $syncUrl = null, 47 | ?int $syncInterval = null, 48 | ?bool $read_your_writes = true 49 | ): self { 50 | return new self( 51 | $scheme, 52 | $flags, 53 | $encryptionKey, 54 | $tls, 55 | $authority, 56 | $path, 57 | $authToken, 58 | $syncUrl, 59 | $syncInterval, 60 | $read_your_writes 61 | ); 62 | } 63 | 64 | /** 65 | * Convert the ExpandedConfig object to an array. 66 | * 67 | * @return array An array representation of the ExpandedConfig object. 68 | */ 69 | public function toArray(): array 70 | { 71 | return [ 72 | 'scheme' => $this->scheme, 73 | 'flags' => $this->flags, 74 | 'encryptionKey' => $this->encryptionKey, 75 | 'tls' => $this->tls, 76 | 'authority' => $this->authority ? $this->authority->toArray() : null, 77 | 'path' => $this->path, 78 | 'authToken' => $this->authToken, 79 | 'syncUrl' => $this->syncUrl, 80 | 'syncInterval' => $this->syncInterval, 81 | 'read_your_writes' => $this->read_your_writes, 82 | ]; 83 | } 84 | 85 | /** 86 | * Converts the ExpandedConfig instance to a JSON string. 87 | * 88 | * @return string The JSON representation of the ExpandedConfig instance. 89 | */ 90 | public function toObject(): string 91 | { 92 | return \json_encode($this->toArray()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Types/ExpandedScheme.php: -------------------------------------------------------------------------------- 1 | authority = $authority; 17 | $this->path = $path; 18 | } 19 | 20 | public static function create( 21 | ?Authority $authority, 22 | string $path 23 | ): self 24 | { 25 | return new self($authority, $path); 26 | } 27 | 28 | /** 29 | * Convert the HierPart object to an array. 30 | * 31 | * @return array An array representation of the HierPart object. 32 | */ 33 | public function toArray(): array 34 | { 35 | return [ 36 | 'authority' => !empty($this->authority) ? $this->authority->toArray() : null, 37 | 'path' => $this->path 38 | ]; 39 | } 40 | 41 | /** 42 | * Converts the HierPart instance to a JSON string. 43 | * 44 | * @return string The JSON representation of the HierPart instance. 45 | */ 46 | public function toObject(): string 47 | { 48 | return \json_encode($this->toArray()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Types/HttpResponse.php: -------------------------------------------------------------------------------- 1 | baton = $baton; 28 | $this->base_url = $base_url; 29 | $this->results = $results; 30 | } 31 | 32 | /** 33 | * Creates a new HttpResponse instance. 34 | * 35 | * This method creates a new instance of the HttpResponse class. 36 | * 37 | * @param string|null $baton The baton identifier. 38 | * @param string|null $base_url The base URL for the HTTP response. 39 | * @param array|HttpResultSets $results The HTTP result sets. 40 | * @return self The created HttpResponse instance. 41 | */ 42 | public static function create( 43 | string|null $baton, 44 | string|null $base_url, 45 | array|HttpResultSets $results 46 | ): self { 47 | return new self($baton, $base_url, $results); 48 | } 49 | 50 | 51 | /** 52 | * Convert the result set to an associative array. 53 | * 54 | * This method converts the result set to an associative array representation. 55 | * It includes the baton, base URL, and the results converted to an array using the `objectToArray()` function. 56 | * 57 | * @return array An associative array representation of the result set containing baton, base URL, and results. 58 | */ 59 | public function toArray(): array 60 | { 61 | return [ 62 | 'baton' => $this->baton, 63 | 'base_url' => $this->base_url, 64 | 'results' => \objectToArray($this->results) 65 | ]; 66 | } 67 | 68 | 69 | /** 70 | * Convert the result set to a JSON-encoded string. 71 | * 72 | * This method converts the result set to a JSON-encoded string representation. 73 | * It internally uses the `toArray()` method to convert the result set to an associative array 74 | * before encoding it as JSON. 75 | * 76 | * @return string The JSON-encoded string representation of the result set. 77 | */ 78 | public function toObject(): string 79 | { 80 | return \json_encode($this->toArray()); 81 | } 82 | 83 | 84 | /** 85 | * Retrieve the first result set from the query execution. 86 | * 87 | * This method returns a new instance of the current class containing the first result set 88 | * obtained from the executed query. It converts the internal result object to an array and 89 | * extracts the first element to create a new instance. 90 | * 91 | * @return self A new instance of the current class containing the first result set. 92 | */ 93 | public function first(): self 94 | { 95 | $data = \objectToArray($this->results); 96 | $result = \current($data); 97 | return new self( 98 | $this->baton, 99 | $this->base_url, 100 | HttpResultSets::create( 101 | $result['cols'], 102 | $result['rows'], 103 | $result['affected_row_count'], 104 | $result['last_insert_rowid'], 105 | $result['replication_index'] 106 | ) 107 | ); 108 | } 109 | 110 | /** 111 | * Fetch the result set from the query execution. 112 | * 113 | * This method retrieves the result set from the executed query and returns it in the specified format. 114 | * It converts the internal result object to an array and switches based on the provided type parameter 115 | * to determine the format of the returned data. 116 | * 117 | * @param int $type The type of fetch operation. Default is LibSQLResult::FETCH_ASSOC. 118 | * @return array|string The result set in the specified format. 119 | * @throws LibsqlError When an undefined fetch option is provided. 120 | */ 121 | public function fetch(int $type = LibSQLResult::FETCH_ASSOC): array|string 122 | { 123 | $results = objectToArray($this->results); 124 | switch ($type) { 125 | case LibSQLResult::FETCH_ASSOC: 126 | return $this->fetchArray($results); 127 | break; 128 | case LibSQLResult::FETCH_OBJ: 129 | return $this->fetchObject($results); 130 | break; 131 | default: 132 | throw new LibsqlError("Error Undefined fetch options", "UNDEFINED_FETCH_OPTIONS"); 133 | break; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/Types/HttpResultSets.php: -------------------------------------------------------------------------------- 1 | cols = $cols; 52 | $this->rows = $rows; 53 | $this->affected_row_count = $affected_row_count; 54 | $this->last_insert_rowid = $last_insert_rowid; 55 | $this->replication_index = $replication_index; 56 | } 57 | 58 | /** 59 | * Creates a new HttpResultSets instance. 60 | * 61 | * @param array $cols The columns of the result set. 62 | * @param array $rows The rows of the result set. 63 | * @param int $affected_row_count The number of affected rows. 64 | * @param int $last_insert_rowid The last inserted row ID. 65 | * @param int $replication_index The replication index. 66 | * @return self The created HttpResultSets instance. 67 | */ 68 | public static function create( 69 | array $cols, 70 | array $rows, 71 | int $affected_row_count, 72 | int|null $last_insert_rowid, 73 | int|string $replication_index 74 | ): self { 75 | return new self($cols, $rows, $affected_row_count, $last_insert_rowid, $replication_index); 76 | } 77 | 78 | /** 79 | * Converts the HttpResultSets instance to an array. 80 | * 81 | * @return array The array representation of the HttpResultSets instance. 82 | */ 83 | public function toArray(): array 84 | { 85 | return [ 86 | 'cols' => $this->cols, 87 | 'rows' => $this->rows, 88 | 'affected_row_count' => $this->affected_row_count, 89 | 'last_insert_rowid' => $this->last_insert_rowid, 90 | 'replication_index' => $this->replication_index, 91 | ]; 92 | } 93 | 94 | /** 95 | * Converts the HttpResultSets instance to a JSON string. 96 | * 97 | * @return string The JSON representation of the HttpResultSets instance. 98 | */ 99 | public function toObject(): string 100 | { 101 | return \json_encode($this->toArray()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Types/HttpStatement.php: -------------------------------------------------------------------------------- 1 | sql = $sql; 22 | $this->args = $args; 23 | $this->named_args = $named_args; 24 | } 25 | 26 | /** 27 | * Creates a new HttpStatement instance. 28 | * 29 | * **Example Usage** 30 | * 31 | * ``` 32 | * $query = HttpStatement::create(sql: 'SELECT name, id FROM users LIMIT 5'); 33 | * 34 | * // or 35 | * 36 | * $stmts = [ 37 | * HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Ramons", 32]), 38 | * HttpStatement::create(sql: 'INSERT INTO users (name, age) VALUES (?, ?)', args: ["Georgia", 43]) 39 | * ]; 40 | * ``` 41 | * 42 | * @param string $sql The SQL statement. 43 | * @param array|null $args The optional arguments for the SQL statement. 44 | * @return self The created HttpStatement instance. 45 | */ 46 | public static function create( 47 | string $sql, 48 | ?array $args = [], 49 | ?bool $named_args = false 50 | ): self { 51 | return new self($sql, $args, $named_args); 52 | } 53 | 54 | /** 55 | * Converts the HttpStatement instance to an array. 56 | * 57 | * @return array The array representation of the HttpStatement instance. 58 | */ 59 | public function toArray(): array 60 | { 61 | return [ 62 | 'sql' => $this->sql, 63 | 'args' => $this->args, 64 | 'named_args' => $this->named_args 65 | ]; 66 | } 67 | 68 | /** 69 | * Converts the HttpStatement instance to a JSON string. 70 | * 71 | * @return string The JSON representation of the HttpStatement instance. 72 | */ 73 | public function toObject(): string 74 | { 75 | return \json_encode($this->toArray()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Types/HttpTransaction.php: -------------------------------------------------------------------------------- 1 | _createRequest(LibSQL::LIBSQL_EXECUTE, Mods::transactionModeToBegin($mode)); 16 | $response = $this->runQuery($this->_makeRequest($request, false), true); 17 | $data = map_results($response->getBody()); 18 | $this->baton = $data['baton']; 19 | return $this; 20 | } 21 | 22 | /** 23 | * Add a transaction to the transaction batch. 24 | * 25 | * @param HttpStatement $query The HTTP statement to add to the transaction. 26 | * 27 | * @return self The current instance of HttpClient. 28 | */ 29 | public function addTransaction(HttpStatement $query): self 30 | { 31 | \array_push($this->collectors, $this->_createRequest(LibSQL::LIBSQL_EXECUTE, $query->sql, $query->args, $query->named_args)); 32 | return $this; 33 | } 34 | 35 | /** 36 | * End the current transaction batch and commit the transactions. 37 | * 38 | * @return HttpResponse The HTTP response containing the results of the transaction batch. 39 | */ 40 | public function endTransaction(): HttpResponse 41 | { 42 | \array_push($this->collectors, $this->_rawCommit()); 43 | $response = $this->runQuery($this->_makeRequest($this->collectors, true, $this->baton), true); 44 | $data = map_results($response->getBody()); 45 | return HttpResponse::create($data['baton'], $data['base_url'], $data['results']); 46 | } 47 | 48 | /** 49 | * Rollback the current transaction. 50 | */ 51 | public function rollback(): void 52 | { 53 | $this->runQuery($this->_makeRequest($this->_createRequest(LibSQL::LIBSQL_EXECUTE, 'ROLLBACK'), true, $this->baton)); 54 | } 55 | 56 | protected function _rawRollback(): array 57 | { 58 | return $this->_createRequest(LibSQL::LIBSQL_EXECUTE, 'ROLLBACK'); 59 | } 60 | 61 | /** 62 | * Commit the current transaction. 63 | */ 64 | public function commit(): void 65 | { 66 | $this->runQuery($this->_makeRequest($this->_createRequest(LibSQL::LIBSQL_EXECUTE, 'COMMIT'), true, $this->baton)); 67 | } 68 | 69 | protected function _rawCommit(): array 70 | { 71 | return $this->_createRequest(LibSQL::LIBSQL_EXECUTE, 'COMMIT'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Types/KeyValue.php: -------------------------------------------------------------------------------- 1 | key = $key; 17 | $this->value = $value; 18 | } 19 | 20 | public static function create( 21 | string $key, 22 | string $value 23 | ): self 24 | { 25 | return new self($key, $value); 26 | } 27 | 28 | /** 29 | * Convert the KeyValue object to an array. 30 | * 31 | * @return array An array representation of the KeyValue object. 32 | */ 33 | public function toArray(): array 34 | { 35 | return [ 36 | 'key' => $this->key, 37 | 'value' => $this->value, 38 | ]; 39 | } 40 | 41 | /** 42 | * Converts the KeyValue instance to a JSON string. 43 | * 44 | * @return string The JSON representation of the KeyValue instance. 45 | */ 46 | public function toObject(): string 47 | { 48 | return \json_encode($this->toArray()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Types/LibSQLResult.php: -------------------------------------------------------------------------------- 1 | pairs = $pairs; 15 | } 16 | 17 | public static function create(array $pairs): self 18 | { 19 | return new self($pairs); 20 | } 21 | 22 | /** 23 | * Convert the Query object to an array. 24 | * 25 | * @return array An array representation of the Query object. 26 | */ 27 | public function toArray(): array 28 | { 29 | return ['pairs' => $this->pairs]; 30 | } 31 | 32 | /** 33 | * Converts the Query instance to a JSON string. 34 | * 35 | * @return string The JSON representation of the Query instance. 36 | */ 37 | public function toObject(): string 38 | { 39 | return \json_encode($this->toArray()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Types/TransactionMode.php: -------------------------------------------------------------------------------- 1 | getConstants(); 25 | if (!in_array($mode, $constants)) { 26 | throw new LibsqlError("Transaction mode is not supported. The only avaibale mode is: write, read, and deferred", "INVALID_TRANSACTION_MODE"); 27 | } 28 | 29 | return $mode; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Types/Uri.php: -------------------------------------------------------------------------------- 1 | scheme = $scheme; 20 | $this->authority = $authority; 21 | $this->path = $path; 22 | $this->query = $query; 23 | $this->fragment = $fragment; 24 | } 25 | 26 | public static function create( 27 | string $scheme, 28 | ?Authority $authority = null, 29 | string $path = '', 30 | ?Query $query = null, 31 | ?string $fragment = '' 32 | ): self 33 | { 34 | return new self( 35 | $scheme, 36 | $authority, 37 | $path, 38 | $query, 39 | $fragment 40 | ); 41 | } 42 | 43 | /** 44 | * Convert the Uri object to an array. 45 | * 46 | * @return array An array representation of the Uri object. 47 | */ 48 | public function toArray(): array 49 | { 50 | return [ 51 | 'scheme' => $this->scheme, 52 | 'authority' => !empty($this->authority) ? $this->authority->toArray() : null, 53 | 'path' => $this->path, 54 | 'query' => !empty($this->query) ? $this->query->toArray() : null, 55 | 'fragment' => $this->fragment 56 | ]; 57 | } 58 | 59 | /** 60 | * Converts the Uri instance to a JSON string. 61 | * 62 | * @return string The JSON representation of the Uri instance. 63 | */ 64 | public function toObject(): string 65 | { 66 | return \json_encode($this->toArray()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Types/UserInfo.php: -------------------------------------------------------------------------------- 1 | username = $username; 17 | $this->password = $password; 18 | } 19 | 20 | public static function create( 21 | string|null $username, 22 | ?string $password = '' 23 | ): self 24 | { 25 | return new self($username, $password); 26 | } 27 | 28 | /** 29 | * Convert the UserInfo object to an array. 30 | * 31 | * @return array An array representation of the UserInfo object. 32 | */ 33 | public function toArray(): array 34 | { 35 | return [ 36 | 'username' => $this->username, 37 | 'password' => !empty($this->password) ? $this->password : null 38 | ]; 39 | } 40 | 41 | /** 42 | * Converts the UserInfo instance to a JSON string. 43 | * 44 | * @return string The JSON representation of the UserInfo instance. 45 | */ 46 | public function toObject(): string 47 | { 48 | return \json_encode($this->toArray()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Utils/Exceptions/LibsqlError.php: -------------------------------------------------------------------------------- 1 | log($message); 33 | parent::__construct($message, 0, $cause); 34 | $this->code = $code; 35 | $this->rawCode = $rawCode; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Utils/Mods.php: -------------------------------------------------------------------------------- 1 | query->pairs)) { 102 | foreach ($uri->query->pairs as $pair) { 103 | $key = $pair->key; 104 | $value = $pair->value; 105 | if ($key === 'authToken') { 106 | $authToken = $value !== '' ? $value : null; 107 | } elseif ($key === 'tls') { 108 | // Parse the 'tls' parameter 109 | if ($value === '0') { 110 | $tls = false; 111 | } elseif ($value === '1') { 112 | $tls = true; 113 | } else { 114 | throw new LibsqlError('Unknown value for the "tls" query argument: ' . json_encode($value) . '. Supported values are "0" and "1"', "URL_INVALID"); 115 | } 116 | } else { 117 | throw new LibsqlError('Unknown URL query parameter ' . json_encode($key), "URL_PARAM_NOT_SUPPORTED"); 118 | } 119 | } 120 | } 121 | 122 | // Determine the scheme 123 | $uriScheme = strtolower($uri->scheme); 124 | if ($uriScheme === 'libsql') { 125 | // Handle 'libsql' scheme 126 | if ($tls === false) { 127 | if ($uri->authority->port === null) { 128 | throw new LibsqlError('A "libsql:" URL with ?tls=0 must specify an explicit port', "URL_INVALID"); 129 | } 130 | $scheme = $preferHttp ? ExpandedScheme::http : ExpandedScheme::ws; 131 | } else { 132 | $scheme = $preferHttp ? ExpandedScheme::https : ExpandedScheme::wss; 133 | } 134 | } elseif (in_array($uriScheme, [ExpandedScheme::http, ExpandedScheme::ws])) { 135 | // Handle HTTP and WebSocket schemes 136 | $scheme = $uriScheme; 137 | $tls ??= false; 138 | } elseif (in_array($uriScheme, [ExpandedScheme::https, ExpandedScheme::wss, ExpandedScheme::file])) { 139 | // Handle HTTPS, WSS, and file schemes 140 | $scheme = $uriScheme; 141 | } else { 142 | // Unsupported scheme 143 | throw new LibsqlError( 144 | 'The client supports only "libsql:", "wss:", "ws:", "https:", "http:" and "file:" URLs, got ' . json_encode($uri->scheme . ":") . '. For more information, please read ' . LibSQL::SUPPORTED_URL_LINK, 145 | "URL_SCHEME_NOT_SUPPORTED" 146 | ); 147 | } 148 | 149 | // Check for URL fragments 150 | if (!empty($uri->fragment)) { 151 | throw new LibsqlError('URL fragments are not supported: ' . json_encode("#" . $uri->fragment), "URL_INVALID"); 152 | } 153 | 154 | // Create and return the ExpandedConfig object 155 | return new ExpandedConfig( 156 | scheme: $scheme, 157 | flags: $flags, 158 | encryptionKey: $encryptionKey, 159 | tls: $tls ?? true, 160 | authority: $uri->authority, 161 | path: $uri->path, 162 | authToken: $authToken, 163 | syncUrl: $syncUrl, 164 | syncInterval: $syncInterval, 165 | read_your_writes: $read_your_writes 166 | ); 167 | } 168 | 169 | /** 170 | * Parse a URI string and return a Uri object. 171 | * 172 | * @param string $text The URI string to parse. 173 | * @return Uri An object containing the parsed components of the URI. 174 | * @throws LibsqlError If the URI is not in a valid format. 175 | */ 176 | public static function parseUri(string $text): Uri 177 | { 178 | $match = []; 179 | preg_match(LibSQL::URI_RE, $text, $match); 180 | if (empty($match)) { 181 | throw new LibsqlError("The URL is not in a valid format", "URL_INVALID"); 182 | } 183 | 184 | $groups = [ 185 | 'scheme' => $match['scheme'] ?? '', 186 | 'authority' => $match['authority'] ?? '', 187 | 'path' => $match['path'] ?? '', 188 | 'query' => $match['query'] ?? '', 189 | 'fragment' => $match['fragment'] ?? '' 190 | ]; 191 | 192 | $scheme = $groups['scheme']; 193 | $authority = !empty($groups['authority']) ? self::parseAuthority($groups['authority']) : null; 194 | $path = self::percentDecode($groups['path']); 195 | $query = !empty($groups['query']) ? self::parseQuery($groups['query']) : null; 196 | $fragment = self::percentDecode($groups['fragment']); 197 | 198 | return Uri::create($scheme, $authority, $path, $query, $fragment); 199 | } 200 | 201 | /** 202 | * Parse authority part of URL and return an Authority object. 203 | * 204 | * @param string $text The authority part of the URL. 205 | * @return Authority An object containing host, port, and userInfo components. 206 | * @throws LibsqlError If the authority part of the URL is not in a valid format. 207 | */ 208 | public static function parseAuthority(string $text): Authority 209 | { 210 | $match = []; 211 | preg_match(LibSQL::AUTHORITY_RE, $text, $match); 212 | if (empty($match)) { 213 | throw new LibsqlError("The authority part of the URL is not in a valid format", "URL_INVALID"); 214 | } 215 | 216 | $groups = [ 217 | 'username' => $match['username'] ?? '', 218 | 'password' => $match['password'] ?? '', 219 | 'host' => $match['host'] ?? '', 220 | 'host_br' => $match['host_br'] ?? '', 221 | 'port' => $match['port'] ?? '' 222 | ]; 223 | 224 | $host = self::percentDecode($groups['host_br'] !== '' ? $groups['host_br'] : $groups['host']); 225 | $port = !empty($groups['port']) ? (int)$groups['port'] : null; 226 | $username = !empty($groups['username']) ? self::percentDecode($groups['username']) : null; 227 | $password = !empty($groups['password']) ? self::percentDecode($groups['password']) : null; 228 | $userInfo = UserInfo::create($username, $password); 229 | 230 | return Authority::create($host, $port, $userInfo); 231 | } 232 | 233 | /** 234 | * Function parseQuery 235 | * 236 | * Parses the query string of a URI and returns a Query object. 237 | * 238 | * @param string $text The query string to parse. 239 | * @return Query The parsed query. 240 | */ 241 | public static function parseQuery(string $text): Query 242 | { 243 | $sequences = explode("&", $text); 244 | $pairs = []; 245 | foreach ($sequences as $sequence) { 246 | if ($sequence === "") { 247 | continue; 248 | } 249 | 250 | $splitIdx = strpos($sequence, "="); 251 | if ($splitIdx === false) { 252 | $key = $sequence; 253 | $value = ""; 254 | } else { 255 | $key = substr($sequence, 0, $splitIdx); 256 | $value = substr($sequence, $splitIdx + 1); 257 | } 258 | 259 | $pairs[] = KeyValue::create(self::percentDecode(str_replace("+", " ", $key)), self::percentDecode(str_replace("+", " ", $value))); 260 | } 261 | return Query::create($pairs); 262 | } 263 | 264 | /** 265 | * Function percentDecode 266 | * 267 | * Decodes a percent-encoded string. 268 | * 269 | * @param string $text The string to decode. 270 | * @return string The decoded string. 271 | * @throws LibsqlError If the URL component has invalid percent encoding. 272 | */ 273 | public static function percentDecode(string $text): string 274 | { 275 | try { 276 | return rawurldecode($text); 277 | } catch (\Exception $e) { 278 | throw new LibsqlError("URL component has invalid percent encoding: " . $e->getMessage(), "URL_INVALID", null, $e); 279 | } 280 | } 281 | 282 | /** 283 | * Function encodeBaseUrl 284 | * 285 | * Encodes the components of a URI and returns a URL object. 286 | * 287 | * @param string $scheme The scheme of the URI. 288 | * @param Authority|null $authority The authority of the URI. 289 | * @param string $path The path of the URI. 290 | * @return string The encoded URL object. 291 | * @throws LibsqlError If the URL requires authority. 292 | */ 293 | public static function encodeBaseUrl(string $scheme, ?Authority $authority, string $path): array|string|int|false|null 294 | { 295 | if ($authority === null) { 296 | throw new LibsqlError("URL with scheme $scheme: requires authority (the \"//\" part)", "URL_INVALID"); 297 | } 298 | 299 | $schemeText = $scheme . ":"; 300 | 301 | $hostText = self::encodeHost($authority->host); 302 | $portText = self::encodePort($authority->port); 303 | $userInfoText = self::encodeUserInfo($authority->userInfo); 304 | $authorityText = "//" . $userInfoText . $hostText . $portText; 305 | 306 | $pathText = $path !== "" && substr($path, 0, 1) !== "/" ? "/" . $path : $path; 307 | $pathText = implode("/", array_map("rawurlencode", explode("/", $pathText))); 308 | 309 | return urldecode($schemeText . $authorityText . $pathText); 310 | } 311 | 312 | /** 313 | * Function encodeHost 314 | * 315 | * Encodes the host component of a URI. 316 | * 317 | * @param string $host The host to encode. 318 | * @return string The encoded host. 319 | */ 320 | public static function encodeHost(string $host): string 321 | { 322 | return strpos($host, ":") !== false ? "[" . rawurlencode($host) . "]" : rawurlencode($host); 323 | } 324 | 325 | /** 326 | * Function encodePort 327 | * 328 | * Encodes the port component of a URI. 329 | * 330 | * @param int|null $port The port to encode. 331 | * @return string The encoded port. 332 | */ 333 | public static function encodePort(?int $port): string 334 | { 335 | return $port !== null ? ":" . $port : ""; 336 | } 337 | 338 | /** 339 | * Function encodeUserInfo 340 | * 341 | * Encodes the userInfo component of a URI. 342 | * 343 | * @param UserInfo|null $userInfo The userInfo to encode. 344 | * @return string The encoded userInfo. 345 | */ 346 | public static function encodeUserInfo(?UserInfo $userInfo): string 347 | { 348 | if ($userInfo === null) { 349 | return ""; 350 | } 351 | 352 | $usernameText = !empty($userInfo->username) ? rawurlencode($userInfo->username) : ""; 353 | $passwordText = !empty($userInfo->password) ? ":" . rawurlencode($userInfo->password) : ""; 354 | if (!empty($usernameText) && !empty($passwordText)) { 355 | return $usernameText . $passwordText . "@"; 356 | } 357 | return ""; 358 | } 359 | 360 | /** 361 | * Check if a string is base64 encoded. 362 | * @link https://stackoverflow.com/a/38627879/12439522 363 | * 364 | * @param string $data The string to check. 365 | * 366 | * @return bool True if the string is base64 encoded, false otherwise. 367 | */ 368 | public static function is_base64($string) 369 | { 370 | $decoded_data = base64_decode($string, true); 371 | $encoded_data = base64_encode($decoded_data); 372 | if ($encoded_data != $string) return false; 373 | else if (!ctype_print($decoded_data)) return false; 374 | 375 | return true; 376 | } 377 | 378 | /** 379 | * Determines the type of a given column value. 380 | * 381 | * @param mixed $column The column value to check. 382 | * @return string The type of the column value ('unknown', 'float', 'blob', 'integer', 'text', or 'null'). 383 | */ 384 | public static function checkColumnType(mixed $column): string 385 | { 386 | $type = 'unknown'; 387 | 388 | if (is_float($column)) { 389 | $type = 'float'; 390 | } else if (self::is_base64($column)) { 391 | $type = 'blob'; 392 | } else if (is_int($column)) { 393 | $type = 'integer'; 394 | } else if (is_string($column)) { 395 | $type = 'text'; 396 | } else if (is_null($column)) { 397 | $type = 'null'; 398 | } 399 | 400 | return $type; 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /src/Utils/helpers.php: -------------------------------------------------------------------------------- 1 | [] 21 | ]; 22 | 23 | // Extract baton and base_url from the data 24 | $mapped_results['baton'] = $data['baton']; 25 | $mapped_results['base_url'] = $data['base_url']; 26 | 27 | // Iterate through each result in the data 28 | foreach ($data['results'] as $result) { 29 | // Check if the result is successful and has a response 30 | if ($result['type'] === 'ok' && isset($result['response']['result'])) { 31 | $response = $result['response']['result']; 32 | 33 | // Create a mapped result array 34 | $mapped_result = [ 35 | 'cols' => array_map(function ($col) { 36 | return [ 37 | 'name' => $col['name'], 38 | 'decltype' => $col['decltype'] 39 | ]; 40 | }, $response['cols']), 41 | 'column_types' => array_column($response['cols'], 'decltype'), 42 | 'rows' => $response['rows'], 43 | 'affected_row_count' => $response['affected_row_count'], 44 | 'last_insert_rowid' => $response['last_insert_rowid'], 45 | 'replication_index' => $response['replication_index'] 46 | ]; 47 | 48 | // Create HttpResultSets object 49 | $resultSet = HttpResultSets::create( 50 | $mapped_result['cols'], 51 | $mapped_result['rows'], 52 | $mapped_result['affected_row_count'], 53 | $mapped_result['last_insert_rowid'], 54 | $mapped_result['replication_index'] 55 | ); 56 | 57 | // Add the resultSet to mapped results 58 | array_push($mapped_results['results'], $resultSet); 59 | } 60 | 61 | if ($result['type'] === 'error') { 62 | throw new LibsqlError($result['error']['message'], $result['error']['code']); 63 | } 64 | } 65 | 66 | // Return mapped results 67 | return $mapped_results; 68 | } 69 | 70 | function objectToArray($object) 71 | { 72 | if (!is_object($object) && !is_array($object)) 73 | return $object; 74 | 75 | return array_map('objectToArray', (array) $object); 76 | } 77 | --------------------------------------------------------------------------------