@@ -194,7 +194,7 @@ export class PrecompiledBinaryDownloader {
194
194
// eslint-disable-next-line ts/no-require-imports
195
195
const fs = require ( 'node:fs' )
196
196
197
- // Check for Laravel
197
+ // Check for Laravel (or Laravel-like) projects
198
198
if ( fs . existsSync ( 'artisan' ) && fs . existsSync ( 'composer.json' ) ) {
199
199
try {
200
200
const composerJson = JSON . parse ( fs . readFileSync ( 'composer.json' , 'utf-8' ) )
@@ -233,6 +233,20 @@ export class PrecompiledBinaryDownloader {
233
233
}
234
234
}
235
235
236
+ // Even if composer does not indicate Laravel explicitly, infer from .env alone
237
+ try {
238
+ if ( fs . existsSync ( '.env' ) ) {
239
+ const envContent = fs . readFileSync ( '.env' , 'utf-8' )
240
+ if ( envContent . includes ( 'DB_CONNECTION=pgsql' ) || envContent . includes ( 'DB_CONNECTION=postgres' ) ) {
241
+ return 'laravel-postgres'
242
+ }
243
+ if ( envContent . includes ( 'DB_CONNECTION=sqlite' ) ) {
244
+ return 'laravel-sqlite'
245
+ }
246
+ }
247
+ }
248
+ catch { }
249
+
236
250
// Check for WordPress without Laravel
237
251
if ( fs . existsSync ( 'wp-config.php' ) || fs . existsSync ( 'wp-config-sample.php' ) ) {
238
252
return 'wordpress'
@@ -697,6 +711,20 @@ Thanks for helping us make Launchpad better! 🙏
697
711
698
712
// Find Launchpad-installed libraries for PHP dependencies
699
713
const launchpadLibraryPaths = await this . findLaunchpadLibraryPaths ( )
714
+ // Ensure readline from pantry is included as many PHP builds reference it
715
+ const readlineLocal = path . join ( this . installPath , 'gnu.org/readline' )
716
+ const readlineGlobal = path . join ( process . env . HOME || '' , '.local' , 'share' , 'launchpad' , 'global' , 'gnu.org/readline' )
717
+ for ( const base of [ readlineLocal , readlineGlobal ] ) {
718
+ if ( fs . existsSync ( base ) ) {
719
+ const versions = fs . readdirSync ( base ) . filter ( v => v . startsWith ( 'v' ) )
720
+ for ( const v of versions ) {
721
+ const libDir = path . join ( base , v , 'lib' )
722
+ if ( fs . existsSync ( libDir ) && ! launchpadLibraryPaths . includes ( libDir ) ) {
723
+ launchpadLibraryPaths . push ( libDir )
724
+ }
725
+ }
726
+ }
727
+ }
700
728
701
729
// Get all PHP binaries
702
730
const binaries = fs . readdirSync ( binDir ) . filter ( ( file ) => {
@@ -705,6 +733,40 @@ Thanks for helping us make Launchpad better! 🙏
705
733
return stat . isFile ( ) && ( stat . mode & 0o111 ) // is executable
706
734
} )
707
735
736
+ // Prepare a project-level php.ini with database extensions based on detected project usage
737
+ const projectPhpIni = path . join ( this . installPath , 'php.ini' )
738
+ try {
739
+ const detected = await this . detectFrameworkAndDatabase ( )
740
+ const dbExtensions : string [ ] = [ ]
741
+ if ( detected === 'laravel-postgres' ) {
742
+ dbExtensions . push ( 'pdo_pgsql' , 'pgsql' )
743
+ }
744
+ else if ( detected === 'laravel-mysql' ) {
745
+ dbExtensions . push ( 'pdo_mysql' , 'mysqli' )
746
+ }
747
+ else if ( detected === 'laravel-sqlite' ) {
748
+ dbExtensions . push ( 'pdo_sqlite' , 'sqlite3' )
749
+ }
750
+
751
+ const ini = [
752
+ '; Launchpad php.ini (auto-generated)' ,
753
+ 'memory_limit = 512M' ,
754
+ 'max_execution_time = 300' ,
755
+ 'upload_max_filesize = 64M' ,
756
+ 'post_max_size = 64M' ,
757
+ 'display_errors = On' ,
758
+ 'error_reporting = E_ALL' ,
759
+ '' ,
760
+ '; Enable database extensions based on project detection' ,
761
+ ...dbExtensions . map ( ext => `extension=${ ext } ` ) ,
762
+ '' ,
763
+ ] . join ( '\n' )
764
+ fs . writeFileSync ( projectPhpIni , ini , 'utf8' )
765
+ }
766
+ catch ( err ) {
767
+ console . warn ( `⚠️ Could not write project php.ini: ${ err instanceof Error ? err . message : String ( err ) } ` )
768
+ }
769
+
708
770
for ( const binary of binaries ) {
709
771
const originalBinary = path . join ( binDir , binary )
710
772
const shimPath = path . join ( binDir , `${ binary } .original` )
@@ -735,6 +797,11 @@ export DYLD_LIBRARY_PATH="${libraryPaths}:$DYLD_LIBRARY_PATH"
735
797
export DYLD_FALLBACK_LIBRARY_PATH="${ libraryPaths } :$DYLD_FALLBACK_LIBRARY_PATH"
736
798
export LD_LIBRARY_PATH="${ libraryPaths } :$LD_LIBRARY_PATH"
737
799
800
+ # Prefer project-level php.ini when present
801
+ if [ -f "${ projectPhpIni . replace ( / " / g, '\\"' ) } " ]; then
802
+ export PHPRC="${ projectPhpIni . replace ( / " / g, '\\"' ) } "
803
+ fi
804
+
738
805
# Execute the original binary
739
806
exec "${ shimPath } " "$@"
740
807
`
@@ -1288,6 +1355,48 @@ export async function downloadPhpBinary(installPath: string, requestedVersion?:
1288
1355
throw new Error ( `Failed to install PHP binary: ${ result . error } ` )
1289
1356
}
1290
1357
1358
+ // Generate a project-level php.ini that enables DB extensions based on simple detection
1359
+ try {
1360
+ const phpIniPath = path . join ( installPath , 'php.ini' )
1361
+ const iniLines : string [ ] = [
1362
+ '; Launchpad php.ini (auto-generated)' ,
1363
+ 'memory_limit = 512M' ,
1364
+ 'max_execution_time = 300' ,
1365
+ 'upload_max_filesize = 64M' ,
1366
+ 'post_max_size = 64M' ,
1367
+ 'display_errors = On' ,
1368
+ 'error_reporting = E_ALL' ,
1369
+ '' ,
1370
+ '; Enable database extensions based on project detection' ,
1371
+ ]
1372
+
1373
+ // Basic detection using .env
1374
+ try {
1375
+ const envPath = path . join ( process . cwd ( ) , '.env' )
1376
+ if ( fs . existsSync ( envPath ) ) {
1377
+ const envContent = fs . readFileSync ( envPath , 'utf-8' )
1378
+ const dbConnMatch = envContent . match ( / ^ D B _ C O N N E C T I O N = ( .* ) $ / m)
1379
+ const dbConn = dbConnMatch ?. [ 1 ] ?. trim ( ) . toLowerCase ( )
1380
+ if ( dbConn === 'pgsql' || dbConn === 'postgres' || dbConn === 'postgresql' ) {
1381
+ iniLines . push ( 'extension=pdo_pgsql' )
1382
+ iniLines . push ( 'extension=pgsql' )
1383
+ }
1384
+ else if ( dbConn === 'mysql' || dbConn === 'mariadb' ) {
1385
+ iniLines . push ( 'extension=pdo_mysql' )
1386
+ iniLines . push ( 'extension=mysqli' )
1387
+ }
1388
+ else if ( dbConn === 'sqlite' ) {
1389
+ iniLines . push ( 'extension=pdo_sqlite' )
1390
+ iniLines . push ( 'extension=sqlite3' )
1391
+ }
1392
+ }
1393
+ }
1394
+ catch { }
1395
+
1396
+ fs . writeFileSync ( phpIniPath , iniLines . join ( '\n' ) )
1397
+ }
1398
+ catch { }
1399
+
1291
1400
// Create shims in installPath/bin and sbin so php is available on PATH
1292
1401
try {
1293
1402
const installedBinaries = await createShims ( result . packageDir , installPath , 'php.net' , result . version )
0 commit comments