How to externalize function for parallel processing in PHP - php

I am going to play with parallel processing in PHP. https://www.php.net/manual/en/book.parallel.php
I could make something very basic to understand the main concept.
Here is where I am :
<?php
for ($i = 0; $i < 7; $i++) {
$runtime = new \parallel\Runtime();
$runtimes[] = $runtime;
echo "starting thread $i from main thread" . PHP_EOL;
$future = $runtime->run(function($i){
$nbtot = 0;
echo "I am thread $i " . PHP_EOL;
for ($j = 0; $j < 5; $j++) {
echo "thread $i in loop $j " . PHP_EOL;
$nbsec = rand(0, 10);
$nbtot = $nbtot + $nbsec;
sleep($nbsec);
}
return array($i, $nbtot); //returning an array to the main thread
}, array($i)); //passing argument to the closure
$futures[] = $future;
}
$ct = count($futures);
while ( $ct > 0 ) {
echo "$ct active threads" . PHP_EOL;
foreach ($futures as $key => $future) {
if ($future->done()) {
print_r($future->value());
unset($futures[$key]);
}
}
sleep(2);
$ct = count($futures);
}
?>
For maintenance purpose, I would like to put the code of the function (closure) in another file. I guess that \parallel\bootstrap is made for it, but I can't figure out how to make it work. What should I change my current code ? and what should I place in the other file ?

After some hard time and the support of Joe Watkins, here is the answer I was looking for :
<?php
\parallel\bootstrap('test_threads_inc.php');
for ($i = 0; $i < 7; $i++) {
echo "starting thread $i from main thread" . PHP_EOL;
$futures[] = \parallel\run(function($a) {return myfunction($a);}, array($i)); //passing argument to the closure
}
$ct = count($futures);
while ( $ct > 0 ) {
echo "$ct active threads" . PHP_EOL;
foreach ($futures as $key => $future) {
if ($future->done()) {
print_r($future->value());
unset($futures[$key]);
}
}
sleep(2);
$ct = count($futures);
}
?>
and test_threads_inc.php :
<?php
function myfunction($i) {
$nbtot = 0;
echo "I am thread $i " . PHP_EOL;
for ($j = 0; $j < 5; $j++) {
echo "thread $i in loop $j " . PHP_EOL;
$nbsec = rand(0, 10);
$nbtot = $nbtot + $nbsec;
sleep($nbsec);
}
return array($i, $nbtot); //returning an array to the main thread
}
?>

I wrote this include file test_inc.php :
<?php
$myworker = function($i){
...
return array($i, $nbtot); //returning an array to the main thread
}
?>
and then include it at the beginning of main script : include('test_inc.php');. I could replace the function description by the variable just like this :
$future = $runtime->run($myworker, array($i));

It's possible to work with class inside the Closure function. For that, you need to use require_once inside the function to include them. It's probably possible to include the require_once outside the Closure function if you use a bootstrap

Related

Why can't I use a function to simplify my "for loops"

I build a webpage to crack simple MD5 hash of a four digit pin for fun. The method I used was basically try all combination and check against the MD5 value the user has entered. Below is the PHP code I created to accomplish the goal.
Debug Output:
<?php
$answer = "PIN not found";
if (isset($_GET['md5'])) {
$txt = 'abcdefjhig';
$time_pre = microtime(TRUE);
$value = $_GET['md5'];
$show = 15;
for ($i = 0; $i <= 9; $i++) {
$first = $i;
for ($j = 0; $j <= 9; $j++) {
$second = $j;
for ($k = 0; $k <= 9; $k++) {
$third = $k;
for ($x = 0; $x <= 9; $x++) {
$fourth = $x;
$whole = $first . $second . $third . $fourth;
$check = hash('md5', $whole);
if ($check == $value) {
$answer = $whole;
echo "The pin is $answer";
}
if ($show > 0) {
print"$check $whole \n";
$show = $show - 1;
}
}
}
}
}
echo "\n";
$time_post = microtime(TRUE);
print "Elapsed time:";
print $time_post - $time_pre;
}
?>
Notice that in the middle there are four very similar for loops,I tried to simplify this by using functions, but it just returns one four digit number which is 9999 instead of all of them.
Below is the function I created:
function construct($input){
for($i=0; $i<=9, $i++){
$input=$i;
}
return $input
}
Then I tried to call this function for four times to form all of the four digit numbers but it just gives me 9999. Can anybody help? Thanks a lot.
Try this:
for ($i=0; $i<=9999 ; $i++) {
$whole = sprintf('%04d', $i);
$check=hash('md5', $whole);
if($check==$value){
$answer=$whole;
echo "The pin is $answer";
break; //remove this if you do not want to break the loop here
}
if ($show>0) {
print"$check $whole \n";
$show=$show-1;
}
}
You're using numbers from 0 to 9999, so why just loop through those numbers? You can add zero's by using str_pad() like so:
for ($i = 0; $i <= 9999; $i++) {
$whole = str_pad($i, 4, '0', STR_PAD_LEFT);
}
Also I'd like to mention that you really should think about better formatting of your code, especially indentation

