Reopened: PHP array_shift(); VS reset(); unset(); array_splice(); - php

Reopened:
Since PHP is a server-side language I had the assumption that it didn't matter what browser I used, but apparently not so. I had only been using Google Chrome.
I installed WAMP on my local machine so I can test it locally to see if it did the same as my shared hosting account. Both codes worked the way they should (in Chrome mind you). Then I looked at the exact same code on my shared hosting -- one worked, the other didn't.
I called my shared hosting support and they tried to duplicate the issue and said they weren't finding it. So I tried it in Firefox with them on the line and in IE, lo and behold... it worked perfectly in both just like on WAMP.
This still isn't making much sense to me. I'm using PHP 5.3 on my shared hosting account with a well known hosting company but not getting anywhere because they can't really troubleshoot code. They can replicate the issue but can't answer why. I'm going to try to find out more in the next weeks and post an update as I know more.
What I'm trying to do is this:
Generate a range of numbers
Shuffle them into a random order
Copy that array of randomly ordered numbers into a session array
Get the first value of the array, delete that value, and shift all
the values down by one
Here's my issue:
I tried using array_shift(); and it worked fine the first run but each time I ran the code after it would remove the first two elements.
To test what was going on I tried to print the array first, do array_shift();, and then print the array again to see what happened.
Expected Results:
Run #1:
[0]=>5 [1]=>2 [2]=>1 [3]=>4 [4]=>3 //print_r($array);
//execute array_shift($array);
[0]=>2 [1]=>1 [2]=>4 [3]=>3 //print_r($array);
Run#2:
[0]=>2 [1]=>1 [2]=>4 [3]=>3 //print_r($array);
//execute array_shift($array);
[0]=>1 [1]=>4 [2]=>3 //print_r($array);
Actual Results:
Run #1:
[0]=>5 [1]=>2 [2]=>1 [3]=>4 [4]=>3 //print_r($array);
//execute array_shift($array);
[0]=>2 [1]=>1 [2]=>4 [3]=>3 //print_r($array);
Run#2:
[0]=>1 [1]=>4 [2]=>3 //print_r($array);
//execute array_shift($array);
[0]=>4 [1]=>3 //print_r($array);
My issue (cont.)
So then I tried using reset($array);, unset($array[0]);, and array_splice($array,1,0); as an alternative to array_shift($array); and it worked! Then I tried to compare them side by side
and cleaned up the code and now they are doing the opposite of each other. Sometimes reset, unset, and array_shift; will even jump through up to 7 cells in the array when called once. array_shift(); is working the way I want it to now but I want to know why. It's driving me nuts! If someone could please help me I'd be so appreciative.
Code Dump:
unset, reset, splice
<?php
session_start();
$min = A;
$max = S;
if((!isset($_SESSION['image'])) || ($_SESSION['image'] == null))
{
$numbers = range($min, $max); //set a range for all images
shuffle($numbers); //shuffle the order for randomness
$_SESSION['image'] = $numbers;
echo "<br />Current value: " . $_SESSION['image'][0] . "<br />";
print_r($_SESSION['image']);
reset($_SESSION['image']);
unset($_SESSION['image'][0]);
array_splice($_SESSION['image'],1,0);
echo "<br />New value: " . $_SESSION['image'][0] . "<br />";
echo "<br />1st exec<br />";
}
else
{
echo "<br />Current value: " . $_SESSION['image'][0] . "<br />";
print_r($_SESSION['image']);
reset($_SESSION['image']);
unset($_SESSION['image'][0]);
array_splice($_SESSION['image'],1,0);
echo "<br />New value: " . $_SESSION['image'][0] . "<br />";
echo "<br />2nd exec<br />";
}
?>
shift
<?php
session_start();
$min = A;
$max = S;
if((!isset($_SESSION['id2'])) || ($_SESSION['id2'] == null))
{
$numbers = range($min, $max); //set a range for all images
shuffle($numbers); //shuffle the order for randomness
$_SESSION['id2'] = $numbers;
echo "<br />Current value: " . $_SESSION['id2'][0] . "<br />";
print_r($_SESSION['id2']);
array_shift($_SESSION['id2']);
echo "<br />New value: " . $_SESSION['id2'][0] . "<br />";
echo "<br />1st execution<br />";
}
else
{
echo "<br />Current value: " . $_SESSION['id2'][0] . "<br />";
print_r($_SESSION['id2']);
array_shift($_SESSION['id2']);
echo "<br />New value: " . $_SESSION['id2'][0] . "<br />";
echo "<br />2nd execution<br />";
}
?>

