'PHP Sorting - getting 10, 11, 12 ... 1, 20, 2 rather than 1, 10, 11, 12 ... 2, 20

I have parameters like this that need to be sorted (Note: I am sorting AFTER converting the key=>value combinations to strings):

$param['SignatureMethod']  = 'HmacSHA256';  
$param['SignatureVersion'] = '2'; 
$param['Timestamp']        = gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
$param['Version']          = '2011-10-01'; 
$param['SellerSKUList.SellerSKU.1']    = $sku1;
$param['SellerSKUList.SellerSKU.2']    = $sku2;
$param['SellerSKUList.SellerSKU.3']    = $sku3;
$param['SellerSKUList.SellerSKU.4']    = $sku4;

I have about 30 parameters total. In order to call the endpoint, I need to generate a signature of the parameters in an alphabetical sort.

Using PHP's sort() works fine for less than 10, but when I try to use 20, it gives me output like this:

SellerSKUList.SellerSKU.10=4574&
SellerSKUList.SellerSKU.11=4575&
...
SellerSKUList.SellerSKU.18=4582&
SellerSKUList.SellerSKU.19=4583&
SellerSKUList.SellerSKU.1=4565&
SellerSKUList.SellerSKU.20=4584&
SellerSKUList.SellerSKU.2=4566

I need it to be like this:

SellerSKUList.SellerSKU.1=4565&
SellerSKUList.SellerSKU.10=4574&
SellerSKUList.SellerSKU.11=4575&
...
SellerSKUList.SellerSKU.18=4582&
SellerSKUList.SellerSKU.19=4583&
SellerSKUList.SellerSKU.2=4566&
SellerSKUList.SellerSKU.20=4584

Sort function looks like this:

$url = array();
foreach ($param as $key => $val) {

    $key = str_replace("%7E", "~", rawurlencode($key));
    $val = str_replace("%7E", "~", rawurlencode($val));
    $url[] = "{$key}={$val}";
}

sort($url);

It seems to me that the sort() function should give desired output, but my experiences show different. Is there another function or another way to sort 1 before 10 within a string?

I have tried:

usort($url,strcmp)  => 10,11,12...1,20,2
uksort($url,strcmp) => 10,11,12...20,2,1
natsort($url)       => 1,2,3,...10,11,12

Desired:            => 1,10,11...19,2,20


Solution 1:[1]

I found a solution - if I uksort($params,strcmp) before imploding the key=>value pairs, the sort order is correct.

uksort($param, 'strcmp');

$url = array();
foreach ($param as $key => $val) {

    $key = str_replace("%7E", "~", rawurlencode($key));
    $val = str_replace("%7E", "~", rawurlencode($val));
    $url[] = "{$key}={$val}";
}

Thanks to @Thomas Smart's comment here: https://stackoverflow.com/a/12505517/2661831

I'd still like to know if there's a way to sort strings like this:

SellerSKUList.SellerSKU.10=4574&
SellerSKUList.SellerSKU.11=4575&
SellerSKUList.SellerSKU.18=4582&
SellerSKUList.SellerSKU.19=4583&
SellerSKUList.SellerSKU.1=4565&
SellerSKUList.SellerSKU.20=4584&
SellerSKUList.SellerSKU.2=4566

Solution 2:[2]

You can sort your array of strings by isolating the substring before the first = in the string.

Code: (Demo)

array_multisort(array_map(fn($v) => strtok($v, '='), $array), $array);
var_export($array);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 mickmackusa