Import variables from an array into the current symbol table.
Checks each key to see whether it has a valid variable name.
It also checks for collisions with existing variables in
the symbol table.
Warning
Do not use
extract()
on untrusted data, like user input
(e.g.
$_GET
,
$_FILES
).
An associative array. This function treats keys as variable names and
values as variable values. For each key/value pair it will create a
variable in the current symbol table, subject to
flags
and
prefix
parameters.
You must use an associative array; a numerically indexed array
will not produce results unless you use
EXTR_PREFIX_ALL
or
EXTR_PREFIX_INVALID
.
The way invalid/numeric keys and collisions are treated is determined
by the extraction
flags
. It can be one of the
following values:
EXTR_OVERWRITE
Only overwrite the variable if it already exists in the
current symbol table, otherwise do nothing. This is useful
for defining a list of valid variables and then extracting
only those variables you have defined out of
$_REQUEST
, for example.
Extracts variables as references. This effectively means that the
values of the imported variables are still referencing the values of
the
array
parameter. You can use this flag
on its own or combine it with any other flag by OR'ing the
flags
.
Note that
prefix
is only required if
flags
is
EXTR_PREFIX_SAME
,
EXTR_PREFIX_ALL
,
EXTR_PREFIX_INVALID
or
EXTR_PREFIX_IF_EXISTS
. If
the prefixed result is not a valid variable name, it is not
imported into the symbol table. Prefixes are automatically separated from
the array key by an underscore character.
A possible use for
extract()
is to import into the
symbol table variables contained in an associative array returned by
wddx_deserialize()
.
<?php
/* Suppose that $var_array is an array returned from
wddx_deserialize */
$size
=
"large"
;
$var_array
= array(
"color"
=>
"blue"
,
"size"
=>
"medium"
,
"shape"
=>
"sphere"
);
extract
(
$var_array
,
EXTR_PREFIX_SAME
,
"wddx"
);
echo
"
$color
,
$size
,
$shape
,
$wddx_size
\n"
;
?>
The
$size
wasn't overwritten because we specified
EXTR_PREFIX_SAME
, which resulted in
$wddx_size
being created. If
EXTR_SKIP
was
specified, then
$wddx_size
wouldn't even have been created.
EXTR_OVERWRITE
would have caused
$size
to have
value "medium", and
EXTR_PREFIX_ALL
would result in new variables
being named
$wddx_color
,
$wddx_size
, and
$wddx_shape
.
user input
(i.e.
$_GET
,
$_FILES
, etc.).
If you do, make sure you use one of the non-overwriting
flags
values such as
EXTR_SKIP
and be aware that you should extract
in the same order that's defined in
variables_order
within the
php.ini
.
They say "If the result is not a valid variable name, it is not imported into the symbol table."
What they should say is that if _any_ of the results have invalid names, _none_ of the variables get extracted.
Under 4.3.10 on Windows 2000, I was pulling some mySQL records, but needed to convert two fields into IP addresses:
<?
extract(mysql_fetch_assoc(mysql_query('SELECT * FROM foo')));
extract(mysql_fetch_assoc(mysql_query('SELECT INET_NTOA(bar) AS bar, INET_NTOA(baz) FROM foo')));
?>
I had forgotten the second AS modifier in the SQL query. Because it couldn't extract a variable called INET_NTOA(baz) into the symbol table, it didn't do either of them.
(BTW I don't normally stack functions up like that! Just to make a short example!)
We can use extract () function for Template Engine:
<?php
class
Template
{
protected
$viewVars
;
public function
renderPage
(
$tpl
)
{
ob_start
();
extract
(
$this
->
viewVars
,
EXTR_SKIP
);
include
$tpl
;
return
ob_end_flush
();
}
public function
assign
(
$arr
)
{
foreach (
$arr
as
$key
=>
$value
) {
$this
->
viewVars
[
$key
] =
$value
;
}
return
$this
;
}
}
$template
= new
Template
();
$template
->
assign
(
[
'pageHeader'
=>
'Page Header'
,
'content'
=>
'This is the content page'
]
);
$template
->
renderPage
(
'tpl.php'
);
<
h1
><?=
$pageHeader
;
?>
</h1>
<p>
<?= $content
;
?>
</p>
Output:
Page Header
This is the content page
It is possible to use this as a way to create public attributes for a class.
<?php
class
Foo
{
public function
__construct
(
$array
) {
extract
(
$array
,
EXTR_REFS
);
foreach (
$array
as
$key
=>
$value
) {
$this
->
$key
= $
$key
;
}
}
}
$array
= array(
'valueOne'
=>
'Test Value 1'
,
'valueTwo'
=>
'Test Value 2'
,
'valueThree'
=>
'Test Value 3'
);
$foo
= new
Foo
(
$array
);
echo
$foo
->
valueOne
;
echo
$foo
->
valueTwo
;
echo
$foo
::
$valueOne
;
?>
[New Version]
This function is very useful for filtering complicated array structure.
Also, Some integer bitmasks and invalid UTF-8 sequence detection are available.
Code:
<?php
define
(
'FILTER_STRUCT_FORCE_ARRAY'
,
1
);
define
(
'FILTER_STRUCT_TRIM'
,
2
);
define
(
'FILTER_STRUCT_FULL_TRIM'
,
4
);
function
filter_struct_utf8
(
$type
, array
$default
) {
static
$func
=
__FUNCTION__
;
static
$trim
=
"[\\x0-\x20\x7f]"
;
static
$ftrim
=
"[\\x0-\x20\x7f\xc2\xa0\xe3\x80\x80]"
;
static
$recursive_static
=
false
;
if (!
$recursive
=
$recursive_static
) {
$types
= array(
INPUT_GET
=>
$_GET
,
INPUT_POST
=>
$_POST
,
INPUT_COOKIE
=>
$_COOKIE
,
INPUT_REQUEST
=>
$_REQUEST
,
);
if (!isset(
$types
[(int)
$type
])) {
throw new
LogicException
(
'unknown super global var type'
);
}
$var
=
$types
[(int)
$type
];
$recursive_static
=
true
;
} else {
$var
=
$type
;
}
$ret
= array();
foreach (
$default
as
$key
=>
$value
) {
if (
$is_int
=
is_int
(
$value
)) {
if (!(
$value
| (
FILTER_STRUCT_FORCE_ARRAY
|
FILTER_STRUCT_FULL_TRIM
|
FILTER_STRUCT_TRIM
))) {
$recursive_static
=
false
;
throw new
LogicException
(
'unknown bitmask'
);
}
if (
$value
&
FILTER_STRUCT_FORCE_ARRAY
) {
$tmp
= array();
if (isset(
$var
[
$key
])) {
foreach ((array)
$var
[
$key
] as
$k
=>
$v
) {
if (!
preg_match
(
'//u'
,
$k
)){
continue;
}
$value
&=
FILTER_STRUCT_FULL_TRIM
|
FILTER_STRUCT_TRIM
;
$tmp
+= array(
$k
=>
$value
?
$value
:
''
);
}
}
$value
=
$tmp
;
}
}
if (
$isset
= isset(
$var
[
$key
]) and
is_array
(
$value
)) {
$ret
[
$key
] =
$func
(
$var
[
$key
],
$value
);
} elseif (!
$isset
||
is_array
(
$var
[
$key
])) {
$ret
[
$key
] =
null
;
} elseif (
$is_int
&&
$value
&
FILTER_STRUCT_FULL_TRIM
) {
$ret
[
$key
] =
preg_replace
(
"/\A
{
$ftrim
}
++|
{
$ftrim
}
++\z/u"
,
''
,
$var
[
$key
]);
} elseif (
$is_int
&&
$value
&
FILTER_STRUCT_TRIM
) {
$ret
[
$key
] =
preg_replace
(
"/\A
{
$trim
}
++|
{
$trim
}
++\z/u"
,
''
,
$var
[
$key
]);
} else {
$ret
[
$key
] =
preg_replace
(
'//u'
,
''
,
$var
[
$key
]);
}
if (
$ret
[
$key
] ===
null
) {
$ret
[
$key
] =
$is_int
?
''
:
$value
;
}
}
if (!
$recursive
) {
$recursive_static
=
false
;
}
return
$ret
;
}
?>
Sometimes you may want to extract only a named subset of the key/value pairs in an array. This keeps things more orderly and could prevent an unrelated variable from getting clobbered from an errant key. For example,
$things = 'unsaid';
$REQUEST = array(He=>This, said=>1, my=>is, info=>2, had=>a,
very=>3, important=>test, things=>4);
$aVarToExtract = array(my, important, info);
extract (array_intersect_key ($REQUEST, array_flip($aVarToExtract)));
will extract
$my = 'is';
$important = 'test';
$info = 2;
but will leave certain
$things = 'unsaid'
Csaba Gabor from Vienna
NB. Of course the composite request coming in from a web page is in $_REQUEST.
Following up on ktwombley at gmail dot com's post:
Presumably one easy way of dealing with this security issue is to use the EXTR_IF_EXISTS flag and make sure
a) your define acceptable input variables beforehand (i.e. as empty variables)
b) Sanitise any user input to avoid unacceptable variable content.
If you do these two things, then I'm not sure I see the difference between extract($_REQUEST,EXTR_IF_EXISTS); and assigning each of the variables by hand.
I'm not talking here about the idea of storing the variables in a database, just the immediately necessary steps to allow you to use extract on REQUEST arrays with relative safety.
Dan O'Donnell's suggestion needs a third requirement to work as described:
c) No other variables are defined - especially variables that contain potentially sensitive information.
Without that condition the difference between extract() and assigning variables by hand (and the resulting security implications) should be obvious.
The only valid security step there is (b) - but you should be doing that anyway.
[New Version]
Example Usage:
<?php
$_GET
[
'A'
][
'a'
] =
' CORRECT(including some spaces) '
;
$_GET
[
'A'
][
'b'
] =
' CORRECT(including some spaces) '
;
$_GET
[
'A'
][
'c'
] =
"Invalid UTF-8 sequence: \xe3\xe3\xe3"
;
$_GET
[
'A'
][
'd'
][
'invalid_structure'
] =
'INVALID'
;
$_GET
[
'B'
][
'a'
] =
' CORRECT(including some spaces) '
;
$_GET
[
'B'
][
'b'
] =
"Invalid UTF-8 sequence: \xe3\xe3\xe3"
;
$_GET
[
'B'
][
'c'
][
'invalid_structure'
] =
'INVALID'
;
$_GET
[
'B'
][
"Invalid UTF-8 sequence: \xe3\xe3\xe3"
] =
'INVALID'
;
$_GET
[
'C'
][
'a'
] =
' CORRECT(including some spaces) '
;
$_GET
[
'C'
][
'b'
] =
"Invalid UTF-8 sequence: \xe3\xe3\xe3"
;
$_GET
[
'C'
][
'c'
][
'invalid_structure'
] =
'INVALID'
;
$_GET
[
'C'
][
"Invalid UTF-8 sequence: \xe3\xe3\xe3"
] =
'INVALID'
;
$_GET
[
'unneeded_item'
] =
'UNNEEDED'
;
var_dump
(
filter_struct_utf8
(
INPUT_GET
, array(
'A'
=> array(
'a'
=>
''
,
'b'
=>
FILTER_STRUCT_TRIM
,
'c'
=>
''
,
'd'
=>
''
,
),
'B'
=>
FILTER_STRUCT_FORCE_ARRAY
,
'C'
=>
FILTER_STRUCT_FORCE_ARRAY
|
FILTER_STRUCT_TRIM
,
)));
?>
Example Result:
array(3) {
["A"]=>
array(4) {
["a"]=>
string(36) " CORRECT(including some spaces) "
["b"]=>
string(30) "CORRECT(including some spaces)"
["c"]=>
string(0) ""
["d"]=>
string(0) ""
}
["B"]=>
array(3) {
["a"]=>
string(36) " CORRECT(including some spaces) "
["b"]=>
string(0) ""
["c"]=>
string(0) ""
}
["C"]=>
array(3) {
["a"]=>
string(30) "CORRECT(including some spaces)"
["b"]=>
string(0) ""
["c"]=>
string(0) ""
}
}
And if you want with PHP 5 an easy way to extract $V by reference, try this :
<?php
foreach (
$V
as
$k
=> &
$v
) {
$
$k
=&
$v
;
}
?>
It can be used to create special kind of "free args" functions that let you choose when you call them the way you send variables, and which ones. They are moreover very fast to call thanks to references :
<?php
function
free_args
(&
$V
) {
foreach (
$V
as
$k
=> &
$v
) {
$
$k
=&
$v
;
}
unset (
$k
); unset (
$v
); unset (
$V
);
}
$huge_text
=
'...'
;
$a
= array (
'arg1'
=>
'val1'
,
'arg2'
=> &
$huge_text
);
free_args
(
$a
);
?>
Be warned that you can't write : "
<?php free_args
(array (
'arg1'
=>
'val1'
));
?>
" because the array can't be referenced by the function, as it's not yet created when the function starts.
It's really easy to open gaping security holes using extract() on $_REQUEST, $_GET, etc. You have to be really sure of what you're doing, and use the proper flags on extract() to avoid clobbering important variables.
For instance, the submission by kake26 at gmail dot com will not only perfectly emulate register globals (that's bad), but it'll store it in a database and recall the same variables every time the script runs (essentially allowing an attacker to attack your script every time it runs via one attack). Oops!
To fix it, you'd have to get creative with flags. Maybe you could use EXTR_PREFIX_ALL instead of EXTR_OVERWRITE, for example. Of course, you should also sanitize the form elements to ensure there's no php code in them, and also to make sure any very important variables aren't in the form data. (like the classic $is_admin = true attack)
Re: anon at anon dot org, about extract() and null values
Personally I've found use extracting multiple resultsets from db where the latter would overwrite the previous when a variable is not null ( and optionally if its not >0 )
It would be useful if $extract_type was extended on top of these two:
EXTR_OVERWRITE
EXTR_SKIP
with something like this:
EXTR_OVERWRITE_NULL
- If there is a collision, overwrite the existing variable if it is null
EXTR_OVERWRITE_0
- Same thing but == 0 or null
EXTR_SKIP_NULL
- If there is a collision, skip the new variable if the existing is not null
EXTR_SKIP_0
- Same thing but == 0 or null
Those ought to cover a few good cases that aren't covered now.
Note that extract() will only create or overwrite variables in the current scope, so
<?
function test(){
$a=Array('b'=>1,'c'=>2);
extract($a);
}
test();
exit("$b");
?>
will produce no output, whereas
<?
function test(){
global $b;
$a=Array('b'=>1,'c'=>2);
extract($a);
}
test();
exit("$b");
?>
will output 1.
This function provides exactly the same functionality as extract except that a parameter was added defining the extract target.
This function can be used if your PHP installation does not support the required Flags or more important if you would like to extract arrays to another destination as to $GLOBALS, i.e. other arrays or objects.
The only difference to extract is that extract_to moves the array pointer of $arr to the end as $arr is passed by reference to support the EXTR_REFS flag.
<?php
if( !
defined
(
'EXTR_PREFIX_ALL'
) )
define
(
'EXTR_PREFIX_ALL'
,
3
);
if( !
defined
(
'EXTR_PREFIX_INVALID'
) )
define
(
'EXTR_PREFIX_INVALID'
,
4
);
if( !
defined
(
'EXTR_IF_EXISTS'
) )
define
(
'EXTR_IF_EXISTS'
,
5
);
if( !
defined
(
'EXTR_PREFIX_IF_EXISTS'
) )
define
(
'EXTR_PREFIX_IF_EXISTS'
,
6
);
if( !
defined
(
'EXTR_REFS'
) )
define
(
'EXTR_REFS'
,
256
);
function
extract_to
( &
$arr
, &
$to
,
$type
=
EXTR_OVERWRITE
,
$prefix
=
false
){
if( !
is_array
(
$arr
) ) return
trigger_error
(
"extract_to(): First argument should be an array"
,
E_USER_WARNING
);
if(
is_array
(
$to
) )
$t
=
0
;
else if(
is_object
(
$to
) )
$t
=
1
;
else return
trigger_error
(
"extract_to(): Second argument should be an array or object"
,
E_USER_WARNING
);
if(
$type
==
EXTR_PREFIX_SAME
||
$type
==
EXTR_PREFIX_ALL
||
$type
==
EXTR_PREFIX_INVALID
||
$type
==
EXTR_PREFIX_IF_EXISTS
)
if(
$prefix
===
false
) return
trigger_error
(
"extract_to(): Prefix expected to be specified"
,
E_USER_WARNING
);
else
$prefix
.=
'_'
;
$i
=
0
;
foreach(
$arr
as
$key
=>
$val
){
$nkey
=
$key
;
$isset
=
$t
==
1
? isset(
$to
[
$key
] ) : isset(
$to
->
$key
);
if( (
$type
==
EXTR_SKIP
&&
$isset
)
|| (
$type
==
EXTR_IF_EXISTS
&& !
$isset
) )
continue;
else if( (
$type
==
EXTR_PREFIX_SAME
&&
$isset
)
|| (
$type
==
EXTR_PREFIX_ALL
)
|| (
$type
==
EXTR_PREFIX_INVALID
&& !
preg_match
(
'#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#'
,
$key
) ) )
$nkey
=
$prefix
.
$key
;
else if(
$type
==
EXTR_PREFIX_IF_EXISTS
)
if(
$isset
)
$nkey
=
$prefix
.
$key
;
else continue;
if( !
preg_match
(
'#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#'
,
$nkey
) ) continue;
if(
$t
==
1
)
if(
$type
&
EXTR_REFS
)
$to
->
$nkey
= &
$arr
[
$key
];
else
$to
->
$nkey
=
$val
;
else
if(
$type
&
EXTR_REFS
)
$to
[
$nkey
] = &
$arr
[
$key
];
else
$to
[
$nkey
] =
$val
;
$i
++;
}
return
$i
;
}
extract_to
(
$myarray
,
$myobject
,
EXTR_IF_EXISTS
);
?>
When extracting from a row after a database query using for example:
$row = mysql_fetch_array($result, MYSQL_ASSOC)
extract($row);
I find that the resultant variables may not match the variable type in the database. In particular I have found integers in the database may gettype() to string on the extracted variable.
As shown in the example, if your 'prefix' is used, a single underscore is added to the name of the extracted variable. Meaning, a prefix of 'p' becomes a prefix of 'p_', so 'blarg' prefixed would be 'p_blarg'.
If you're not sure what variables you've created through extraction, you can call get_defined_vars() to see all defined variables in the current scope.
If an object is typecasted into an array and "extracted",only the public properties will be accessible.Methods are of course omitted.
<?php
class
Test
{
public
$name
=
''
;
protected
$age
=
10
;
public
$status
=
'disabled'
;
private
$isTrue
=
false
;
public function
__construct
()
{
$this
->
name
=
'Amolo'
;
$this
->
status
=
'active'
;
}
public function
getName
()
{
return
$this
->
name
;
}
public function
getAge
()
{
return
$this
->
age
;
}
public function
getStatus
()
{
return
$this
->
status
;
}
}
$obj
= (array) new
Test
();
var_dump
(
$obj
);
extract
((array)new
Test
());
echo
$name
;
echo
$status
;
echo
$age
;
echo
$isTrue
;
I use XDebug with NetbeansIDE to for analyzing and developing PHP Code. When debugging an extract statement no new variables appeared in the variable's list. Although all variables created by extract could be examined by explicit watch items and single variables appeared as soon as an PHP script makes use of them I am not sure weather it is a wrong configuration, a feature or a bug in XDebug.
A warning about extract() and null values.
This might be an actual Zend2 Engine bug, but it's bad programming practice, so I'm sharing it here instead.
I often work in envrionments where E_STRICT (which would prevent errors like this) isn't on, and I don't have access to change it. I also use a very simple template class that in a nutshell works like this:
$t = new Template('somefile.php');
$t->title = $title;
$t->body = $body;
$t->display();
display() more or less looks like this:
function display(){
extract(get_object_vars($this),EXTR_REFS);
ob_start(); include $this->templateFileName;
return ob_get_clean();
}
If any of the assigned values are null (let's say that in this case $title wasn't initialized above) it causes the engine to do all sorts of incredibly whacky stuff like certifiably lose track of variables in an incredibly inconsistent way. I traced the problem down to the fact that it's using the EXTR_REFS flag. I assume that in PHP's internal variable storage or reference counting mechanism, that trying to extract null references makes it lose track or count of something or rather.
In a nutshell, if you start getting wierd behavior when using extract() make sure that the array or object you are trying to get variables out of doesn't contain null keys or values!
In response to Dan O'Donnell's note:
"Presumably one easy way of dealing with this security issue is to use the EXTR_IF_EXISTS flag and make sure"
Not necessarily - even using the EXTR_IF_EXISTS flag could be extremely dangerous - imagine this code running...
<?php
global
$sql
;
function
runSql
()
{
$result
=
$conn
->
query
(
$sql
);
$conn
->
close
();
return
$result
;
}
function
extractGet
()
{
$name
=
''
;
$address
=
''
;
foreach (
$_GET
as
$key
=>
$value
)
$_GET
[
$key
] =
urldecode
(
$value
) ;
extract
(
$_GET
,
EXTR_IF_EXISTS
);
$sql
=
str_replace
(
'{NAME}'
,
$name
,
$sql
) ;
$sql
=
str_replace
(
'{ADDRESS}'
,
$address
,
$sql
) ;
}
function
outputResult
(
$res
)
{
echo
'<pre>'
.
print_r
(
$res
->
fetch_array
(
MYSQLI_NUM
) ).
'</pre>'
;
}
$sql
=
'SELECT postcode FROM Customers WHERE name={NAME} AND address={ADDRESS}'
;
extractGet
() ;
$res
=
runSql
() ;
outputResult
(
$res
) ;
?>
Now can you see a massive security issue here...
seems all well and good if we had a url like
mycode.php?name=joe%20bloggs&address=20%20Any%20Street
as that would specifically find joe bloggs of 20 any street.
however what if someone typed in
mycode.php?sql=SELECT%20password%20FROM%20Customers
or even worse
mycode.php?sql=DELETE%20from%20Customers
The problem here is that even though as far as you're aware you defined both name and address as the only two empty variables within that function - you may have forgotten about global variables, and these global variables could cause major security issues
In the example above $sql is defined as "SELECT postcode FROM Customers WHERE name={NAME} AND address={ADDRESS}" which seems all well and good, and safe, and then later on str_replace in the extractGet function replaces {NAME} and {ADDRESS} with the name and address variables from $_GET - but if GET contains an SQL variable then that would overwrite the global $sql variable before the str_replace function - and if the str_replace function finds no matches it just returns the original string - in the above two examples the SQL string would be "SELECT password FROM Customers" which in the example outputResult just prints the data retrieved from the database and so in this stage it could print all the customers passwords (hopefully encrypted!) to the screen (oops!) or in the second example the SQL string would be "DELETE from Customers" - with no WHERE clause that would delete all the data from the Customers table and of course a combination of
SELECT table_name FROM information_schema.tables
and
DROP TABLE <table_name>
could be a real disaster!
Of course, this is only a basic example, but it could be quite easy to forget about global variables and these global variables could quite easily be used with extract to cause serious security risks if GET, REQUEST or POST is sent to extract!
If you are working porting an older application, and taking the advice above, extracting only _SERVER, _SESSING, _COOKIE, _POST, _GET, you have forgotten to extract _FILES. Putting _FILES last and using EXTR_SKIP doesn't work because the name of the file upload box is already set as a variable containing only the temporary name of the uploaded file from one of the earlier extracts (I haven't tested to see which one specifically, however). A workaround is to put _FILES last and use EXTR_OVERWRITE. This allows extract to replace that temp-name-only variable with the full array of file upload information.
Here is a little example of how an extraction method should look like when it needs to work recursive (work on nested_arrays too)...
Note that this is only an example, it can be done more easily, and more advanced too.
<?php
function
extract_nested
(&
$array
,
$type
=
EXTR_OVERWRITE
,
$prefix
=
''
)
{
if (!
is_array
(
$array
))
{
return
trigger_error
(
'extract_nested (): First argument should be an array'
,
E_USER_WARNING
);
}
if (!empty (
$prefix
) && !
preg_match
(
'#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#'
,
$prefix
))
{
return
trigger_error
(
'extract_nested (): Third argument should start with a letter or an underscore'
,
E_USER_WARNING
);
}
if ((
$type
==
EXTR_PREFIX_SAME
||
$type
==
EXTR_PREFIX_ALL
||
$type
==
EXTR_PREFIX_IF_EXISTS
) && empty (
$prefix
))
{
return
trigger_error
(
'extract_nested (): Prefix expected to be specified'
,
E_USER_WARNING
);
}
$prefix
=
$prefix
.
'_'
;
foreach (
$array
as
$key
=>
$val
)
{
if (!
is_array
(
$array
[
$key
]))
{
switch (
$type
)
{
default:
case
EXTR_OVERWRITE
:
$GLOBALS
[
$key
] =
$val
;
break;
case
EXTR_SKIP
:
$GLOBALS
[
$key
] = isset (
$GLOBALS
[
$key
]) ?
$GLOBALS
[
$key
] :
$val
;
break;
case
EXTR_PREFIX_SAME
:
if (isset (
$GLOBALS
[
$key
]))
{
$GLOBALS
[
$prefix
.
$key
] =
$val
;
}
else
{
$GLOBALS
[
$key
] =
$val
;
}
break;
case
EXTR_PREFIX_ALL
:
$GLOBALS
[
$prefix
.
$key
] =
$val
;
break;
case
EXTR_PREFIX_INVALID
:
if (!
preg_match
(
'#^[a-zA-Z_\x7f-\xff]$#'
,
$key
{
0
}))
{
$GLOBALS
[
$prefix
.
$key
] =
$val
;
}
else
{
$GLOBALS
[
$key
] =
$val
;
}
break;
case
EXTR_IF_EXISTS
:
if (isset (
$GLOBALS
[
$key
]))
{
$GLOBALS
[
$key
] =
$val
;
}
break;
case
EXTR_PREFIX_IF_EXISTS
:
if (isset (
$GLOBALS
[
$key
]))
{
$GLOBALS
[
$prefix
.
$key
] =
$val
;
}
break;
case
EXTR_REFS
:
$GLOBALS
[
$key
] =&
$array
[
$key
];
break;
}
}
else
{
extract_nested
(
$array
[
$key
],
$type
,
$prefix
);
}
}
}
?>
When using EXTR_PREFIX_ALL - and probably all the other EXTR_PREFIX_* constants - and a numerically-indexed array, extract() will add an underscore ("_") between the prefix and the index.
<?php
extract
(array(
'foo'
,
'bar'
),
EXTR_PREFIX_ALL
,
'var'
);
print_r
(
get_defined_vars
());
?>
In the meantime, I'm using this:
// extract alternative
# extracts variables where new value is above the threshold or if old value is on or below the threshold (or var is not defined)
# an associative array is obviously the sane thing to pass
#
# I am absolutely certain someone will find obvious problems or errors with this
# I haven't even tried to compare other values than 0 so if you need to do that and surely finds obvious flaws,
# please mail me, I'd really like to know.
# benjaminATwebbutvecklarnaDOTse
// usage example:
# thrextract(mysql_fetch_assoc(mysql_query("SELECT preset_this,preset_that FROM site_preset WHERE ID = $site_id")));
# thrextract(mysql_fetch_assoc(mysql_query("SELECT preset_this,preset_that FROM category_preset WHERE ID = $category_id")));
function thrextract($arr,$thr = 0){
foreach($arr as $key => $var){
global $$key;
if($var > $thr or $$key <= $thr) $$key = $var;
}
}
Experimentally I found that calling extract() also shows the number of keys if the key is set and is not numeric ! Maybe there was a better definition than mine . Please have a look to this scripts :
<?PHP
$var
[
"i"
] =
"a"
;
$var
[
"j"
] =
"b"
;
$var
[
"k"
] =
1
;
echo
extract
(
$var
);
?>
<?PHP
$var2
[
"i"
] =
"a"
;
$var2
[
2
] =
"b"
;
$var2
[] =
1
;
echo
extract
(
$var2
);
?>
(Arash Moslehi)
The following is a neat use for extract to store and manipulate large amounts of form data from. I basically loop through the $_POST and implode it seperating the key and value pairs by a space. Then store it in a db, the reversing function basically explodes the string to a array. Then converts the indexed array to a associative array then uses extract to seal the deal and make it easily available within a program. My main reason for sharing these are the fact I make some big web applications that store allot of forum data in a DB and these functions make it very easy to quickly and easily store and recall the data. I've contributed it because I spent many hours creating this code and recall going "I wish someone had previously submitted it to the page notes". Would have saved me allot of time and agony and I'm sure I'm not the only person that could really benefit from it, so I decided to share.
<?php
$stack
= array();
foreach (
$_POST
as
$key
=>
$value
) {
array_push
(
$stack
,
$key
,
$value
);
}
$block
=
implode
(
" "
,
$stack
);
$query
=
"INSERT INTO `sometable` VALUES('"
.
$seluser
.
"','"
.
addslashes
(
$block
).
"');"
;
$result
=
mysql_query
(
$query
) or die(
"Query failed for block insert: "
.
mysql_error
());
?>
The nice thing is with the above we can quickly create a string of key and value pairs from the data the script got. Without really caring what their names are. You know how if register globals are on you say $someformvar rather than $_POST["someformvar"]; , basically the code below reads this previous created block returns it to that state. Sort of like presistant register globals.
<?php
$query
=
"SELECT * FROM `sometable` WHERE `blockid` = '"
.
addslashes
(
$bid
).
"';"
;
$result
=
mysql_query
(
$query
) or die(
"Query failed read: "
.
mysql_error
());
$sql
=
mysql_fetch_array
(
$result
,
MYSQL_ASSOC
);
$array
=
eplode
(
" "
,
$sql
[
"data"
]);
for (
$i
=
0
;
$i
<
sizeof
(
$array
);
$i
+=
2
) {
$myassoc
[
$array
[
$i
]] = isset(
$array
[
$i
+
1
])?
$array
[
$i
+
1
]:
NULL
;
}
extract
(
$myassoc
,
EXTR_OVERWRITE
);
?>
Here's a way to use extract in $_FILES arrays without using register_gloabals on.
I started to use extract a few weeks ago, and my codes hasn't been so clean since then. The use of the arrays $_POST and $_GET is ok, but one missed doublequote causes a lot of trouble.
Besides I teach PHP in a school, and this function has made my examples easier.
<?php
if(isset(
$_FILES
[
"file"
])){
extract
(
$_FILES
);
extract
(
$file
);
echo
$name
.
"<br>"
;
echo
$tmp_name
.
"<br>"
;
echo
$size
.
"<br>"
;
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
http://www.w3.org/TR/html4/loose.dtd
">
<html>
<head>
<title>Documento sin título</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<form action="" method="post" enctype="multipart/form-data" name="form1">
<p>
<input type="file" name="file">
</p>
<p>
<input type="submit" name="Submit" value="Enviar">
</p>
</form>
</body>
</html>
Hope this can help anyone.