To ultimately learn what's going on, I propose to register a tick-function. The tick-function can execute at each PHP statement execution.
Here's a simple one, which traces line/file of each statement (feel free to add further details):
// Execute at each single statement
declare(ticks=1);
// Function to get called at each executing statement
function logEachStatement() {
$traceInfo = debug_backtrace();
$lastActivation = $traceInfo[ count( $traceInfo ) - 1 ];
$info = "\n"
. $lastActivation[ 'line' ] . '#' . $lastActivation[ 'file' ]
;
$targetFile = dirname( __FILE__ ) . '/stmnt.log' );
file_put_contents( $targetFile, $info, FILE_APPEND );
}
// using a function as the callback
register_tick_function( 'logEachStatement', true );
While there are other options to track down the problem, this one does not require external infrastructure.

Assuming that you pasted the actual code, the only way for this to happen is if you made an unintentional intermediate request. It would be impossible for us to determine how or why this is the case with only the given information, though.
My suggestion is to use your browser dev tool of choice (e.g. Firebug) and monitor the network tab to make sure that only one request is being sent to the script. If this doesn't turn up your problem, add some simple debug logging, such as this:
$log = date('Y-m-d H:i:s')
. ' :: Request received from '
. $_SERVER['REMOTE_ADDR']
. "\n";
file_put_contents('/path/to/your/log/file', $log, FILE_APPEND);
Then check your log after your test to make sure only one entry was added.

Related

splitting a large array() on a specific index

