@@ -342,6 +342,229 @@ public function compareBinaryHash(string $url, string $binaryPath) {
342
342
return true ;
343
343
}
344
344
345
+ /**
346
+ * Perform cURL to download python binary (in directory format)
347
+ *
348
+ * @param string $url
349
+ * @param array $binariesFolder appdata binaries folder
350
+ * @param string $appId target Application::APP_ID
351
+ * @param string $filename archive and extracted folder name
352
+ * @param bool $update flag to determine whether to update already downloaded binary or not
353
+ *
354
+ * @return array
355
+ */
356
+ public function downloadPythonBinaryDir (
357
+ string $ url ,
358
+ array $ binariesFolder ,
359
+ string $ appId ,
360
+ string $ filename = 'main ' ,
361
+ bool $ update = false
362
+ ): array {
363
+ if (isset ($ binariesFolder ['success ' ]) && $ binariesFolder ['success ' ]) {
364
+ $ dir = $ binariesFolder ['path ' ] . '/ ' ;
365
+ } else {
366
+ return $ binariesFolder ; // Return getAppDataFolder result
367
+ }
368
+ $ file_name = $ filename . '.tar.gz ' ;
369
+ $ save_file_loc = $ dir . $ file_name ;
370
+ $ shouldDownloadBinary = $ this ->compareBinaryDirectoryHashes ($ url , $ binariesFolder , $ appId );
371
+
372
+ if (!file_exists ($ dir . $ filename ) || ($ update && $ shouldDownloadBinary )) {
373
+ $ cURL = curl_init ($ url );
374
+ $ fp = fopen ($ save_file_loc , 'wb ' );
375
+ if ($ fp ) {
376
+ curl_setopt_array ($ cURL , [
377
+ CURLOPT_RETURNTRANSFER => true ,
378
+ CURLOPT_FILE => $ fp ,
379
+ CURLOPT_FOLLOWLOCATION => true ,
380
+ ]);
381
+ curl_exec ($ cURL );
382
+ curl_close ($ cURL );
383
+ fclose ($ fp );
384
+ $ unpacked = $ this ->unTarGz ($ binariesFolder , $ filename . '.tar.gz ' );
385
+ unlink ($ save_file_loc );
386
+ return [
387
+ 'downloaded ' => true ,
388
+ 'unpacked ' => $ unpacked
389
+ ];
390
+ }
391
+ }
392
+
393
+ return [
394
+ 'downloaded ' => true ,
395
+ 'unpacked ' => true ,
396
+ ];
397
+ }
398
+
399
+ /**
400
+ * Extract tar.gz file
401
+ *
402
+ * @param array $binariesFolder appdata binaries folder
403
+ * @param string $src_filename source tar.gz file name
404
+ *
405
+ * @return array
406
+ */
407
+ public function unTarGz (array $ binariesFolder , string $ src_filename ): array {
408
+ if (isset ($ binariesFolder ['success ' ]) && $ binariesFolder ['success ' ]) {
409
+ $ dir = $ binariesFolder ['path ' ] . '/ ' ;
410
+ $ src_file = $ dir . $ src_filename ;
411
+ $ phar = new \PharData ($ src_file );
412
+ $ extracted = $ phar ->extractTo ($ dir , null , true );
413
+ $ filename = $ phar ->getFilename ();
414
+ return [
415
+ 'extracted ' => $ extracted ,
416
+ 'filename ' => $ filename
417
+ ];
418
+ }
419
+ return [
420
+ 'extracted ' => false ,
421
+ ];
422
+ }
423
+
424
+ /**
425
+ * Perform cURL to get binary folder hashes sha256 sum
426
+ *
427
+ * @param string $url url to the binary hashsums file
428
+ *
429
+ * @return array
430
+ */
431
+ public function downloadBinaryDirHashes (string $ url ): array {
432
+ $ cURL = curl_init ($ url );
433
+ curl_setopt_array ($ cURL , [
434
+ CURLOPT_RETURNTRANSFER => true ,
435
+ CURLOPT_FOLLOWLOCATION => true ,
436
+ ]);
437
+ $ binaryHash = curl_exec ($ cURL );
438
+ curl_close ($ cURL );
439
+ return [
440
+ 'success ' => $ binaryHash != false ,
441
+ 'binaryHash ' => json_decode ($ binaryHash , true ),
442
+ ];
443
+ }
444
+
445
+ /**
446
+ * Compare binary folder hashes from release.
447
+ * If hash not exists return `true` (download anyway)
448
+ *
449
+ * @param string $url
450
+ * @param array $binariesFolder
451
+ *
452
+ * @return bool
453
+ */
454
+ public function compareBinaryDirectoryHashes (
455
+ string $ url , array $ binariesFolder , string $ appId
456
+ ): bool {
457
+ $ currentBinaryHashes = $ this ->getCurrentBinaryDirHashes ($ binariesFolder , $ appId );
458
+ $ newBinaryHashes = $ this ->downloadBinaryDirHashes (str_replace ('.tar.gz ' , '.json ' , $ url ));
459
+ if ($ newBinaryHashes ['success ' ] && $ currentBinaryHashes ['success ' ]) {
460
+ // Skip hash check of archive file
461
+ $ archiveFilename = $ appId . '_ ' . $ this ->getBinaryName () . '.tar.gz ' ;
462
+ if (isset ($ newBinaryHashes ['binaryHashes ' ][$ archiveFilename ])) {
463
+ unset($ newBinaryHashes ['binaryHashes ' ][$ archiveFilename ]);
464
+ }
465
+ foreach ($ newBinaryHashes ['binaryHashes ' ] as $ filename => $ hash ) {
466
+ $ fileExists = !isset ($ currentBinaryHashes [$ filename ]);
467
+ $ currentHash = $ currentBinaryHashes ['binaryHashes ' ][$ filename ];
468
+ $ hashEqual = $ currentHash == $ hash ;
469
+ if (!$ fileExists || !$ hashEqual ) {
470
+ return true ;
471
+ }
472
+ }
473
+ return false ;
474
+ }
475
+ return true ;
476
+ }
477
+
478
+ /**
479
+ * Get current binary folder files hashes
480
+ *
481
+ * @param array $binariesFolder
482
+ *
483
+ * @return array
484
+ */
485
+ public function getCurrentBinaryDirHashes (array $ binariesFolder , string $ appId ): array {
486
+ $ currentBinaryHashes = [];
487
+ $ archiveFilename = $ appId . '_ ' . $ this ->getBinaryName () . '.tar.gz ' ;
488
+ if (file_exists ($ binariesFolder ['path ' ] . '/ ' . $ archiveFilename )) {
489
+ $ currentBinaryHashes [$ archiveFilename ] = hash_file (
490
+ 'sha256 ' ,
491
+ $ binariesFolder ['path ' ] . '/ ' . $ archiveFilename
492
+ );
493
+ }
494
+ $ extractedBinaryFolder = $ binariesFolder ['path ' ] . '/ ' . $ appId . '_ ' . $ this ->getBinaryName ();
495
+ $ files = scandir ($ extractedBinaryFolder );
496
+ if ($ files !== false ) {
497
+ foreach ($ files as $ file ) {
498
+ if ($ file != '. ' && $ file != '.. ' ) {
499
+ // Get sha256 hash of each file
500
+ // If file is directory, get sha256 hash of each file in directory
501
+ if (is_dir ($ extractedBinaryFolder . '/ ' . $ file )) {
502
+ $ dirFiles = scandir ($ extractedBinaryFolder . '/ ' . $ file );
503
+ $ currentBinaryHashes = $ this ->getFolderHashes (
504
+ $ dirFiles ,
505
+ $ file ,
506
+ $ extractedBinaryFolder . '/ ' . $ file ,
507
+ $ currentBinaryHashes ,
508
+ $ appId
509
+ );
510
+ } else {
511
+ $ binaryFolderFilePath = $ appId . '_ ' . $ this ->getBinaryName () . '/ ' . $ file ;
512
+ $ currentBinaryHashes [$ binaryFolderFilePath ] = hash_file (
513
+ 'sha256 ' ,
514
+ $ extractedBinaryFolder . '/ ' . $ file
515
+ );
516
+ }
517
+ }
518
+ }
519
+ }
520
+ return [
521
+ 'success ' => count ($ currentBinaryHashes ) > 0 ,
522
+ 'binaryHashes ' => $ currentBinaryHashes
523
+ ];
524
+ }
525
+
526
+ /**
527
+ * Get sha256 hashes of each file in binary folder
528
+ * Recursive function call if file is directory
529
+ *
530
+ * @param array $files
531
+ * @param string $folder
532
+ * @param string $extractedBinaryFolder
533
+ * @param array $currentBinaryHashes
534
+ * @param string $appId
535
+ *
536
+ * @return array
537
+ */
538
+ private function getFolderHashes (
539
+ array $ files ,
540
+ string $ folder ,
541
+ string $ extractedBinaryFolder ,
542
+ array $ currentBinaryHashes ,
543
+ string $ appId
544
+ ): array {
545
+ foreach ($ files as $ file ) {
546
+ if ($ file != '. ' && $ file != '.. ' ) {
547
+ // Get sha256 hash of each file
548
+ // If file is directory, get sha256 hash of each file in directory
549
+ if (is_dir ($ extractedBinaryFolder . '/ ' . $ file )) {
550
+ $ dirFiles = scandir ($ extractedBinaryFolder . '/ ' . $ file );
551
+ $ currentBinaryHashes = $ this ->getFolderHashes (
552
+ $ dirFiles ,
553
+ $ folder . '/ ' . $ file , $ extractedBinaryFolder . '/ ' . $ file ,
554
+ $ currentBinaryHashes , $ appId
555
+ );
556
+ } else {
557
+ $ binaryFolderFilePath = $ appId . '_ '
558
+ . $ this ->getBinaryName () . '/ ' . $ folder . '/ ' . $ file ;
559
+ $ currentBinaryHashes [$ binaryFolderFilePath ] = hash_file (
560
+ 'sha256 ' , $ extractedBinaryFolder . '/ ' . $ file
561
+ );
562
+ }
563
+ }
564
+ }
565
+ return $ currentBinaryHashes ;
566
+ }
567
+
345
568
/**
346
569
* Perform cURL to get binary's sha256 sum
347
570
*
0 commit comments