PHP Script To Copy Files Recursively With Options

, ,

This script will help you copy files and folders from one location to another, recursively.
For each file or folder you can have copy options.

Here is an example conf file :

:: GitHub File ::
[/etc/php/cacert.pem] keep_existing = 1 [/etc/nginx/nginx.conf] keep_existing = 0 backup = 1 [/etc/nginx/sites-available/default] keep_existing = 0 backup = 1 [/etc/nginx] keep_existing = 1 [/home/default] keep_existing = 1

In this example, the file data/etc/nginx/sites-available/default will be copied to /etc/nginx/sites-available/default, and if the file already exists it will be backuped and overwritten.
In the same way, all the files inside data/etc/nginx will be copied to /etc/nginx, but existing file will be ignored.

How To

Place folders and files that you want to copy in data/
Edit filecopier-config.ini to configure which files and folders you want to copy, backup and overwrite

Command Lines :

php filecopier.php process_all [options]

This command will execute every entries in the filecopier-config.ini file

Config file options :

option values default description
keep_existing 1/0 0 keep file if already exists, do not overwrite it
backup 1/0 0 create a backup of the file if exists, then copy the new file
debug 1/0 0 write the copy in a test/ folder
php confeditor.php process filepath [options]

This command will copy the file located in data/filepath to filepath

Cmd options :

option equivalent values default
-ke keep_existing 1/0 0
-b backup 1/0 0
-d debug 1/0 0

PHP Script