I have a form on my site for the users to post a results report into,
the report looks like this:
Nojoks's Tourney Bracket Tool Version 1.2.1.84
Tournament: 3/5 Backgammon 1:00pm
Date: 01/22/2017
Day: Sunday
Scheduled Start: 1.00pm PST
Actual Start: 20:00:30
Closed: 20:11:00
Host: Waiter ()
Number of Players: 15
1st place: poppop
1st place email: bobmitch1170#gmail.com
2nd place: Sarge
2nd place email: rgarvey5#hotmail.com
3rd place: Litigolfer
3rd place email: dostrow2008#gmail.com
3rd place: PhantomMask
3rd place email:
START POINTS
burnieboy 5
EU_BNL_Chris1 5
EU_IT_VIANG 5
GennaLee 5
happybear 5
MC_Vicky 5
merceaviles 5
MRC_cadet 5
poeticfool 5
UBG_Angel_D_8 5
UBG_sara1smoon 5
Litigolfer 60
PhantomMask 60
Sarge 90
poppop 120
STOP POINTS
this report is going to be identical everytime with some minor changes
I have already split this into an array with explode
$records = explode( PHP_EOL, $_POST['points'] );
$records = array_map('htmlspecialchars', $records );
$records = array_map ('trim', $records);
Then i have work on collecting the information from the top of the report like so:
// Get Date
$date = substr($records[2], 7, 10);
echo "<b>Tournament Date: </b>" . $date . "<br />";
// Get star time
$start_time = substr($records[4], 18, 7);
echo "<b>Tournament Start Time: </b>" . $start_time . "<br />";
now i need to work on everything from $records[20] down
what i need to do is simple enough i just do not know how to get to the correct part of my array first
I used to ask my users to post only the information from the START POINTS line down to STOP POINTS so to get my information out and split was simple i used:
foreach( $records as $record ) {
$lastSpace = strrpos( $record, ' ' );
$player = trim( substr( $record, 0, $lastSpace ) );
$points = trim( substr( $record, $lastSpace+1 ) );
this code will still work in this case if i can drop the index's 0 - 19 or just split the array into a new array $records1
P.S its this section in the report that is ever changing so to speak this report is from a online tournament hosting tool and each tournament has no set amount of players it can range from 8 upwards
I'm not sure I understand what you need. Perhaps something like this?
The idea is that you search for the indexes in the array which contain the start and end of the points and do a for loop to iterate only over those points.
$start = array_search("START POINTS", $records);
$end = array_search("END POINTS", $records);
$playerArray = [];
for ($i = $start+1;$i < $end;$i++) {
$parts = explode(" ",$records[$i]);
$player = $parts[0];
$points = $parts[1];
$playerArray = [ "player" => $player, "points" => $points ];
}
I managed to work this problem out for myself with thanks to #apokryfos your code still did not do quiet what i wanted so i used your codes and added them into what i have now,
Here is what i came up with:
// New try to split a full report in one go.
$points = $date = $day = $start_time = $host = $number_of_players = $fp_name = $fp_email = $sp_name = $sp_email = "";
// Explode the string at the end of each line,
// array map and remove any special chars then trim white space.
$records = explode( PHP_EOL, $_POST['points'] );
$records = array_map('htmlspecialchars', $records );
$records = array_map ('trim', $records);
// now each line of the NJ's report is in an array, call the array $records[index number]
// use substr( , , ) to find the needed part of the array indexs,
// I.E in the array $records on line 2 is the Date the actual needed information is the date dd/mm/yyyy,
// so we use $date = substr($records[2], 7, 10);
// from this string : Date: 01/18/2017 which is line 2 in records we get the 01/18/2017
// Get Date
$date = substr($records[2], 7, 10);
echo "<b>Tournament Date: </b>" . $date . "<br />";
// Get star time
$start_time = substr($records[4], 18, 7);
echo "<b>Tournament Start Time: </b>" . $start_time . "<br />";
// get Host name
$host = substr($records[7], 7);
echo "<b>Tournament Host: </b>" . $host . "<br />";
// get number of players
$number_of_players = substr($records[8], 20);
echo "<b> Number Of Players: </b>" . $number_of_players . "<br />";
echo "<br />";
// get the first place name and email address
$fplaceName = substr($records[10], 12);
echo "<b>1ST place: </b>" . $fplaceName . "<br />";
$fplaceEmail = substr($records[11], 18);
echo "<b>1ST place Email: </b>" . $fplaceEmail . "<br />";
// Get second place name and email
$splaceName = substr($records[12], 12);
echo "<b>2ND place Email: </b>" . $splaceName . "<br />";
$splaceEmail = substr($records[13], 18);
echo "<b>2ND place Email: </b>" . $splaceEmail . "<br />";
// get third place name and email
$tplaceName = substr($records[14], 12);
echo "<b>3RD place Email: </b>" . $tplaceName . "<br />";
$tplaceEmail = substr($records[15], 18);
$t1placeEmail = "fake#fake.com";
if($tplaceEmail == "") { // if third place email is empty add a generic fake email else continue as normal
$tplaceEmail = $t1placeEmail;
} ;
echo "<b>3RD place Email: </b>" . $tplaceEmail . "<br />";
echo "<hr /><br /><br />";
// Getting the players and points.
$parts1 = array_slice($records, 20, -1);
$end = array_pop($parts1);
$records = array_map('htmlspecialchars', $records );
$records = array_map ('trim', $records);
foreach( $parts1 as $record ) {
$lastSpace = strrpos( $record, ' ' );
$player = trim( substr( $record, 0, $lastSpace ) );
$points = trim( substr( $record, $lastSpace+1 ) );
echo $player . " " . " " . " " . $points . "<hr /><br />";
}
so what happens is, some user pastes the report as above in my original post,
and hits submit,
the form posts to my processing.php page,
I explode the whole post "string" into an array $records,
array_map the htmlspecialchars and trim the records,
then there is all the codes to extract the Date, time, host, number of players,
Then we get the 1st, 2nd, 3rd names and email address's,
then we get to sorting the playernames and points,
array_slice from the line after STOP POINTS index[20] also -1 for the STOP POINTS index,
pop the last line from the array "STOP POINTS" gone,
re do the array_map's on the new array,
run a foreach loop on the new array using a lastSpace strpos " " and the new array
then split player name from points....
if i run the finished code on the report given in my original post you get the following output:
Music Cafe Tournament Date: 01/22/2017 Tournament Start Time: 1.00pm
Tournament Host: Waiter () Number Of Players: 15
1ST place: poppop 1ST place Email: bobmitch1170#gmail.com 2ND place
Email: Sarge 2ND place Email: rgarvey5#hotmail.com 3RD place Email:
Litigolfer 3RD place Email: dostrow2008#gmail.com
burnieboy 5
EU_BNL_Chris1 5
EU_IT_VIANG 5
GennaLee 5
happybear 5
MC_Vicky 5
merceaviles 5
MRC_cadet 5
poeticfool 5
UBG_Angel_D_8 5
UBG_sara1smoon 5
Litigolfer 60
PhantomMask 60
Sarge 90
poppop 120
of course with the rule separating each name and points,
which is what i needed and now i can add all my sql statements and bingo.
please if anyone can see an easier or better way to achieve this goal i would love to see your edits and test them out

How a string of text every other two lines in a foreach loop in PHP? (retrieving records from a database)

I am working on a "boxing records" database for a school project. The loop retrieves records from a SQL statement. I want to add a "VS" string of text between every other two lines in order to show records outputted somewhat like this.
Upcoming Fights
Sergey Kovalev (28-0-25)
VS
Jean Pascal (30-3-17)
Another Boxer (123-0-5)
VS
Some Boxer (123-3-1)
However, my current loop outputs like this
Sergey Kovalev (28-0-25)
VS
Jean Pascal (30-3-17)
VS
Another Boxer (123-3-1)
VS
Some Other Boxer (123-3-1)
VS
The loop I currently have is the following
foreach($records as $record) {
$i = 0;
echo $record['name'] . " (" . $record['wins'] . "-" . $record['losses'] . "-" . $record['kos'] . ")" . "<br>";
$i=$i*2;
if($i%2 == 0)
{
echo "VS <br/>";
}
else{
echo "<br />";
}
I know I could probably change the SQL in order to display two fighters in the same row, and then append "vs" on the echo, but I thought that just modifying the for loop would work by using a variable counter $i. I thought it would be pretty easy to make the "VS" appear between every two rows but im missing something in my logic.
You need to increment value of $i by one rather than multiplying it by 2 and initialize $i outside foreach loop.
$i = 0; // Initialize counter here
foreach($records as $record) {
echo $record['name'] . " (" . $record['wins'] . "-" . $record['losses'] . "-" . $record['kos'] . ")" . "<br>";
if($i%2 == 0)
{
echo "VS <br/>";
}
else
{
echo "<br />";
}
$i++; // Increment counter here
}

unexpected result in php output with larger strings

I am trying to create a binary/hexadecimal converter to convert a denary(base 10) number/value into binary and hexadecimal.
It works fine so far for binary until the input from the form is greater than 11 digits and over(string length), ruffly as it seems to variety. after 11 digits it starts adding " - " into the outcome. Im not sure were this is coming from as I don't have an " - " in the code.
I wasn't sure if this was something to do with large integers as I saw some other questions on that topic(not in php however it was java, so not sure if there is something simpler in php)
That said I was under the impression that form inputs were always strings.
To test if a variable is a number or a numeric string (such as form input, which is always a string), you must use is_numeric(). - from : http://www.php.net/manual/en/function.is-float.php
(haven't yet got to hexadecimal but needed to mention it as some of the following code contains parts for it.)
here is the php code (note: I do check user input just not added it yet)
$inpu = $_POST['number'];
$numinput = $_POST['number'];
if (is_numeric($numinput))
{
while ($numinput >= 1)
{
$binary .= $numinput % 2;
$numinput = $numinput / 2;
}
$mult = strlen($binary) % 4;
echo gettype($numinput) . "<br />";
echo gettype($binary) . "<br />";
echo gettype($mult) . "<br />";
echo $mult . "<br />";
while ($mult < 4)
{
$binary.= "0";
$mult++;
}
$revbinary = strrev($binary);
echo $inpu . " in binary = " . $revbinary ;
echo "<br /> <br />";
echo chunk_split($revbinary, 4);
echo "<br />" . gettype($revbinary) . "<br />";
echo gettype($inpu) . "<br />";
}
else
{
if (is_numeric($numinput))
{
echo "$numinput is over the max value of 255";
}
else
{
echo "your entry is not a vaild number <br />";
echo $numinput;
}
}
Im not looking for completed version of this code as you would ruin my fun, I am just wondering why there is a "-" being entered after 11 digits or so. It also did't add the symbol before I added :
$mult = strlen($binary) % 4;
echo $mult . "<br />";
while ($mult < 4)
{
$binary.= "0";
$mult++;
}
This was to split the binary into 4s ( 0011 1101 0010 0110 ).
Edit: wondered if this would be useful:
echo gettype($numinput); result double
echo gettype($binary); result string
echo gettype($mult); result integer
gettype($revbinary); result string
echo gettype($inpu); result string
still trying to work this out myself.
Any advice is much appreciated Thanks
I would suggest simply using decbin() and dechex(). Those are functions included in php, which do exactly what you're trying to accomplish.
You might want to check if it is a number first (like you are already doing).
Then cast it to an integer (through intval()) and then apply decbin() and dechex()
http://php.net/manual/de/function.decbin.php
http://www.php.net/manual/de/function.dechex.php
http://php.net/manual/de/function.intval.php

combining arrays to get 3rd array value

I am doing a profile quiz. This is just an example of code. Ultimately I will do a loop for all possible combinations. Basically, if the student chooses answer 3 to question 1 (what is your height - small, medium, large, xl, xxl) I want their pgheight to be stored as 4, sgheight as 9, cheight as 4, etc... My final array will consist of 16 $pos and 16 $attr with 5 scores for each combination. Hope this makes sense. Thanks for any help.
e.g.
function height(){
$pos=array("pg","sg","c");
$attr=array("height","weight","strength");
$pgheight=array(1,2,3,4,5);
$sgheight=array(6,7,8,9,10);
$cheight=array(1,2,3,4,5);
$ans=3;
$i=0;
// THIS IS THE CODE THAT DOESN'T SEEM TO WORK.
// My logic is $pgheight=$pgheight[3];
$pos[$i].$attr[$i]=$pos[$i].$attr[$i]."[".$ans."]";
echo $pgheight;
}
you either want to eval the statement or use two dollar signs. you're reusing the variable pgheight so its a bit confusing. let me give you an example instead.
$fruit = array("apples", "oranges", "pears");
$drinks = array("beer", "cider", "wine");
$krislikes = "drinks";
$whichone = 0;
echo "Kris likes " . ${$krislikes}[$whichone] . "<br>";
// or
$answer = $$krislikes;
echo "Kris likes " . $answer[$whichone] . "<br>";
// or
eval('$the_answer=$' . $krislikes . '[' . $whichone . '];');
echo "Kris likes " . $the_answer . "<br>";
hope that helps.

Convert EXIF data to how it should looks like

According to PHP, the EXIF information for a image is 20/10 for F-number, 51/10 for focal length, and 10/150 for exposure. This is not how these values should look like! It should looks like F/2 for F-number, 5, mm for focal length, and 1/150 for exposure. These values are just some examples! Please see this link for how I really mean how it should looks like. Note that I will not use any third party software! Just pure PHP.
Is it possible to convert these values (for example 20/10) to the real values (for example F/2) in PHP? If yes, how can I convert them?
Thanks in advance.
EDIT
The following code convert 150/10 to 150 seconds which is 2 minutes and 30 seconds. This is wrong because I took the photo with 15 seconds shutter. How can I make it to calculate to the correct amount of seconds?
list($d1, $d2) = str_split('/', 'P1220379.JPG');
if($d1 > 0 AND $d2 > 0) {
$e = $d1 / $d2;
} else {
$e = 'P1220379.JPG';
}
if($e < 1 AND $e > 0) {
$e = '1/'.round(1 / $e, 0).' sekunder';
} else {
$e = round($e, 1).' sekunder';
}
"drpain" on this link says
Please note that when resizing images with GD and most image
processing scripts or applications you will loose the EXIF
information.What I did as a workaround is book this information into
MySQL before I re-size images.
His little program below
<?php
$camera = cameraUsed("/img/myphoto.jpg");
echo "Camera Used: " . $camera['make'] . " " . $camera['model'] . "<br />";
echo "Exposure Time: " . $camera['exposure'] . "<br />";
echo "Aperture: " . $camera['aperture'] . "<br />";
echo "ISO: " . $camera['iso'] . "<br />";
echo "Date Taken: " . $camera['date'] . "<br />";
?>
does produce these numbers in correct format, according to him
Will display the following, depending on the data:
Camera Used: SONY DSC-S930
Exposure Time: 1/400
Aperture: f/4.3
ISO: 100
Date Taken: 2010:12:10 18:18:45
This is my solution in kotlin if anyone needs
fun convertShutterSpeed(value: String?): String {
if (value.isNullOrBlank()) {
return ""
}
val split = value.split("/")
val ed: Float = split[0].toFloat()
val ed1: Float = split[1].toFloat()
val fl = ed / ed1
return if (ed < 0) {
Math.round(1 / Math.pow(2.toDouble(), fl.toDouble())).toString() + "s"
} else {
"1/" + Math.round(Math.pow(2.toDouble(), fl.toDouble()))
}
}
And here are some tests
#Test
fun convertShutterSpeed() {
assertEquals("1/8", imageExif.convertShutterSpeed("3/1"))
assertEquals("1/10", imageExif.convertShutterSpeed("3321928/1000000"))
assertEquals("1/20", imageExif.convertShutterSpeed("4321928/1000000"))
assertEquals("1/125", imageExif.convertShutterSpeed("6965784f/1000000"))
assertEquals("1/250", imageExif.convertShutterSpeed("7965784/1000000"))
assertEquals("1/320", imageExif.convertShutterSpeed("8321928/1000000"))
assertEquals("1/400", imageExif.convertShutterSpeed("8643856/1000000"))
assertEquals("1/640", imageExif.convertShutterSpeed("9321928/1000000"))
assertEquals("1/800", imageExif.convertShutterSpeed("9643856/1000000"))
assertEquals("1/1000", imageExif.convertShutterSpeed("9965784/1000000"))
assertEquals("2s", imageExif.convertShutterSpeed("-1/1"))
assertEquals("6s", imageExif.convertShutterSpeed("-2584963/1000000"))
}
Values that I got is from Canon images, but it works for other camera models as well.

Categories