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()); // Reveals $var_0 = 'foo' and $var_1 = 'bar'
?>
extract
(PHP 4, PHP 5)
extract — Sætter variabler efter indholdet af et array
Beskrivelse
Denne funktion bruges til at fremstille variabler fra et array. Den tager et associativ array var_array og behandler nøglerne som variablenavne og værdierne som de nye variablers værdier. For hvert nøgle/værdi par vil den lave en variable, alt efter hvad extract_type og prefix er sat til.
Note: Vi starter ved version 4.0.5, hvor denne funktion returnerede antallet af variabler som blev udpakket.
Note: EXTR_IF_EXISTS og EXTR_PREFIX_IF_EXISTS blev tilføjet i version 4.2.0.
Note: EXTR_REFS blev tilføjet i version 4.3.0.
extract() kontrollerer hver nøgle for at se om det er et korrekt variablenavn. Den tjekker også for om der allerede er sat en variable med det navn. Måden ukorrekte variablenavne og sammenfald med tidligere variabler skal behandles på, bestemmes ved parameteren extract_type . Den kan blive sat til en af følgende værdier:
- EXTR_OVERWRITE
- Hvis der er et sammenfald, overskriv den eksisterende variable.
- EXTR_SKIP
- Hvis der er et sammenfald, overskriv ikke den eksisterende variable.
- EXTR_PREFIX_SAME
- Hvis der er et sammenfald, tilføj prefix foran variablenavnet.
- EXTR_PREFIX_ALL
- Start alle variabelnavne med prefix . I PHP 4.0.5 ville det også inklidere nummervariabler.
- EXTR_PREFIX_INVALID
- Indsæt kun prefix foran ukorrekte/nummer variabler. Denne mulighed blev tilføjet i PHP 4.0.5.
- EXTR_IF_EXISTS
- Overskriver kun variablen hvis den allerede findes og ellers skal den ikke gøre noget. Dette er brugbart ved definering af en liste af korrekte variablenavne og man derefter udpakker de variabler der er blevet sat med f.eks. $_REQUEST. Denne mulighed blev tilføjet i PHP 4.2.0.
- EXTR_PREFIX_IF_EXISTS
- Fremstiller kun variablenavne med prefix, hvis den orginale version af samme variable allerede findes. Denne mulighed blev tilføjet i PHP 4.2.0.
- EXTR_REFS
- Udpakker alle variabler som referencer. Det betyder at de nye variabler peger på de værdier der står i var_array parameteren. Du kan bruge denne indstilling som den eneste eller du kan sætte den sammen med andre værdier ved at indsætte OR mellem de to settings i extract_type . Denne indstilling blev muligt i PHP 4.3.0.
Hvis extract_type ikke er sat, vil den som som standard blive sat til EXTR_OVERWRITE.
Bemærk at prefix kun er krævet hvis extract_type er EXTR_PREFIX_SAME, EXTR_PREFIX_ALL, EXTR_PREFIX_INVALID eller EXTR_PREFIX_IF_EXISTS. Hvis variabelnavnet med prefix foran, ikke er et korrekt variablenavn, vil den variable ikke blive oprettet.
extract() returnerer antallet af variabler der er blevet oprettet korrekt.
Brug ikke extract() ved usikker data som f.eks. bruger-input ($_GET, ...). Hvis du gør dette, f.eks. hvis du ønsker at køre gammel kode som ikke bruger register_globals, vær sikker på at du bruger en af de ikke overskrivende indstillinger extract_type kan sættes til, som f.eks. EXTR_SKIP og pas på hvis du udpakker $_SERVER, $_SESSION, $_COOKIE, $_POST og $_GET i den rækkefølge.
Et eksempel hvor brugen af extract() ville være perfekt, er ved et associativt array fra funktionen wddx_deserialize().
Example#1 extract() eksempel
<?php
/* Gå ud fra at $var_array er et array returneret af 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";
?>
Ovenstående eksempel vil udskrive:
blue, large, sphere, medium
Variablen $size blev ikke overskrevet, fordi vi havde sat EXTR_PREFIX_SAME, hvilket resultere i $wddx_size bliver lavet. Hvis EXTR_SKIP var bestemt, ville $wddx_size ikke engang blive lavet. EXTR_OVERWRITE ville have betydet at $size havde fået værdien "medium" og EXTR_PREFIX_ALL ville have betydet nye variablenavne kaldet $wddx_color, $wddx_size og $wddx_shape.
Du skal bruge et associativt array. Et array indekseret med numre vil ikke komme med et resultat med mindre at du bruger EXTR_PREFIX_ALL eller EXTR_PREFIX_INVALID.
Se også compact().
extract
24-Aug-2009 11:04
17-Mar-2008 03:15
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;
}
}
17-Mar-2008 02:19
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.
13-Mar-2008 11:18
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.
21-Apr-2007 07:25
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.
13-Mar-2007 08:26
I would draw your attention to the user note at the very end of this page regarding PREFIXES. The user points out that php adds a '_' to your prefixes.
31-Aug-2006 05:05
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)
16-Mar-2006 05:24
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;
}
// e.g.:
extract_to( $myarray, $myobject, EXTR_IF_EXISTS );
?>
08-Mar-2006 12:21
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);
// be careful that if you need to extract $k, $v or $V variables you should find other names for them in the lines above (ie. $__k, $__v and $__V)
}
$huge_text = '...';
$a = array ('arg1' => 'val1', 'arg2' => &$huge_text); // in this call, only $arg2 will be a true reference in the function
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.
20-Jan-2006 09:32
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); // returns 3
?>
<?PHP
$var2["i"] = "a";
$var2[2] = "b";
$var2[] = 1;
echo extract($var2); // returns 1
?>
(Arash Moslehi)
27-Nov-2005 07:41
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.
30-May-2005 07:02
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!
01-May-2005 03:59
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);
}
// store it
$block = implode(" ",$stack); // yeilds a space delimited string
// insert query to store string in DB here, like the one below
$query = "INSERT INTO `sometable` VALUES('".$seluser."','".addslashes($block)."');";
$result = mysql_query($query) or die("Query failed for block insert: " . mysql_error());
// note $seluser in my case is a user ID associated with that block
// in one of my web apps
?>
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
// insert query to grab the previously stored string here
$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);
// now you're key and value pairs from $_POST have been restored
// instead of $_POST
?>
14-Mar-2005 10:33
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
/**
* A nested version of the extract () function.
*
* @param array $array The array which to extract the variables from
* @param int $type The type to use to overwrite (follows the same as extract () on PHP 5.0.3
* @param string $prefix The prefix to be used for a variable when necessary
*/
function extract_nested (&$array, $type = EXTR_OVERWRITE, $prefix = '')
{
/**
* Is the array really an array?
*/
if (!is_array ($array))
{
return trigger_error ('extract_nested (): First argument should be an array', E_USER_WARNING);
}
/**
* If the prefix is set, check if the prefix matches an acceptable regex pattern
* (the one used for variables)
*/
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);
}
/**
* Check if a prefix is necessary. If so and it is empty return an error.
*/
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);
}
/**
* Make sure the prefix is oke
*/
$prefix = $prefix . '_';
/**
* Loop thru the array
*/
foreach ($array as $key => $val)
{
/**
* If the key isn't an array extract it as we need to do
*/
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;
}
}
/**
* The key is an array... use the function on that index
*/
else
{
extract_nested ($array[$key], $type, $prefix);
}
}
}
?>
03-Mar-2005 01:23
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!)
To make this perfectly clear (hopefully), an underscore is always added when the string is prefixed.
extract(array("color" => "blue"),EXTR_PREFIX_ALL,'');// note: prefix is empty
is the same as
$color='_blue';
17-Nov-2004 06:44
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.
03-Oct-2004 12:03
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.