Hackerrank draw a staircase of length N in php

Draw a staircase of height N like this:
#
##
###
####
#####
######
Staircase of height 6, note the last line should have zero spaces.
My solution does not work correctly
function draw($size)
{
for ($i = 1; $i <=$size ; $i++)
{
$spaces = $size-$i;
while ($spaces)
{
echo " ";
$spaces--;
}
$stairs = 0;
while ($stairs < $i)
{
echo "#";
$stairs++;
}
echo "<br/>";
}
}
draw(6);
//output
#
##
###
####
#####
######
It is not printing the spaces, I tried \n, PHP.EOL still it didn't work. Any suggestions?
Although other solutions are all good , here is my code as well.
$max=5;
for ( $i =1 ; $i<=$max;$i++) {
for ( $space = 1; $space <= ($max-$i);$space++) {
echo " ";
}
for ( $hash = 1; $hash <= $i;$hash ++ ) {
echo "#";
}
echo "\n";
}
//PHP
$n = 6; // Number of rows.
for($i=1;$i<=$n;$i++){
echo str_repeat(' ', $n-$i) . str_repeat('#', $i);
echo '\n';
}
for(var i = 0; i < n; i++)
{
var s = "";
for(var j = 0; j < n; j++)
{
if(n - i - 2 < j)
{
s += "#";
}
else
{
s += " ";
}
}
console.log(s);
}
for ($i=0; $i<$n; $i++){
for ($j=0; $j<$n; $j++){
if($i+$j>$n-2){
echo "#";
} else {
echo " ";
}
if($j==$n-1 && $i+$j<$n*2-2){ //The second part is to dont break the last line
echo "\n";
}
}
}
Here's another solution:
$int = 7;
for($i = 1; $i<=$int; $i++){
printf('%1$s%2$s%3$s',str_repeat(" ",$int-$i),str_repeat("#",$i),"\n");
}
From official PHP documentation:
str_repeat
$n = 6;
for ($i = 0; $i < $n; $i++) {
$pad = 1;
for ($space = 0; $space < $n-$i-1; $space++) {
$pad++;
}
echo str_pad('#', $pad,' ',STR_PAD_LEFT);
for ($j = 0; $j < $i; $j++) {
echo '#';
}
echo '<br>';
}
Took me a while but finally I manage to do it following OFC (A. Sharma) Example.
<?php
$handle = fopen("php://stdin","r");
$n = intval(fgets($handle));
for ($rows = 0; $rows < $n; $rows++) {
for ($columns = 0; $columns < $n - $rows - 1; $columns++) {
echo " ";
}
for ($columns = 0; $columns < $rows + 1; $columns++) {
echo "#";
}
echo "\n";
}
?>
Use PHP functions range() and str_repeat() for an elegant solution:
function staircase($n){
foreach (range(1, $n) as $i)
print( str_repeat(' ',$n-$i).str_repeat('#',$i)."\n");
}
demo
Check if n is between 0 and 101 ( 0 < n <= 100)
Loop through each row
2.1 print spaces according to the last item position
2.2 print the items
Separate rows
The code below explains everything...
function staircase($n) {
// check if n is between 0 and 101 (0 < n <=100)
if( 0 < $n && $n > 100 ) {
} else {
// Loop through each row
for($i = 1; $i <= $n; $i++) {
// print spaces according to the last item position
$si = 1;
while( $si <= ($n - $i)){
print(" ");
$si++;
}
// print the items
for($j = 1; $j <= $i; $j++) {
print("#");
}
// separate rows
print("\n");
}
}
}
Output: For n = 6
#
##
###
####
#####
######
After playing around with the code and trying/failing couple of times I finally got it right. Notice how in order to print the space and new line I am using "\n". Previous "<br/>" and " " for space didn't work.
Break line will come out of the loop every row number. So if we have $n=4 then every 4 spaces after break line will be echoed.
I have made 2 loops to fill in all fields in the staircase.
The tricky part here is to have them right aligned. This is where if statement comes in place.
Reference link:
Hackerrank Challenge
// Complete the staircase function below.
function staircase($n) {
for($i=1; $i<=$n; $i++){
for($j=1; $j <= $n; $j++){
if( ($n - $i) < $j ){
echo "#";
}else{
echo " ";
}
}
echo "\n";
}
}
Try This
$n=6;
for($i=1;$i<=$n;$i++){
for($spaces=1;$spaces<=($n-$i);$spaces++){
echo " ";
}
for($staires=0;$staires<$i;$staires++){
echo "#";
}
echo "\n";
}
This worked for me
$n = 6;
function staircase($n) {
for($i=1; $i <= $n; $i++){
for($j=1; $j <= $n; $j++){
if($j > $n-$i){
echo "#";
}else{
echo " ";
}
}
echo "\n";
}
}
Use print(' '), if you want to go to next line put print(' ')."\n"
JavaScript:
Solution:
function StairCase(n){
let x = [];
for(let i = 0; i<n; i++){
while(x.length < n){
x.push(" ");
}
x.shift();
x.push("#");
console.log(x.join(''));
} } //StairCase(6)

