PHP's parse_str in TypeScript

How to use

Install via yarn add locutus and import: import { parse_str } from 'locutus/php/strings/parse_str'.

Or with CommonJS: const { parse_str } = require('locutus/php/strings/parse_str')

Use a bundler that supports tree-shaking so you only ship the functions you actually use. Vite, webpack, Rollup, and Parcel all handle this. For server-side use this is less of a concern.

Examples

These examples are extracted from test cases that automatically verify our functions against their native counterparts.

#codeexpected result
1var $arr = {} parse_str('first=foo&second=bar', $arr) var $result = $arr{ first: 'foo', second: 'bar' }
2var $arr = {} parse_str('str_a=Jack+and+Jill+didn%27t+see+the+well.', $arr) var $result = $arr{ str_a: "Jack and Jill didn't see the well." }
3var $abc = {3:'a'} parse_str('a[b]["c"]=def&a[q]=t+5', $abc) var $result = $abc{"3":"a","a":{"b":{"c":"def"},"q":"t 5"}}
4var $arr = {} parse_str('a[][]=value', $arr) var $result = $arr{"a":{"0":{"0":"value"}}}
5var $arr = {} parse_str('a=1&a[]=2', $arr) var $result = $arr{"a":{"0":"2"}}

Notes

  • When no argument is specified, will put variables in global scope. When a particular argument has been passed, and the returned value is different parse_str of PHP. For example, a=b=c&d====c

Dependencies

This function uses the following Locutus functions:

Here's what our current TypeScript equivalent to PHP's parse_str looks like.

import { getPhpGlobalScope } from '../_helpers/_phpRuntimeState.ts'
import { isPhpAssocObject, type PhpAssoc, type PhpInput } from '../_helpers/_phpTypes.ts'

type ParseObject = PhpAssoc<PhpInput>

export function parse_str(str: string, array?: ParseObject): void {
// discuss at: https://locutus.io/php/parse_str/
// original by: Cagri Ekin
// improved by: Michael White (https://getsprink.com)
// improved by: Jack
// improved by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: stag019
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: MIO_KODUKI (https://mio-koduki.blogspot.com/)
// reimplemented by: stag019
// input by: Dreamer
// input by: Zaide (https://zaidesthings.com/)
// input by: David Pesta (https://davidpesta.com/)
// input by: jeicquest
// bugfixed by: Rafał Kukawski
// note 1: When no argument is specified, will put variables in global scope.
// note 1: When a particular argument has been passed, and the
// note 1: returned value is different parse_str of PHP.
// note 1: For example, a=b=c&d====c
// example 1: var $arr = {}
// example 1: parse_str('first=foo&second=bar', $arr)
// example 1: var $result = $arr
// returns 1: { first: 'foo', second: 'bar' }
// example 2: var $arr = {}
// example 2: parse_str('str_a=Jack+and+Jill+didn%27t+see+the+well.', $arr)
// example 2: var $result = $arr
// returns 2: { str_a: "Jack and Jill didn't see the well." }
// example 3: var $abc = {3:'a'}
// example 3: parse_str('a[b]["c"]=def&a[q]=t+5', $abc)
// example 3: var $result = $abc
// returns 3: {"3":"a","a":{"b":{"c":"def"},"q":"t 5"}}
// example 4: var $arr = {}
// example 4: parse_str('a[][]=value', $arr)
// example 4: var $result = $arr
// returns 4: {"a":{"0":{"0":"value"}}}
// example 5: var $arr = {}
// example 5: parse_str('a=1&a[]=2', $arr)
// example 5: var $result = $arr
// returns 5: {"a":{"0":"2"}}

const strArr = String(str).replace(/^&/, '').replace(/&$/, '').split('&')
const sal = strArr.length
let i = 0
let j = 0
let ct = 0
let lastObj: ParseObject = {}
let obj: ParseObject = {}
let chr
let tmp: string[] = []
let key = ''
let value = ''
let postLeftBracketPos = 0
let keys: string[] = []
let keysLen = 0

const _fixStr = function (str: string): string {
return decodeURIComponent(str.replace(/\+/g, '%20'))
}

const target: ParseObject = array || getPhpGlobalScope()

for (i = 0; i < sal; i++) {
tmp = (strArr[i] ?? '').split('=')
key = _fixStr(tmp[0] ?? '')
value = tmp.length < 2 ? '' : _fixStr(tmp[1] ?? '')

if (/__proto__|constructor|prototype/.test(key)) {
break
}

while (key.charAt(0) === ' ') {
key = key.slice(1)
}

const nullByteIndex = key.indexOf('\x00')
if (nullByteIndex > -1) {
key = key.slice(0, nullByteIndex)
}

if (key && key.charAt(0) !== '[') {
keys = []
postLeftBracketPos = 0

for (j = 0; j < key.length; j++) {
if (key.charAt(j) === '[' && !postLeftBracketPos) {
postLeftBracketPos = j + 1
} else if (key.charAt(j) === ']') {
if (postLeftBracketPos) {
if (!keys.length) {
keys.push(key.slice(0, postLeftBracketPos - 1))
}

keys.push(key.substr(postLeftBracketPos, j - postLeftBracketPos))
postLeftBracketPos = 0

if (key.charAt(j + 1) !== '[') {
break
}
}
}
}

if (!keys.length) {
keys = [key]
}

let primaryKey = keys[0] ?? ''
for (j = 0; j < primaryKey.length; j++) {
chr = primaryKey.charAt(j)

if (chr === ' ' || chr === '.' || chr === '[') {
primaryKey = primaryKey.substring(0, j) + '_' + primaryKey.substring(j + 1)
}

if (chr === '[') {
break
}
}
keys[0] = primaryKey

obj = target

for (j = 0, keysLen = keys.length; j < keysLen; j++) {
key = (keys[j] ?? '').replace(/^['"]/, '').replace(/['"]$/, '')
lastObj = obj

if ((key === '' || key === ' ') && j !== 0) {
// Insert new dimension
ct = -1

for (const objKey of Object.keys(obj)) {
if (+objKey > ct && /^\d+$/.test(objKey)) {
ct = +objKey
}
}

key = String(ct + 1)
}

// if primitive value, replace with object
const current = obj[key]
if (!isPhpAssocObject(current)) {
obj[key] = {}
}

const next = obj[key]
if (!isPhpAssocObject(next)) {
break
}
obj = next
}

lastObj[key] = value
}
}
}

Improve this function

Locutus is a community effort following The McDonald's Theory: we ship first iterations, hoping others will improve them. If you see something that could be better, we'd love your contribution.

View on GitHub · Edit on GitHub · View Raw


« More PHP strings functions


Star