:: GitHub File ::
<?php if(count($argv) >= 2 ) { if($argv[1] == 'process' && count($argv) >= 4 ) { process($argv[2], $argv[3]); } else if($argv[1] == 'process-all' ) { $config = parse_ini('confeditor-config.ini',false,false); //print_r($config); //exit(); foreach($config as $k=>$v) { $AddEdit = $k; $original = $v['original']; process($k, $original, $v); } } } function process( $editFileName, $originalFile, $config = null ) { global $argv; // gettings extra params $keepComments = getSetting( $config, $argv, 'keep_comments', '-kc', false, false); $keepEmptyLines = getSetting( $config, $argv, 'keep_empty_lines', '-kel', false, false); $sort = getSetting( $config, $argv, 'sort', '-sort', false, false); $debug = getSetting( $config, $argv, 'debug', '-d', false, false); $separator = getSetting( $config, $argv, 'separator', '-sep', true, '='); $commentRegex = getSetting( $config, $argv, 'comment_regex', '-cr', true, '-^(;|#)-'); $separator = str_replace('"', '', $separator); $commentRegex = str_replace('"', '',$commentRegex); //exit( '$keepComments '.$keepComments. ' $keepEmptyLines '.$keepEmptyLines. ' $sort '.$sort.' $separator '.$separator.' $commentRegex '.$commentRegex.' $debug '.$debug); $editFile = './data/'.$editFileName; if(!file_exists($editFile)) die( "editFile does not exist ".$editFile); if(!file_exists($originalFile)) die( "originalFile does not exist ".$originalFile); $to = $debug ? $originalFile.'-new.ini' : $originalFile; backup_file($originalFile); $ini = parse_ini($originalFile, $keepComments, $keepEmptyLines, $separator, $commentRegex ); $iniNewValues = parse_ini($editFile, false, false); $iniEdited = edit_ini($ini, $iniNewValues, $sort); save_ini($to, $iniEdited); //print_r($config); print_r($ini); print_r($iniNewValues); print_r($iniEdited); //$ini2 = parse_ini($file2, true); //print_r($ini2); } function getSetting( $config, $argv, $varName, $argName, $keepNextArg, $default) { if(!empty($config) && isset($config[$varName])) return $config[$varName]; if(!empty($argv) && !empty($argName) ) { if(in_array($argName, $argv) ) return $keepNextArg ? $argv[ array_search($argName, $argv) + 1 ] : true; } return $default; } function backup_file ($file) { //echo $file.'.bak'; if(!copy( $file, $file.'.bak')) //if(!file_put_contents( $file.'.bak', file_get_contents( $file))) exit("la création du backup a échoué"); } function edit_ini ( $ini, $iniNewValues, $sort = false ) { $ini = array_replace_recursive( $ini, $iniNewValues ); $globals = []; $sections = []; foreach( $ini as $k=>$v) { if(is_array($v)) //section $sections[$k] = $v; else $globals[$k] = $v; } if($sort) { ksort($globals); //print_r($globals); foreach($sections as $k => $v) { ksort($v); $sections[$k] = $v; //print_r($sections[$k]); } } return $globals + $sections; } function save_ini ( $filepath, $ini, $save = true ) { $str = ''; foreach( $ini as $k=>$v) { if(is_array($v)) //section { $str .= "[$k]".PHP_EOL; $str .= save_ini( '', $v, false); }else { if( preg_match('#^comment#', $k )) $str .= $v.PHP_EOL; else if( preg_match('#^empty#', $k )) $str .= PHP_EOL; else $str .= "$k = $v".PHP_EOL; } } if($save) file_put_contents($filepath, $str ); else return $str; } function parse_ini ( $filepath, $keepComments = true, $keepEmptyLines = true, $separator = '=', $commentRegex = '-^(;|#)-' ) { $ini = file( $filepath ); if ( count( $ini ) == 0 ) { return array(); } $sections = array(); $values = array(); $globals = array(); $result = array(); $i = 0; $j = 0; foreach( $ini as $line ){ $line = trim( $line ); // Sections if ( !empty($line) && $line{0} == '[' ) { $sections[] = substr( $line, 1, -1 ); $i++; continue; } // Key-value pair if ( $line == '' ) { if($keepEmptyLines) { $key = 'empty'.$j++; $value = $line; //echo $value; } else continue; }else if ( preg_match($commentRegex, $line) ) { if($keepComments ) { $key = 'comment'.$j++; $value = $line; //echo $value }else continue; }else if( preg_match( '#'.$separator.'#', $line)){ list( $key, $value ) = explode( $separator, $line, 2 ); } $key = trim( $key ); $value = trim( $value ); if ( $i == 0 ) { // Array values if ( substr( $line, -1, 2 ) == '[]' ) { $globals[ $key ][] = $value; } else { $globals[ $key ] = $value; } } else { // Array values if ( substr( $line, -1, 2 ) == '[]' ) { $values[ $i - 1 ][ $key ][] = $value; } else { $values[ $i - 1 ][ $key ] = $value; } } } for( $j=0; $j<$i; $j++ ) { $result[ $sections[ $j ] ] = $values[ $j ]; } return $globals + $result; } ?>

The full repository is here : https://github.com/anthonykozak/iniTools

How To Edit ini & conf Files With Shell Scripts

,

I wrote some scripts to help editing ini files and conf files while reinstalling my servers.

The script is able to process multiple files at once and will add or edit the parameters you want automatically.

the configuration file looks like this :

:: GitHub File ::
[_www.conf] original = /etc/php/5.6/fpm/pool.d/www.conf keep_comments = 0 keep_empty_lines = 0 sort = 1 [_sysctl.conf] original = /etc/sysctl.conf keep_comments = 1 keep_empty_lines = 1 [_php-fpm.conf] original = /etc/php/5.6/fpm/php-fpm.conf keep_comments = 0 keep_empty_lines = 0 [_php.ini] original = /etc/php/5.6/fpm/php.ini keep_comments = 1 keep_empty_lines = 1

As you can see for each file I want to edit, there is a small file containing only the lines I need to be edited or added. For exxample the _php-fpm.conf file looks like this :

:: GitHub File ::
[global] error_log = /var/log/php/php-fpm.log emergency_restart_threshold = 10 emergency_restart_interval = 1m process_control_timeout = 20s

 

Command Lines :

php confeditor.php process_all [options]

This command will execute every entries in the confeditor-config.ini file

file options :

option values default description
keep_comments 1/0 0 keep comment lines in the target file
keep_empty_lines 1/0 0 keep empty lines in target file
sort 1/0 0 sort ini keys in each section
debug 1/0 0 do not write in files but create a ‘-new’ file instead
separator string ‘=’ separator for key & values
comment_regex regex ‘-^(;|#)-‘ what defines a comment
php confeditor.php process sample-file target-file [options]

This command will merge the target-file with the lines inside the data/sample-file

Cmd options :

option equivalent values default
-kc keep_comments 1/0 0
-kel keep_empty_lines 1/0 0
-sort sort 1/0 0
-d debug 1/0 0
-sep separator string ‘=’
-cr comment_regex string ‘-^(;|#)-‘

The main repository is here : https://github.com/anthonykozak/iniTools

Upgrade EasyPHP’s php version without having to pay for warehouse

,

So you like Easyphp and you just want to upgrade you PHP version?

Easyphp now comes with a website called Warehouse, allowing you to download modules and components but the access is not free. Of course there is plenty of reasons you would pay for such service but if you like me just want to upgrade your PHP version follow those steps :

1. Download the windows PHP version you want on the official site : http://windows.php.net/download/, for example the VC11 x86 Thread Safe (2016-Jun-22 21:49:59) version. (I did not tested with the a x64 version).

2. Unzip the package to your EasyPHP « php » folder. (Create a folder with your version name) for example : C:\EasyPHP-DevServer-14.1VC9\binaries\php\php-5.6\

3. Copy the file « easyphp.php » from php_runningversion/easyphp.php to php-5.6/easyphp.php and edit it.

4. Just indicate a version number, a dir name and a new date greater that the previous one

<?php
$phpversion = array();
$phpversion = array(
"status"    => "0",
"dirname"    => "php5623x160719154425",
"name"         => "PHP",
"version"     => "5.6.23",
"date"         => "2016-07-20 15:44:24",
"notes"     => "",
);
?>

5. Go to you EasyPHP admin page and click on the link to change your php version (http://127.0.0.1/home/index.php?page=php-page&display=changephpversion). Your version should appear on the list, select it.

6. Restart EasyPhp your version should be upgraded. Now be sure to download the appropriate extensions for your version on the official site : http://windows.php.net/downloads/pecl/releases/

[TUTORIAL] Unity3D – Signing and Packaging your game for the Mac AppStore and Outside !

, ,

I spent some times to understand the way to sign and package an .app generated from Unity3D for the Mac AppStore or for outside of it. The workflow is quite the same, you will need to type a few lines of code in order to generate the proper files.

The few differences are that you don’t need the « entitlements »  file and the certifactes are different.

If you want to publish your game outside the store, from the Apple Member Center, you will need to generate the « DEVELOPER ID » application and installer certificates. Then install them by drag and dropping them into you keychain access.

For the Mac AppStore, you have to generate the « MAC APP STORE » production application and installer certifcates.

I made a script in order to automate the signing and packaging process. Here it is on GitHub :

:: GitHub File ::
#!/usr/bin/perl use File::Copy; use File::Find; use File::Path; use Cwd; # Exoa SignAndPackage script v1.3 # Author : Anthony Kozak :: exoa.fr # Place this script in the same folder as the generated .app file from Unity # YOU WOULD NEED IN THIS DIRECTOY: # - a filled Info.plist file # - a PlayerIcon.icns file # - a filled entitlements.entitlements file # - a UnityPlayerIcon.png file # YOU CAN CHECK YOUR INSTALLED CERTIFICATES NAMES USING # security find-identity -p codesigning logit("Hello !"); my $app_found = found_app_indir(); my $appName = ask("What's the .app name in this directory ?", $app_found); my $appPath = getcwd . "/".$appName.".app"; my $appType = ask("Is this app for the MacAppStore or External ?","MacAppStore"); my $appPathSigned = getcwd . "/".$appType."/".$appName.".app"; my $packagePath = getcwd . "/".$appType."/".$appName.".pkg"; #my $profile = ask("What's the provision profile name to use in this directory ?","profile.provisionprofile"); my $doCodeSigning = ask("Sign the app ?", "true"); my $doCreatePackage = ask("Generate package ?","true"); my $copyInfopList = ask("Copy Info.plist from this directory inside the .app ?","true"); my $copyIcons = ask("Copy PlayerIcon.icns from this directory inside the .app ?","false"); my $copyIcon = ask("Copy UnityPlayerIcon.png from this directory inside the .app ?","true"); my $srcAssetPath = "/"; my $certificateApplication = ask("What's the application certificate name ?", $appType eq "MacAppStore" ? "3rd Party Mac Developer Application:" : "Developer ID Application:"); my $certificateInstaller = ""; if($doCreatePackage eq "true") { $certificateInstaller = ask("What's the installer certificate name ?", $appType eq "MacAppStore" ? "3rd Party Mac Developer Installer:" : "Developer ID Installer:"); } my $entitlementsFileName = ""; if($appType eq "MacAppStore") { $entitlementsFileName = ask("What's the .entitlements file name in this directory ?", "entitlements.entitlements"); $entitlementsFileName = "--entitlements \"".$entitlementsFileName."\""; } logit("*** Starting Process - Building at '$appPath' ***"); # src and dest are temp variables. Just ignore them... 🙂 my $src = ""; my $dest = ""; # Removing previous dir rmtree $appType; # Creating target dir mkdir $appType, 0755; # this copies your own /Info.plist to the generated game if($copyInfopList eq "true") { $plist = getcwd . $srcAssetPath . "Info.plist"; $dest = $appPath . "/Contents/Info.plist"; print ("\n*** Copying " . getShort($plist). " to " . getShort($dest)); copy($plist, $dest) or die "File can not be copied: " . $plist; } # this copies PlayerIcon.icns to your generated game replacing the original app icon by your own if($copyIcons eq "true") { $icons = getcwd . $srcAssetPath . "PlayerIcon.icns"; $dest = $appPath . "/Contents/Resources/PlayerIcon.icns"; print ("\n*** Copying " . $icons . " to " . $dest); copy($icons, $dest) or die "File can not be copied: " . $icons; } # this copies /UnityPlayerIcon.png to your generated game replacing the original Unity Player Icon by your own if($copyIcon eq "true") { $playericon = getcwd . $srcAssetPath . "UnityPlayerIcon.png"; $dest = $appPath . "/Contents/Resources/UnityPlayerIcon.png"; print ("\n*** Copying " . getShort($playericon) . " to " . getShort($dest)); copy($playericon, $dest) or die "File can not be copied: " . $playericon; } # this copies $profile to your generated game #$src = getcwd . $srcAssetPath . $profile; #$dest = $appPath . "/Contents/embedded.provisionprofile"; #print ("\n*** Copying " . getShort($src) . " to " . getShort($dest)); #copy($src, $dest) or die "File can not be copied: " . $src; # this copies appPath to appPathSigned and use it print ("\n*** Copying " . getShort($appPath) . " to " . getShort($appPathSigned)); system("cp -r \"".$appPath."\" \"".$appPathSigned."\""); ## Chmod and remove unecessary files system("/bin/chmod -R a+rwx \"$appPathSigned\""); system("find \"$appPathSigned\" -name \*.meta -exec rm -r \"{}\" \\;"); system("/usr/sbin/chown -RH \"cestdesbullshit1:staff\" \"$appPathSigned\""); system("/bin/chmod -RH u+w,go-w,a+rX \"$appPathSigned\""); my $CodesignEnvironment = $ENV{'CODESIGN_ALLOCATE'}; $ENV{'CODESIGN_ALLOCATE'}="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate"; # Auto code signing if ($doCodeSigning eq "true") { recursiveCodesign("$appPathSigned/Contents/Frameworks"); recursiveCodesign("$appPathSigned/Contents/Plugins"); recursiveCodesign("$appPathSigned/Contents/MacOS"); logit ("*** Start signing"); system("/usr/bin/codesign --force --timestamp=none --sign \"" . $certificateApplication . "\" ".$entitlementsFileName." \"" . $appPathSigned . "\""); logit ("*** Verify signing"); system("codesign --verify --verbose \"" . $appPathSigned . "\""); } # Auto creating a package file? if ($doCreatePackage eq "true") { logit("*** Start packaging"); system("productbuild --component \"" . $appPathSigned . "\" /Applications --sign \"". $certificateInstaller . "\" --product \"$appPathSigned/Contents/Info.plist\" \"" . $packagePath . "\""); } $ENV{'CODESIGN_ALLOCATE'}=$CodesignEnvironment; logit("*** ALL DONE ! ***"); sub ask{ my $text = shift; my $default = shift; logit($text . " [default: ".$default."]"); my $answer = <STDIN>; chomp $answer; return ($answer eq "") ? $default : $answer; } sub logit{ my $text = shift; print("\n".$text."\n"); } sub recursiveCodesign { my $dirName = shift; print("\n*** Recursive Codesigning ".getShort($dirName)."\n"); opendir my($dh), $dirName or return; my @files = readdir($dh); closedir $dh; foreach my $currentFile (@files) { next if $currentFile =~ /^\.{1,2}$/; if ( lc($currentFile) =~ /.bundle$/ or lc($currentFile) =~ /.dylib$/ or lc($currentFile) =~ /.a$/ or lc($currentFile) =~ /.so$/ or lc($currentFile) =~ /.lib$/ or (-f "$dirName/$currentFile" && $currentFile =~ /^[^.]*$/ && `file "$dirName/$currentFile"` =~ /Mach-O/) ) { print("\tCodesigning ".getShort($currentFile)."\n"); system("/usr/bin/codesign --force --timestamp=none --sign \"".$certificateApplication."\" \"$dirName/$currentFile\""); } if (-d "$dirName/$currentFile") { recursiveCodesign("$dirName/$currentFile"); } } } sub found_app_indir() { opendir(my $dh, '.') || die "cant open dir"; my @list_found = grep { /.app$/ } readdir($dh); my $app_found = @list_found[0]; chop($app_found); chop($app_found);chop($app_found); chop($app_found); return $app_found; } sub getShort() { my $subject = shift; my $search = getcwd . "/"; my $replace = ""; my $pos = index($subject, $search); while($pos > -1) { substr($subject, $pos, length($search), $replace); $pos = index($subject, $search, $pos + length($replace)); } return $subject; }

1) After installing your certifcates, place this script in the same directory as your .app generated by Unity3D

2) Add the optional files in the same directory such as  Info.plist, PlayerIcon.icns,  entitlements.entitlements,  UnityPlayerIcon.png. They will be overridden inside the .app

3) Open a terminal and launch the script ./SignAndPackage.pl

4) Answer the configuration questions and let the script do the job !

 

Note : You can check that your certificates are installed using this command line :

security find-identity -p codesigning

You don’t need to fill the full name of the certifcates when requested. The default values can be good enough. For example if your certificate is called « 3rd Party Mac Developer Installer: MY DEVELOPER NAME (68684684) », you can just enter « 3rd Party Mac Developer Installer ».

 Edit: Version 1.1 now available

Edit: Version 1.3 removed the embedded profile that was crashing the Application Loader

Unity3D – Tips when building your game with an Editor script

, ,

Here are some basic tricks when you need to build your game by code.

First you can launch a build process with a single line of code, for example :

[MenuItem("Exoa/Build/Android")]
public static void PerformBuildAndroid()
{
	string fullPath = Application.dataPath.Replace("/Assets", "/") + "_BUILDS/android/build.apk";
	// Build Game
	BuildPipeline.BuildPlayer(allScenes, fullPath, BuildTarget.StandaloneWindows, BuildOptions.None);
}

For Android

Then you can install your game on the connected Android device like this :

[MenuItem("Exoa/Build/Install build on Android")]
public static void InstallAndroid()
{
	// Run the game (Process class from System.Diagnostics).
	string fullPath = Application.dataPath.Replace("/Assets", "/") + "_BUILDS/android/build.apk"; 
	proc = new System.Diagnostics.Process();
	proc.StartInfo.FileName = "D:/SDK/android/sdk/platform-tools/adb.exe"; // replace with your adb exe path
	proc.StartInfo.Arguments = "-d install -r " + fullPath;
	proc.Start();
}

Then you can launch the application on the android device like this :

[MenuItem("Exoa/Build/Launch on Android")]
public static void LaunchAndroid()
{
	// Run the game (Process class from System.Diagnostics).
	string fullPath = Application.dataPath.Replace("/Assets", "/") + "_BUILDS/android/build.apk";
	string appid = PlayerSettings.bundleIdentifier;
	proc = new System.Diagnostics.Process();
	proc.StartInfo.FileName = "D:/SDK/android/sdk/platform-tools/adb.exe"; // replace with your adb exe path
	proc.StartInfo.Arguments = "shell am start -n " + appid + "/com.unity3d.player.UnityPlayerNativeActivity"; 
	proc.Start();
}

For Desktop

For desktop releases, you can automatically launch the build with the Process() class :

[MenuItem("Exoa/Build/Run Exe %&r")]
public static void RunGame()
{
	string fullPath = Application.dataPath.Replace("/Assets", "/") + "_BUILDS/win/build.exe";

	// Run the game (Process class from System.Diagnostics).
	Process proc = new Process();
	proc.StartInfo.FileName = fullPath;
	proc.Start();
}

Opening build folder

You can finally automatically open the build folder like Unity do :

[MenuItem("Exoa/Build/Open Build Folder")]
public static void OpenBuildFolder()
{
	string fullPath = Application.dataPath.Replace("/Assets", "/") + "_BUILDS/";
	fullPath = fullPath.Replace("/","\\");
	Debug.Log(fullPath);
	proc = new System.Diagnostics.Process();
	proc.StartInfo.FileName = "explorer.exe";
	proc.StartInfo.Arguments = fullPath;
	proc.Start();
}

NSAppTransportSecurity fix for Unity3D and iOS 9

,

If you upgraded to iOS 9, you probably noticed that the HTTP requests inside Unity were returning an error about domain permissions.

If you can’t upgrade to the latest Unity 5 patch adding NSAppTransportSecurity features. You will need to add a few lines of code inside the info.plist file after each build.

 

You will shortly find the need to add it automatically after each build, so I published a short trick for that on GitHub :

 

:: GitHub File ::
/** @author : Anthony KOZAK :: exoa.fr @description : Add your domain to the NSAppTransportSecurity for ios 9 in Unity Add it automatically or manually from a custom editor menu. **/ using System; using UnityEditor; using UnityEngine; using System.Collections.Generic; using System.IO; public class NSAppTransportSecurity { [MenuItem("Exoa/Build/Add NSAppTransportSecurity")] private static void AddNSAppTransportSecurity() { string domain = "yourdomain.com"; string filepath = Application.dataPath.Replace("/Assets", "/") + "_BUILDS/ios/build/Info.plist"; if (File.Exists(filepath)) { StreamReader streamReader = new StreamReader(filepath); string text = streamReader.ReadToEnd(); streamReader.Close(); if (text.IndexOf("NSAppTransportSecurity") < 1) { text = text.Replace("<key>CFBundleDevelopmentRegion</key>", "<key>NSAppTransportSecurity</key>\n<dict>\n<key>NSExceptionDomains</key>\n<dict>\n<key>" + domain + "</key>\n<dict>\n<key>NSIncludesSubdomains</key>\n<true/>\n<key>NSExceptionAllowsInsecureHTTPLoads</key>\n<true/>\n<key>NSExceptionRequiresForwardSecrecy</key>\n<true/>\n<key>NSExceptionMinimumTLSVersion</key>\n<string>TLSv1.2</string>\n<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>\n<true/>\n<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>\n<true/>\n<key>NSThirdPartyExceptionMinimumTLSVersion</key>\n<string>TLSv1.2</string>\n<key>NSRequiresCertificateTransparency</key>\n<false/>\n</dict>\n</dict>\n</dict>\n<key>CFBundleDevelopmentRegion</key>"); File.WriteAllText(filepath, text); Debug.Log("NSAppTransportSecurity Added for domain " + domain); } } } [PostProcessBuild(1080)] public static void OnPostProcessBuild(BuildTarget target, string path) { print("OnPostProcessBuild " + target + " " + path); AddNSAppTransportSecurity(); } }

 

Unity3D Mecanim Hackable TPS Engine

Voici mon dernier plugin en développement. Il s’agit d’un moteur de zombie shooter. Il permet de gérer les armes sur un personnage, le ramassage d’objets, de munitions, le changement de vêtements, et surtout la découpe des personnages par bones.

Ainsi tirer dans les bras coupera le personnage et générera un ragdoll contenant uniquement le bras.
Tirer dans les jambes aura le même effet et lancera également l’animation « ramper » du zombie.

De la même manière, tirer dans la tête décapitera le zombie et lancera une animation aléatoire de mort.

Toutes ces animations sont retargetable, il est donc facile d’introduire des zombies différents une fois le système mis en place.