How to output arrays in a certain way using PHP?

I'm try to print an array where every other value is reassigned, as examples (from this):
17.34502870451717,62.46137370987033
To this:
62.46137370987033,17.34502870451717
That part have I succeeded with, but now I have this structure:
[62.46137370987033,[17.34501402936927,]
[62.46123453616544,[17.34525377433593,]
[62.4610178881864,[17.34546663705899,]
This is where I get stuck and do not know how to write.
The structure I want looks like this:
[62.392628, 17.309413],
[62.393162, 17.309193],
[62.393403, 17.30922]
Here is my explode.php (GIST)
<?php
$dwarf = "17.34502870451717,62.46137370987033,17.34501402936927,62.46123453616544";
$minion = explode(",",$dwarf);
$wing = "[";
for ($i = 0;$i < count($minion) -1; $i++) {
echo $wing . $minion[$i+1].",";
if($i%2==1) { echo "]<br />"; }
} echo $minion[0] . $wing;
?>
As I understand it, as long as there's always even pairs it should be as easy as;
<?php
$dwarf = "17.34502870451717,62.46137370987033,17.34501402936927,62.46123453616544";
$minion = explode(",",$dwarf);
$eol = '';
for ($i = 0;$i < count($minion) -1; $i+=2) {
echo $eol.'['.$minion[$i+1].','.$minion[$i]."]";
$eol=',<br/>';
}
echo '<br/>';
>>> [62.46137370987033,17.34502870451717],
>>> [62.46123453616544,17.34501402936927]
Try This
$dwarf = "17.34502870451717,62.46137370987033,17.34501402936927,62.46123453616544";
$minion = explode(",",$dwarf);
$wing = "[";
for ($i = 0;$i < count($minion) -1; $i+=2)
{
echo $kk = $wing . $minion[$i+1].",".$minion[$i]."],<br>";
}
Just a small modification to the given answers
$dwarf = "17.34502870451717,62.46137370987033,17.34501402936927,62.46123453616544";
$minion = explode(",",$dwarf);
$str = '';
for ($i = 0;$i < count($minion) -1; $i+=2) {
$str.='['.$minion[$i+1].','.$minion[$i].'],<br/>';
}
echo rtrim($str,','); // to trim ',' at the end

what's wrong with my php codes?

I wanted to convert my Javascript code for creating a triangle to PHP codes, the Javascript codes works but the PHP code doesn't. This is what I have in my PHP codes, I tried to run it but ended up with a fatal error and undefined variable. I understand javascript but not php...
<?php
{
$size = $_POST['size'];
$firstChoice = $_POST['firstChoice'];
$secondChoice = $_POST['secondChoice'];
echo "<textarea>";
$allLines = '';
for ( $i = 1; $i <= $size; $i++ )
{
$oneLine = createLine ( $i, $i % 2 ? $FirstChoice : $secondChoice );
$allLines += $oneLine + "\n";
}
echo "$allLines";
function createLine ($size, $symbol) {
$aLine = '';
for ( $j = 1; $j <= $size; $j++ )
{
echo $aLine += $symbol;
}
echo "$aLine";
echo "</textarea>";
}
?>
It should look like this if size = 5, firstChoice = # and secondChoice = &
#
&&
###
&&&&
#####
What is $createLine ? Looks as if you're trying to use it as a function, but it is not defined anywhere.
Edit:
You need to declare the function in php
function createLine($size, $symbol) {
// code
}
And when you call it, just call it by the name, don't add a $.
$line = createLine($a, $b);
See documentation on php User-defined functions.
Working:
There were a few issues including: string concatenation should be using the . operator not +, a typo in $FirstChoice, and the function needs to be defined before you use it.
<?php
$size = $_POST['size'];
$firstChoice = $_POST['firstChoice'];
$secondChoice = $_POST['secondChoice'];
function createLine($size, $symbol) {
$aLine = '';
for ($j = 1; $j <= $size; $j++) {
$aLine .= $symbol;
}
return $aLine;
}
echo "<textarea>";
$allLines = '';
for ($i = 1; $i <= $size; $i++) {
$oneLine = createLine($i, $i % 2 ? $firstChoice : $secondChoice);
$allLines .= $oneLine . "\n";
}
echo "$allLines";
echo "</textarea>";
?>
Use createLine(...) and not $createLine(...)
I suppose you have javascript function like below
<script>
function createLine (...)
{
...
}
</script>

Fixtures PHP algorithm

Struggling with this tournament fixtures algorithm.
The code is working perfectly but I need help inserting the data to mysql
I cant seem to access the $varables..
any tweaking by a php pro greatly appreciated ...
$teamnames = "Arsenal|Tottenham|Leeds|Man United|Liverpool";
# XXX check for int
print show_fixtures(isset($_GET['teams']) ? nums(intval($_GET['teams'])) : explode("|", trim($teamnames)));
function nums($n) {
$ns = array();
for ($i = 1; $i <= $n; $i++) {
$ns[] = $i;
}
return $ns;
}
function show_fixtures($names) {
$teams = sizeof($names);
print "<p>Fixtures for $teams teams.</p>";
// If odd number of teams add a "ghost".
$ghost = false;
if ($teams % 2 == 1) {
$teams++;
$ghost = true;
}
// Generate the fixtures using the cyclic algorithm.
$totalRounds = $teams - 1;
$matchesPerRound = $teams / 2;
$rounds = array();
for ($i = 0; $i < $totalRounds; $i++) {
$rounds[$i] = array();
}
for ($round = 0; $round < $totalRounds; $round++) {
for ($match = 0; $match < $matchesPerRound; $match++) {
$home = ($round + $match) % ($teams - 1);
$away = ($teams - 1 - $match + $round) % ($teams - 1);
// Last team stays in the same place while the others
// rotate around it.
if ($match == 0) {
$away = $teams - 1;
}
$rounds[$round][$match] = team_name($home + 1, $names)
. " v " . team_name($away + 1, $names);
}
}
// Interleave so that home and away games are fairly evenly dispersed.
$interleaved = array();
for ($i = 0; $i < $totalRounds; $i++) {
$interleaved[$i] = array();
}
$evn = 0;
$odd = ($teams / 2);
for ($i = 0; $i < sizeof($rounds); $i++) {
if ($i % 2 == 0) {
$interleaved[$i] = $rounds[$evn++];
} else {
$interleaved[$i] = $rounds[$odd++];
}
}
$rounds = $interleaved;
// Last team can't be away for every game so flip them
// to home on odd rounds.
for ($round = 0; $round < sizeof($rounds); $round++) {
if ($round % 2 == 1) {
$rounds[$round][0] = flip($rounds[$round][0]);
}
}
// Display the fixtures
for ($i = 0; $i < sizeof($rounds); $i++) {
print "<hr><p>Round " . ($i + 1) . "</p>\n";
foreach ($rounds[$i] as $r) {
print $r . "<br />";
}
print "<br />";
}
print "<hr>Second half is mirror of first half";
$round_counter = sizeof($rounds) + 1;
for ($i = sizeof($rounds) - 1; $i >= 0; $i--) {
print "<hr><p>Round " . $round_counter . "</p>\n";
$round_counter += 1;
foreach ($rounds[$i] as $r) {
print flip($r) . "<br />";
}
print "<br />";
}
print "<br />";
if ($ghost) {
print "Matches against team " . $teams . " are byes.";
}
}
function flip($match) {
$components = split(' v ', $match);
return "$components[1]" . " v " . "$components[0]";
}
function team_name($num, $names) {
$i = $num - 1;
if (sizeof($names) > $i && strlen(trim($names[$i])) > 0) {
return trim($names[$i]);
} else {
return "BYE";
}
}
I'm not entirely sure what you're hung up on (you should really be more specific in your questions, as specified by the FAQ), but I suspect it is a matter of scope.
When you set a variable within a function, that variable is only accessible within that function. For example:
function do_something() {
$a = 'something!';
}
do_something();
echo $a;
This should result in PHP notice telling you that PHP doesn't know what $a is in the scope that it is trying to echo. Now, if I modify this script...
$a = '';
function do_something() {
global $a; // Lets PHP know we want to use $a from the global scope
$a = 'something!';
}
do_something();
echo $a;
This will work and output "something!", because $a is being "defined" in the scope outside of the function.
You can read more about variable scope in the PHP documentation: http://php.net/manual/en/language.variables.scope.php
Now, something else you need to pay attention to is outputting user data. In your script, you take data straight from $_GET and print it out to the page. Why is this bad? Someone could inject some nice JavaScript into your page (or anything they wanted) and steal users' sessions. You should be using htmlspecialchars() any time you need to output a variable. Even if it is just a team name, you never know when some team will stick a ; or < or > or some other reserved character in there.
Finally, I strongly recommend not mixing your logic with your computation. Let your program figure everything out, and then loop through the data for your output. You should be able to save the entire data for this type of problem in a nice associative array, or some crafty object you come up with.

Categories