How can I validate a Vehicle Identification Number with PHP? I just need to check if the entered VIN number is correct or not.
Here's something I wrote up real quick using the example in the wikipedia article.
Not guaranteed perfect or bug free or super efficient, but should provide you with a solid starting point:
Note: I included the edits provided by Confluence below, making the procedure slightly more succinct.
function validate_vin($vin) {
$vin = strtolower($vin);
if (!preg_match('/^[^\Wioq]{17}$/', $vin)) {
return false;
}
$weights = array(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2);
$transliterations = array(
"a" => 1, "b" => 2, "c" => 3, "d" => 4,
"e" => 5, "f" => 6, "g" => 7, "h" => 8,
"j" => 1, "k" => 2, "l" => 3, "m" => 4,
"n" => 5, "p" => 7, "r" => 9, "s" => 2,
"t" => 3, "u" => 4, "v" => 5, "w" => 6,
"x" => 7, "y" => 8, "z" => 9
);
$sum = 0;
for($i = 0 ; $i < strlen($vin) ; $i++ ) { // loop through characters of VIN
// add transliterations * weight of their positions to get the sum
if(!is_numeric($vin{$i})) {
$sum += $transliterations[$vin{$i}] * $weights[$i];
} else {
$sum += $vin{$i} * $weights[$i];
}
}
// find checkdigit by taking the mod of the sum
$checkdigit = $sum % 11;
if($checkdigit == 10) { // checkdigit of 10 is represented by "X"
$checkdigit = "x";
}
return ($checkdigit == $vin{8});
}
Note: there is a small percent error with verifying VINs because of the nature of the checksum:
...a match does not prove the VIN is correct, because there is still a 1 in 11 chance of any two distinct VINs having a matching check digit.
Also note: 11111111111111111 will validate against the procedure above. Whether or not you want to check for that is up to you:
Straight-ones (seventeen consecutive '1's) will suffice the check-digit. This is because a value of one, multiplied against 89 (sum of weights), is still 89. And 89 % 11 is 1, the check digit. This is an easy way to test a VIN-check algorithm.
reference: http://en.wikipedia.org/wiki/Vehicle_identification_number#Check_digit_calculation
Here's a version of the code by jordan ported to Javascript, hope it's helpful to someone...
function validate_vin(vin)
{
function isnumeric(mixed_var) {
return (typeof(mixed_var) === 'number' || typeof(mixed_var) === 'string') && mixed_var !== '' && !isNaN(mixed_var);
}
var pattern = /^[^\Wioq]{17}$/;
var weights = Array(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2);
var transliterations = {
"a" : 1, "b" : 2, "c" : 3, "d" : 4,
"e" : 5, "f" : 6, "g" : 7, "h" : 8,
"j" : 1, "k" : 2, "l" : 3, "m" : 4,
"n" : 5, "p" : 7, "r" : 9, "s" : 2,
"t" : 3, "u" : 4, "v" : 5, "w" : 6,
"x" : 7, "y" : 8, "z" : 9
};
vin = vin.toLowerCase();
if(!vin.match(pattern)) { return false; }
var sum = 0;
for(var i=0; i<vin.length; i++) {
if(!isnumeric(vin.charAt(i))) {
sum += transliterations[vin.charAt(i)] * weights[i];
} else {
sum += parseInt(vin.charAt(i)) * weights[i];
}
}
var checkdigit = sum % 11;
if(checkdigit == 10) { // check digit of 10 represented by X
checkdigit = 'x';
}
return (checkdigit == vin.charAt(8));
}
It's "VIN." "VIN Number" = "Vehicle Identification Number Number," which doesn't make sense.
You can see a definition of the structure of VINs here:
http://en.wikipedia.org/wiki/Vehicle_identification_number
And you can work from there, or you can grab this script here:
http://www.geekpedia.com/code29_Check-if-VIN-number-is-valid.html
Here is an improved version of the function posted by jordan:
$vin = "1M8GDM9AXKP042788";
function validate_vin($vin) {
$vin = strtolower($vin);
if (!preg_match('/^[^\Wioq]{17}$/', $vin)) {
return false;
}
$weights = array(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2);
$transliterations = array(
"a" => 1, "b" => 2, "c" => 3, "d" => 4,
"e" => 5, "f" => 6, "g" => 7, "h" => 8,
"j" => 1, "k" => 2, "l" => 3, "m" => 4,
"n" => 5, "p" => 7, "r" => 9, "s" => 2,
"t" => 3, "u" => 4, "v" => 5, "w" => 6,
"x" => 7, "y" => 8, "z" => 9
);
$sum = 0;
for($i = 0 ; $i < strlen($vin) ; $i++ ) { // loop through characters of VIN
// add transliterations * weight of their positions to get the sum
if(!is_numeric($vin{$i})) {
$sum += $transliterations[$vin{$i}] * $weights[$i];
} else {
$sum += $vin{$i} * $weights[$i];
}
}
// find checkdigit by taking the mod of the sum
$checkdigit = $sum % 11;
if($checkdigit == 10) { // checkdigit of 10 is represented by "X"
$checkdigit = "x";
}
return ($checkdigit == $vin{8});
}
I recently had to write a VIN validation class with PHP. I posted my class for everyone to use at:
http://dev.strategystar.net/2012/05/validate-vin-checksum-with-php/
class VIN
{
public static $transliteration = array(
'A'=>1, 'B'=>2, 'C'=>3, 'D'=>4, 'E'=>5, 'F'=>6, 'G'=>7, 'H'=>8,
'J'=>1, 'K'=>2, 'L'=>3, 'M'=>4, 'N'=>5, 'P'=>7, 'R'=>9,
'S'=>2, 'T'=>3, 'U'=>4, 'V'=>5, 'W'=>6, 'X'=>7, 'Y'=>8, 'Z'=>9,
);
public static $weights = array(8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2);
/***
* The checksum method is used to validate whether or not a VIN is valid
* It will return an array with two keys: status and message
* The "status" will either be boolean TRUE or FALSE
* The "message" will be a string describing the status
*/
public static function checksum($vin)
{
$vin = strtoupper($vin);
$length = strlen($vin);
$sum = 0;
if($length != 17)
{
return array('status'=>false, 'message'=>'VIN is not the right length');
}
for($x=0; $x<$length; $x++)
{
$char = substr($vin, $x, 1);
if(is_numeric($char))
{
$sum += $char * self::$weights[$x];
}
else
{
if(!isset(self::$transliteration[$char]))
{
return array('status'=>false, 'message'=>'VIN contains an invalid character.');
}
$sum += self::$transliteration[$char] * self::$weights[$x];
}
}
$remainder = $sum % 11;
$checkdigit = $remainder == 10 ? 'X' : $remainder;
if(substr($vin, 8, 1) != $checkdigit)
{
return array('status'=>false, 'message'=>'The VIN is not valid.');
}
return array('status'=>true, 'message'=>'The VIN is valid.');
}
}
Note that the wiki says:
"A check-digit validation is used for all road vehicles sold in the United States and Canada."
So if you're working with other countries you might want to loosen the check-digit validation
https://www.olschimke.eu/2012/08/02/dealing-with-vehicle-identification-numbers-vin-data-quality/
had some good tips.
Thanks to all for the algorithm etc. which I see is on Wikipedia. This is the version I put together based on the comments above. Note, there are problems with the versions above, for ex this 00000000000354888 returns OK for a vin. I took what was above and added an option to check year first if <1980, assume it isn't a 17digit real vin (have to), and also if there are sequences of a single character, assume invalid. This is good enough for my needs as I am comparing against values that are filled with 0s if not 17 in length. Also I know the year value so if I check that I can speed up the code by skipping the vin check (yes I could have put that in before the function) lol bye!.
<?php
/*
=======================================================================================
PURPOSE: VIN Validation (Check-digit validation is compulsory for all road vehicles sold in North America.)
DETAILS: Validates 17 digit VINs by checking their formatting
USAGE: returns boolean or returns an array with a detailed message
COMMENTS: This could be made more robust by checking the country codes etc..
MORE INFO: https://en.wikipedia.org/wiki/Vehicle_identification_number
=======================================================================================
*/
class vinValidation {
public static $transliteration = array(
'A'=>1, 'B'=>2, 'C'=>3, 'D'=>4, 'E'=>5, 'F'=>6, 'G'=>7, 'H'=>8,
'J'=>1, 'K'=>2, 'L'=>3, 'M'=>4, 'N'=>5, 'P'=>7, 'R'=>9,
'S'=>2, 'T'=>3, 'U'=>4, 'V'=>5, 'W'=>6, 'X'=>7, 'Y'=>8, 'Z'=>9,
);
public static $weights = array(8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2);
public function validateVIN($vin, $ret_array_status = false, $year = null) {
//validates US/NA 1980>= VINs, if before 1980, no vin standards, this returns false
if (!empty($year) && preg_match("/^[0-9]{4}/", $year)) {
if ($year < 1980) return ($ret_array_status ? array('status' => false, 'message' => 'Unable to check VIN, pre-dates 1980.') : false);
}
$vin_length = 17; // US vin requirements >= 1980
$vin = strtoupper(trim($vin));
$sum = 0;
//if (!preg_match('/^[^\Wioq]{17}$/', $vin))
//return ($ret_array_status ? array('status'=>false, 'message'=>'VIN is not valid, not the right length.') : false);
if (!preg_match('/^[A-HJ-NPR-Z0-9]{17}$/', $vin))
return ($ret_array_status ? array('status'=>false, 'message'=>'VIN is not valid, VIN formatting is incorrect.') : false);
if (preg_match('/(\w)\1{5,}/', $vin))
return ($ret_array_status ? array('status'=>false, 'message'=>'VIN contains invalid repeating character sequence.') : false);
for($x=0; $x < $vin_length; $x++) {
$char = substr($vin, $x, 1);
if(is_numeric($char)) {
$sum += $char * self::$weights[$x];
} else {
if(!isset(self::$transliteration[$char]))
return ($ret_array_status ? array('status'=>false, 'message'=>'VIN contains an invalid character.') : false);
$sum += self::$transliteration[$char] * self::$weights[$x];
}
}
$remainder = $sum % 11;
$checkdigit = $remainder == 10 ? 'X' : $remainder;
//echo " sum:".$sum." remain:".$remainder." check dig:".$checkdigit."\n";
if(substr($vin, 8, 1) != $checkdigit)
return ($ret_array_status ? array('status'=>false, 'message'=>'The VIN is not valid, failed checksum.') : false);
// all is good return true or a value and status.
return ($ret_array_status ? array('status'=>true, 'message'=>'The VIN is valid, passed checksum.') : true);
}
}
TESTING :
$vinClass = new vinValidation();
// not long enough not val
var_dump($vinClass->validateVIN('1I345678123456789', false, 2000));
var_dump($vinClass->validateVIN('1I345678123456789'));
echo "-----------------------------------------------------------\n";
// not valid
var_dump($vinClass->validateVIN('00000000012870842', true));
var_dump($vinClass->validateVIN('00000000012870842', 1968)); //assumes faulty by year
var_dump($vinClass->validateVIN('00000000012870842'));
echo "-----------------------------------------------------------\n";
// not valid
var_dump($vinClass->validateVIN('00000000000354888', true));
var_dump($vinClass->validateVIN('00000000000354888'));
echo "-----------------------------------------------------------\n";
// Fails Checksum test
var_dump($vinClass->validateVIN('368TU79MXH4763452',false,2000));
var_dump($vinClass->validateVIN('368TU79MXH4763452'));
echo "-----------------------------------------------------------\n";
// yachtzee, (returns true or array) !
var_dump($vinClass->validateVIN('WP1AF2A56GLB91679',true));
var_dump($vinClass->validateVIN('WP1AF2A56GLB91679'));
Here is the JavaScript class version as posted by Mike Q:
class VIN {
static transliteration = {
'A':1, 'B':2, 'C':3, 'D':4, 'E':5, 'F':6, 'G':7, 'H':8, 'J':1, 'K':2, 'L':3, 'M':4, 'N':5, 'P':7, 'R':9, 'S':2, 'T':3, 'U':4, 'V':5, 'W':6, 'X':7, 'Y':8, 'Z':9
}
static weights = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2];
validateVIN(vin, retArrayStatus = false, year = null) {
if (year != null && year.match(/^[0-9]{4}/)) {
if (year < 1980)
return retArrayStatus ? {'status': false, 'message': 'Unable to check VIN, pre-dates 1980.'} : false;
}
let vinLength = 17;
vin = vin.trim();
let sum = 0;
if (!vin.match(/^[A-HJ-NPR-Z0-9]{17}$/))
return retArrayStatus ? {'status': false, 'message': 'VIN is not valid, VIN formatting is incorrect [i, o, q].'} : false;
//if (!vin.match(/(\w)\1{5,}/))
// return retArrayStatus ? {'status': false, 'message': 'VIN contains invalid repeating character sequence.'} : false;
for (let x = 0; x < vinLength; x++) {
let char = vin.substr(x, 1);
if (!isNaN(char)) {
sum += char * VIN.weights[x];
}
else {
if (VIN.transliteration[char] == '')
return retArrayStatus ? {'status': false, 'message': 'VIN contains an invalid character.'} : false;
sum += VIN.transliteration[char] * VIN.weights[x];
}
}
let reminder = sum % 11;
let checkdigit = reminder == 10 ? 'X' : reminder;
if (vin.substr(8, 1) != checkdigit)
return retArrayStatus ? {'status': false, 'message': 'The VIN is not valid, failed checksum.'} : false;
return retArrayStatus ? {'status': true, 'message': 'The VIN is valid, passed checksum.'} : true;
}
}
Related
I am trying to create a mathematical function (in PHP) that will take a given number of Kg, and convert them to a readable form or better yet, return the unit best suited for that amount. The input will always be kg. Preferably log.
For example:
5 kg = (5) kg
0.5 kg = (500) gm
1000 kg = (1) tonne
0.001 kg = (1) gm
0.0001 kg = (100) mg
I know there is a way to do it using log or log10 functions but I cannot figure it out.
How could it be done?
I think something like this should work, but I'm sure there are people who can make a much better solution.
function outputWeight($kg)
{
$power = floor(log($kg, 10));
switch($power) {
case 5 :
case 4 :
case 3 : $unit = 'ton';
$power = 3;
break;
case 2 :
case 1 :
case 0 : $unit = 'kilogram';
$power = 0;
break;
case -1 :
case -2 :
case -3 : $unit = 'gram';
$power = -3;
break;
case -4 :
case -5 :
case -6 : $unit = 'milligram';
$power = -6;
break;
default : return 'out of range';
}
return ($kg / pow(10, $power)) . ' ' . $unit;
}
echo outputWeight(0.015) . '<br>';
echo outputWeight(0.15) . '<br>';
echo outputWeight(1.5) . '<br>';
echo outputWeight(15) . '<br>';
echo outputWeight(150) . '<br>';
The idea is that you can easily extend the range. This will output
15 gram
150 gram
1.5 kilogram
15 kilogram
150 kilogram
I did not thoroughly test this code!
After playing with it for a while, here is what I came up with
function readableMetric($kg)
{
$amt = $kg * pow(1000, 3);
$s = array('mcg', 'mg', 'gm', 'kg','tonne');
$e = floor(log10($amt)/log10(1000));
return [
"amount" => $amt/pow(1000, $e),
"unit" => $s[$e]
];
}
The following function internally uses an array with the assignments unit => conversion-factor. This array can easily be expanded or modified to meet your own requirements. A fixed limit of 1000 is used in the function. This means that the output value is always less than 1000, with the exception of tons. With an additional argument which is preset to 2, the number of maximum decimal places can be changed.
function scaleKg(float $kg, int $decimalPlaces = 2) : string {
$scale = [
'micrograms' => 1.E9,
'milligram' => 1.E6,
'gram' => 1.E3,
'kilogram' => 1,
'ton' => 1.E-3,
];
foreach($scale as $unit => $factor){
$mass = $kg * $factor;
if($mass < 1000) {
return round($mass,$decimalPlaces).' '.$unit;
}
}
return round($mass,$decimalPlaces).' '.$unit;
}
Some examples:
$kg = 1.212345;
echo scaleKg($kg); //1.21 kilogram
$kg = 455;
echo scaleKg($kg); //455 kilogram
$kg = 0.0456;
echo scaleKg($kg); //45.6 gram
$kg = 23456;
echo scaleKg($kg); //23.46 ton
$kg = 23489000;
echo scaleKg($kg); //23489 ton
$kg = 167E-6;
echo scaleKg($kg); //167 milligram
I find myself agreeing with Kiko that the shortest code isn't always the best or most readable.
Bearing that in mind bringing log into it seems like unnecessary complication. So I suggest a condensed version of my original code:
function readableMetric($mass)
{
$units = [
-3 => "tonne",
0 => "kg",
3 => "g",
6 => "mg",
];
foreach ($units as $x => $unit) {
if ( ($newMass = $mass * 10 ** $x) >= 1 ) {
return "{$newMass} {$unit}";
}
}
}
This is more extensible (e.g. you could easily add centigram)
The math is intuitive to most (powers of 10)
If you really want to golf it you can shrink it down to a one liner:
function readableMetric($m)
{
foreach([-3=>"tonne",0=>"kg",3=>"g",6 =>"mg"] as $x=>$g)if(($n=$m*10**$x)>=1)return"$n $g";
}
Original Answer
You could just do it with a series of if / else statements?
$values = [
5, 0.5, 1000, 0.001, 0.0001
];
function convertmass($mass) : string
{
if ($mass >= 1000) {
return ($mass / 1000) . " ton";
}
elseif ($mass < 0.001) {
return ($mass * 1000000) . " mg";
}
elseif ($mass < 1) {
return ($mass * 1000 ) . " g";
}
else {
return $mass . " kg";
}
}
foreach ($values as $mass) {
echo convertmass($mass), PHP_EOL;
}
Output:
5 kg
500 g
1 ton
1 g
100 mg
If you want slightly easier/more readable/more user friendly updating to add new measurements in then you can do something like this instead:
$values = [
5, 0.5, 1000, 0.001, 0.0001
];
function convertmass($mass) : string
{
$massLookup = [
[ "unit" => "kg", "min" => 1, "max" => 1000, "multiple" => 1],
[ "unit" => "tonne", "min" => 1000, "max" => 1000000, "multiple" => 0.001],
[ "unit" => "g", "min" => 0.001, "max" => 1, "multiple" => 1000],
[ "unit" => "mg", "min" => 0.000001, "max" => 0.001, "multiple" => 1000000],
];
foreach ($massLookup as $unit) {
if ($mass >= $unit["min"] && $mass < $unit["max"]) {
return ($mass * $unit["multiple"]) . " {$unit["unit"]}";
}
}
return "Measurement {$mass} kg is out of range";
}
foreach ($values as $mass) {
echo convertmass($mass), PHP_EOL;
}
I've inherited a project written in PHP which has a double entry style cashbook, which requires that the amount going in is equal to the amount going out.
When validating figures entered via a form (to work out if it equals zero), it runs the code below which works fine until there is a decimal number, which seems to make it randomly fall over and return an incorrect value.
In the example below, it returns a really tiny number from 53.87 - 53.87, which should be zero.This has been stripped back to eliminate other things from causing problems, so I've removed a lot of input validation etc.
<?php $inputs = array(
array(
"in" => '',
"out" => '249.6',
),
array(
"in" => '',
"out" => '396',
),
array(
"in" => '554.4',
"out" => ''
),
array(
"in" => '145.07',
"out" => ''
),
array(
"in" => '',
"out" => '53.87',
),
);
$fTotal = 0;
echo "Start at 0: ";
foreach($inputs as $key=>$sRef) {
$itemValid = true;
$aItem = array();
$amountIn = $inputs[$key]['in'];
$amountOut = $inputs[$key]['out'];
if ($itemValid) {
echo "'".$fTotal."'";
$is_in = 0;
if ($amountIn > 0.0) {
$is_in = 1;
echo "+";
$amount = $amountIn;
$fTotal = $fTotal + $amountIn;
} else {
$is_in = 0;
echo "-";
$amount = $amountOut;
$fTotal = $fTotal - $amountOut;
}
echo "'".$amount."'=";
echo "'".$fTotal."' | ";
$aItem["is_in"] = $is_in;
$aItem["amount"] = $amount;
$aItems[] = $aItem;
}
}
You can run this on a sandbox here.
Here is the expected output:
Start at 0: '0'-'249.6'='-249.6' | '-249.6'-'396'='-645.6' | '-645.6'+'554.4'='-91.2' | '-91.2'+'145.07'='53.87' | '53.87'-'53.87'='0' |
Here is the actual output:
Start at 0: '0'-'249.6'='-249.6' | '-249.6'-'396'='-645.6' | '-645.6'+'554.4'='-91.2' | '-91.2'+'145.07'='53.87' | '53.87'-'53.87'='-4.9737991503207E-14' |
What is wrong here?
Update
Following help below, here's the working code for anyone who stumbles on this in the future.
This is happening because of floating point (decimal) maths where computers like binary maths. Sometimes decimal numbers don't have a nice representation in binary so these tiny differences happen.
If you can state that every number can be rounded to 2 decimal points, and based on your limited dataset, wrapping your 'sums' in number_format($fTotal + $amountIn , 2) etc can sort this out for you.
Alternatively for a "more accurate", just wrap the final one eg. echo "'".number_format($fTotal, 2)."' | "; (or 0 or whatever)
Your numbers are being interpreted as strings.
Try this:
<?php
$inputs = array(
array(
"in" => 0,
"out" => 249.6,
),
array(
"in" => 0,
"out" => 396,
),
array(
"in" => 554.4,
"out" => 0
),
array(
"in" => 145.07,
"out" => 0
),
array(
"in" => 0,
"out" => 53.87,
),
);
$fTotal = 0;
echo "Start at 0: ";
foreach($inputs as $key => $sRef) {
$itemValid = true;
$amountIn = $sRef['in'];
$amountOut = $sRef['out'];
if ($itemValid) {
echo $fTotal;
$is_in = 0;
if ($amountIn > 0.0) {
$is_in = 1;
echo "+";
$amount = floatval($amountIn);
$fTotal = floatval($fTotal) + floatval($amountIn);
} else {
$is_in = 0;
echo "-";
$amount = floatval($amountOut);
$fTotal = floatval($fTotal) - floatval($amountIn);
}
echo $amount;
echo ' = ' . $fTotal . " | ";
}
}
The bcsub() function in PHP is an inbuilt function and is used to subtract one arbitrary precision number from another.
Syntax:
string bcsub ( $num_str1, $num_str2, $scaleVal)
Example :
<?php $num_str1 = "8"; $num_str2 = "3"; $res = bcsub($num_str1, $num_str2) echo $res; ?>
Result:
5
I have a script that generates sitemaps based on url index http://example.com/sitemap.index.xml where index is a number >0 that defines what results should be included in each chunk.
$chunk = 10000;
$counter = 0;
$scroll = $es->search(array(
"index" => "index",
"type" => "type",
"scroll" => "1m",
"search_type" => "scan",
"size" => 10,
"from" => $chunk * ($index - 1)
));
$sid = $scroll['_scroll_id'];
while($counter < $chunk){
$docs = $es->scroll(array(
"scroll_id" => $sid,
"scroll" => "1m"
));
$sid = $docs['_scroll_id'];
$counter += count($docs['hits']['hits']);
}
// ...
Now each time I access http://example.com/sitemap.1.xml or http://example.com/sitemap.2.xml the results returned from ES are exactly the same. It returns 50 results (10 per each shard) but does not seem to take count of from = 0, from = 10000.
I'm using elasticsearch-php as ES library.
Any ideas?
In Java, it can be done as follows
QueryBuilder query = QueryBuilders.matchAllQuery();
SearchResponse scrollResp = Constants.client.prepareSearch(index)
.setTypes(type).setSearchType(SearchType.SCAN)
.setScroll(new TimeValue(600000)).setQuery(query)
.setSize(500).execute().actionGet();
while (true) {
scrollResp = Constants.client
.prepareSearchScroll(scrollResp.getScrollId())
.setScroll(new TimeValue(600000)).execute().actionGet();
System.out.println("Record count :"
+ scrollResp.getHits().getHits().length);
total = total + scrollResp.getHits().getHits().length;
System.out.println("Total record count: " + total);
for (SearchHit hit : scrollResp.getHits()) {
//handle the hit
}
// Break condition: No hits are returned
if (scrollResp.getHits().getHits().length == 0) {
System.out.println("All records are fetched");
break;
}
}
Hope it helps.
I want to get the date of the first day of the last week:
$date = new DateTime(NULL, new DateTimeZone('Pacific/Wake'));
$date = $date->modify('previous week');
$date = $date->format('Y-m-d');
and
$date = new DateTime(NULL, new DateTimeZone('Pacific/Wake'));
$date = $date->modify('last week');
$date = $date->format('Y-m-d');
Both work.
But is there any difference?
They are the same, you can confirm this for yourself if you want, the PHP source code is available on github.
https://github.com/php/php-src/blob/master/ext/date/php_date.c#L1443
PHP_FUNCTION(strtotime)
{
...
t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); /* we ignore the error here, as this should never fail */
So it calls timelib_strtotime, where can this be found? Well luckily that's online too
https://github.com/php/php-src/blob/master/ext/date/lib/parse_date.c#L24743
timelib_time* timelib_strtotime(char *s, int len, struct timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper)
{
...
do {
t = scan(&in, tz_get_wrapper);
#ifdef DEBUG_PARSER
printf("%d\n", t);
#endif
} while(t != EOI);
...
Which relies on scan:
https://github.com/php/php-src/blob/master/ext/date/lib/parse_date.c#L835
static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper)
{
...
while(*ptr) {
i = timelib_get_relative_text((char **) &ptr, &behavior);
Which makes a call to timelib_get_relative_text
https://github.com/php/php-src/blob/master/ext/date/lib/parse_date.c#L561
static timelib_sll timelib_get_relative_text(char **ptr, int *behavior)
{
while (**ptr == ' ' || **ptr == '\t' || **ptr == '-' || **ptr == '/') {
++*ptr;
}
return timelib_lookup_relative_text(ptr, behavior);
}
Which makes a call to timelib_lookup_relative_text:
https://github.com/php/php-src/blob/master/ext/date/lib/parse_date.c#L536
static timelib_sll timelib_lookup_relative_text(char **ptr, int *behavior)
{
...
for (tp = timelib_reltext_lookup; tp->name; tp++) {
if (strcasecmp(word, tp->name) == 0) {
value = tp->value;
*behavior = tp->type;
}
}
...
}
Which in turn uses a structure set called timelib_reltext_lookup defined at the top of the file:
https://github.com/php/php-src/blob/master/ext/date/lib/parse_date.c#L248
static timelib_lookup_table const timelib_reltext_lookup[] = {
{ "first", 0, 1 },
{ "next", 0, 1 },
{ "second", 0, 2 },
{ "third", 0, 3 },
{ "fourth", 0, 4 },
{ "fifth", 0, 5 },
{ "sixth", 0, 6 },
{ "seventh", 0, 7 },
{ "eight", 0, 8 },
{ "eighth", 0, 8 },
{ "ninth", 0, 9 },
{ "tenth", 0, 10 },
{ "eleventh", 0, 11 },
{ "twelfth", 0, 12 },
{ "last", 0, -1 },
{ "previous", 0, -1 },
{ "this", 1, 0 },
{ NULL, 1, 0 }
};
Hopefully this is sufficient proof that they are, in every way, the same.
The word "previous" is supported since PHP5, "last" since PHP4. The result of both is the same and both are still valid.
I have this as result in and HTML page created from script.
thumbnail[++nr] = new makeIt(nr, "slides/IMG_3924.html", "thumbs/IMG_3924.jpg", 150, 100, "IMG_3924.jpg", "slides/IMG_3924.jpg", 150, 100, "", "sorting01", 0)
thumbnail[++nr] = new makeIt(nr, "slides/IMG_3909.html", "thumbs/IMG_3909.jpg", 100, 150, "IMG_3909.jpg", "slides/IMG_3909.jpg", 100, 150, "", "sorting02", 0)
thumbnail[++nr] = new makeIt(nr, "slides/IMG_3914.html", "thumbs/IMG_3914.jpg", 150, 100, "IMG_3914.jpg", "slides/IMG_3914.jpg", 150, 100, "", "sorting02", 0)
thumbnail[++nr] = new makeIt(nr, "slides/IMG_3904.html", "thumbs/IMG_3904.jpg", 100, 150, "IMG_3904.jpg", "slides/IMG_3904.jpg", 100, 150, "", "sorting01", 0)
And here's the code that produced it
if ($file2 != "." && $file2 != ".." && strpos($file2,'.')!==0 ) {
list($widthT2, $heightT2, $type2, $attr2) = getimagesize($pathToThumbs."/$name2.jpg");
$thumbW2 = $widthT2;
$thumbH2 = $heightT2;
$out[]="thumbnail[++nr] = new makeIt(nr, \"slides/$name2.html\", \"thumbs/$name2.jpg\", $thumbW2, $thumbH2, \"$name2.jpg\", \"slides/$name2.jpg\", $widthT2, $heightT2, \"\", \"$commentaire\", 0)\n";
}
}
//usort($out, function ($a, $b){
// return substr($b, -8) - substr($a, -8);
//});
sort($out);
foreach($out as $key => $value){
print $value;
}
How can I sort the results so they are sorted by sorting01, and then by sorting02 text at the end of each line? I want to sort the array from what the last 2 fields of each line contains.
Searching last "some text in quotas" in strings and compare:
function compare($a,$b)
{
// searching commentaire (searching last " and second from end ")
$end_commentaire = strrpos($a, '"');
$substr_a = substr($a, 0, $end_commentaire);
$begin_commentaire = strrpos($substr_a, '"');
$substr_a = substr($substr_a, $begin_commentaire+1);
$end_commentaire = strrpos($b, '"');
$substr_b = substr($b, 0, $end_commentaire);
$begin_commentaire = strrpos($substr_b, '"');
$substr_b = substr($substr_b, $begin_commentaire+1);
//echo "|$substr_a|$substr_b|<br>";
// compare
$result = strcmp($substr_a, $substr_b);
// $substr_a and $substr_b are different,
// don't compare rest of string
if( $result != 0 )
return $result;
// $substr_a and $substr_b are the same,
// compare rest of string
return strcmp($a, $b);
}
usort($out, 'compare');
Put this in place of sort($out)
Edit:
Using RegEx:
function compare($a,$b)
{
// searching commentaire (searching last " and second from end ")
preg_match('/"([^"]*)"[^"]*$/', $a, $result_a);
preg_match('/"([^"]*)"[^"]*$/', $b, $result_b);
//echo "|$result_a[1]|$result_b[1]|$result_a[0]|$result_b[0]|<br>";
// compare
$result = strcmp($result_a[1], $result_b[1]);
// $result_a[1] and $result_b[1] are different,
// don't compare rest of string
if( $result != 0 )
return $result;
// $result_a[1] and $result_b[1] are the same,
// compare rest of string
return strcmp($a, $b);
}
usort($out, 'compare');