php array in_array oddity - php

of all the languages i know im the weakest in php...
I have a script... that takes a csv file and does some stuff with it... fairly simple.
the issue i am having:
in_array('username', $headers) ... returns null...
while...
print_r ($headers); shows username being the first entry in the csv.
thoughts? mistakes i may have made?
TIA
code here
/// Turn the string into an array
$rows = explode("\n", $this->raw_data);
/// First row includes headers
$headers = $rows[0];
$headers = explode($this->delimiter, $headers);
/// Trim spaces from $headers
$headers = array_map('trim', $headers);
/// Check that there are no empty headers. This can happen if there are delimiters at the end of the file
foreach($headers as $header){
if(!empty($header)){
$headers2[] = $header;
}
}
$headers = $headers2;
if(! in_array('password', $headers)){
/// Add password column for generated passwords
$headers[] = 'password';
}
/// Add status column to the headers
$headers[] = 'status';
$this->headers = $headers;
/// Check that at least username, name and email are provided in the headers
if(!in_array('username', $headers) ||
!in_array('name', $headers) ||
!in_array('email', $headers)){
echo "error\n";
return false;
}

You can use the built in str_getcsv() function. Try replacing the $headers variable assignment with
$headers = str_getcsv($rows[0], $this->delimiter);
Then find the value(column) you want and loop through the rest of the $rows using the same str_getcsv() function to get the matches you need.
You may want to use the file() function to grab the file in an array delimited by newlines to begin with, as well.

Check the first three functions in this list . Your problem can arise from several causes. Start by elimination of unnecessary parsing by using the built in CSV function.

I don't see code that sets $headers2 to be an array. Is the first assignment to that variable getting lost once the second assignment happens which turns it into an array?

Related

How to convince Zend Framework to send duplicate headers?

With Content-Security-Policy headers there is often a need to send more than one such header or to union merge these headers before sending them. This arises from the fact that each module/package of an application may define its own CSP.
Right now ZF3 doesn't seem to have a way to handle such a scenario. If I try to add multple CSP headers, they keep overwriting each other so that only the last added header is sent.
Code to reproduce the issue
$headers = $controller->getResponse()->getHeaders();
$headers->addHeader(new ContentSecurityPolicy($someDirectives));
$headers->addHeader(new ContentSecurityPolicy($someOtherDirectives));
Expected results
The expected result is a response with two CSP headers (OR a union merged CSP).
Actual results
The second addition overwrites the first, the response only contains that one CSP.
Question
How can I make ZF3 send multple headers with the same fieldname?
For more information about this problem, also see my own issue on github https://github.com/zendframework/zend-http/issues/159
You should be able to create a simple workaround using GenericMultipleHeader as a reference (and changing comma delimiter to semicolon):
class MultiContentSecurityPolicy extends ContentSecurityPolicy implements MultipleHeaderInterface {
public static function fromString($headerLine)
{
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
if (strpos($fieldValue, ';')) {
$headers = [];
foreach (explode(';', $fieldValue) as $multiValue) {
$headers[] = new static($fieldName, $multiValue);
}
return $headers;
} else {
$header = new static($fieldName, $fieldValue);
return $header;
}
}
public function toStringMultipleHeaders(array $headers)
{
$name = $this->getFieldName();
$values = [$this->getFieldValue()];
foreach ($headers as $header) {
if (! $header instanceof static) {
throw new Exception\InvalidArgumentException(
'This method toStringMultipleHeaders was expecting an array of headers of the same type'
);
}
$values[] = $header->getFieldValue();
}
return $name . ': ' . implode(';', $values) . "\r\n";
}
}
Then use that class instead of ContentSecurityPolicy:
$headers = $controller->getResponse()->getHeaders();
$headers->addHeader(new MultiContentSecurityPolicy($someDirectives));
$headers->addHeader(new MultiContentSecurityPolicy($someOtherDirectives));
Since Zend checks the interface rather than the class, should work fine.
This is the accepted HTTP standard and the PHP Core upholds this. http://php.net/manual/en/function.header.php
If you set headers in PHP header("TESTHeader: Test1"); header("TESTHeader: Test2") only one will come through and this is correct to specification RFC2616 Section 4.2 Page 31&32
If you wish to send multiple values your header should construct as header("TESTHeader: Test1, Test2");. while it is possible to send multiple same name headers through PHP it is not recommended as browsers & servers receiving 2 sets of the same header should convert them to the above style this could cause problems as you will not know for certain what format they are in. header("TESTHeader: Test1", false); header("TESTHeader: Test2", false). depending on the server or clients adherence to the RFC or HTTP Version.
So this answer is the reason as to why you are not allowed to send the same header multiple times in ZF3, it can't identify when to use the overwrite or not to based on you setting the header. to get around this and use multi-valued headers you can use Jim's answer
make your own multipleheader class, add the function you need (MultipleHeaderInterface) then add your header in a multistering and finally call it in your
$headers = $controller->getResponse()->getHeaders();
(call the new function with the new fromStringHeaders)

How to send message a list with foreach only one message

I am trying to send a message with one list with PHP, here is my code:
$packs = $db->QueryFetchArrayAll("SELECT * FROM configmoreg");
foreach($packs as $pack) {
echo '<a>'.$pack['setting_id'].'</a>
<a>'.$pack['config_name'].'</a>
<a>'.$pack['config_value'].'</a>
<br>';
}
mail('example#something.com',"My List",$msg);
How do I make it send only one message with list on it?
For example:
id 00000001
My_name game_over_new
NR_Job 11
type_secure MD5
5 etc...
Build up a string in the for-loop, and send that. Consider:
$msg = '';
foreach($packs as $pack)
$msg .= "<a>${pack['some_key']}</a>";
$subject = "My List";
mail('null#example.com', $subject, $msg);
Meanwhile, I gather you're still learning PHP, so hold on to this next piece of advice until you're ready: don't use PHP's builtin mail() function, use PHPMailer.
Try adding all the variables to an array; then send the array containing the variables.
As you don't know how to use arrays I suggest reading:
https://www.w3schools.com/php/php_arrays.asp
However to get what you want, you'll want something along these lines:
$infoToSend = array($pack['setting_id'], $pack['config_name'], $pack['config_value']);
mail('example#something.com',"My List", $infoToSend);

is there reverse function for \http_parse_headers()?

PHP function \http_parse_headers() parses HTTP headers into an associative array.
But is there some reverse function? Which parses associative array into HTTP headers?
Cannot find anything :(
(it's for saveing email into textual .eml file)
There isn't a function that turns associative array into text-representation of headers. The reason: this function is extremely trivial to create.
Headers are defined as key: value delimiter is \r\n.
There is another \r\n delimiter between headers and body.
Lets take an example array:
$headers = [
'Content-Length': 50,
'Content-Encoding': 'gzip'
];
The goal: provide a string that represents HTTP headers
function parse_array_to_headers(array $headers)
{
$result = [];
$delimiter = "\r\n";
foreach($headers as $name => $value)
{
$result[] = sprintf("%s: %s", $name, $value);
}
return implode($delimiter, $result);
}
Note: this function will not check the validity of array and it won't return the string with two repetitions of \r\n at the end. This example serves to show how easy it should be to add missing function. Adjust according to your needs. Also, I didn't test this so don't copy paste it! :)

PHP foreach loop inside foreach loop

I'm trying to do a foreach loop inside a foreach loop.
I have a form where the user type in some text and hit send. On the server site I loop through an array with email addresses and send out the text message.
Now I also want the user to be able to use variables in the textarea, like $name.
So my loop should first loop through the emails, and then str_replace the userinput $name variable, with the names in my array.
The loop works fine with the email part ($tlf), but not the replace $name part.
Could some spot what I am doing wrong?
$message = stripslashes(strip_tags($_POST['message2']));
$tlf=array("name1","name2");
$test=array("mname1", "mname2");
$subject = "Hello world";
$from = "me#gmail.com";
$headers = "From: $from";
foreach($tlf as $name){
$to = $name. "#gmail.com";
foreach($test as $navn){
$message = str_replace('$navn', $navn, $message);}
mail($to,$subject,$message,$headers);
}
Thanks a lot.
EDIT:
The output is an email sent. Say the user type in "hello $name".
I want it to first loop through the $tlf array, in this case creating 2 emails. This goes in as $to in the first loop. This works.
Now the next loop should recognize the user input "hello $name" and loop through the $test array replacing the user $name variable.
The output would be 2 emails send.
Mail output:
to: name1#gmail.com
message: hello mname1
Mail output:
to: name1#gmail.com
message: hello mname2
Let me know if I need to explain better, its hard for me to explain sorry.
When you do the following:
str_replace('$navn', $navn, $message)
Then all literal occurences of $navn will be replaced (the first, the second, the third, ...). So running through that loop a second time can't possibly replace anything more.
You will need to define two placeholders, or make some distinction, or use preg_replace_callback if you want to declare in which order (or other logic) the possible replacement strings are applied.
If you had told us (but you haven't) you only wanted to replace the first occurence in each iteration, then a normal preg_replace(.., .., .., 1) would work.
Is this what you want?
$message = stripslashes(strip_tags($_POST['message2']));
$tlf=array(
array("email" => "name1", "name" => "mname1"),
array("email" => "name2", "name" => "mname2")
);
$subject = "Hello world";
$from = "me#gmail.com";
$headers = "From: $from";
foreach($tlf as $contact){
$to = $contact["email"] "#gmail.com";
$replacedMessage = str_replace('$navn', $contact["name"], $message);
mail($to,$subject,$replacedMessage,$headers);
}

Adding input field to PHP emailer only if it exists, how?

I have a form with inputs for 'name' and 'email'. And another for 'data-1'. The user can click on add button and jQuery will dynamically add a input for 'data-2', 'data-3' etc..as needed.
The form is posted to a PHP emailer script which validates fields and places data into a template for mailing.
How can i add inputs 'data-2', 'data-3' etc.. if they are created? And if they are not how can i avoid gaps in my email template?
(is there a way to write it so if the post is received add this and if not do nothing?)
Here is an example of the code i am using:
$name = $_POST['name'];
$email = $_POST['email'];
$data-1 = $_POST['data-1'];
(do i need to add: $data-2 = $_POST['data-2'] and $data-3....up to a set value of say 10?)
$e_body = "You were contacted by $name today.\r\n\n";
$e_data = "Data Set 1: $data-1.\r\n\n";
Here is where i would like to show "Data Set 2/3/4....etc" if they exist
$e_reply = "You can contact $name via email, $email";
$msg = $e_body . $e_data . $e_reply;
if(mail($address, $e_subject, $msg, "From: $email\r\nReply-To: $email\r\nReturn-Path: $email\r\n")) {
I hope that is clear and thank you for any help or guidance
thom
You should be using input arrays for this purpose.
In your HTML, set the name of the form element to conform to this naming scheme: data[].
Then, when the form is submitted you can simply loop through this array and add fields to the email within the loop:
$name = $_POST['name'];
$email = $_POST['email'];
$data = $_POST['data'];
$e_data = '';
foreach($data as $i => $d) {
if((int) $i != $i) continue; //thanks Alex
$e_data .= "Data Set {$i}: " . $d . "\r\n\n";
}
//...
On the client side, your code should be something like this:
<input type="hidden" name="data[]"/>
As a general point form processing is trick and has many traps for the unwary. It's worth having a look at this post on best practice form processing
The crux of your problem is that you do not know how many "data" values you will get in your $_POST array. The answer is simply to iterate over the $_POST array to find your data values.
$rawData = array();
foreach ($_POST as $index => $value) {
// Test for a "data-n" index
if ((preg_match('#^data-\d+#i', $index, $matches))) {
$rawData[] = $value;
}
}
The above code will copy all the $_POST values with keys of the form 'data-0', 'data-1', etc. You can then filter and validate these values.
All we do is iterate over $_POST to get each key and value. We then test the key using preg_match to see if it starts with the string 'data-' and is followed by one or more digits. If so, we add it to our raw (unfiltered, non validated) data.
In this example, we could replace the preg_match with the strpos function -
if ( strpos ($index, 'data-') === 0) {
The use of the preg_match gives us more flexibility. For example, if you wanted to capture the numeric portion of your 'data-n' keys - 'data-23', 'data-999', 'data-5', etc. Then change the if statement to
if ((preg_match('#^data-(\d+)#i', $index, $matches))) {
$rawData[$matches[1]] = $value;
}
The variable $matches is an array that captures the results of the search. The complete matching string is is $matches[0]. However, we have enclosed the digit matching pattern in parenthesis and hence the captured digits are placed into $matches1 which we then use to key the $rawData array. In this case $rawData would have the keys = 23, 999 and 5.
Use something like this:
if(isset($_POST['data-1']))
{
// $_POST['data-1'] exists, include it.
}
else
{
// $_POST['data-1'] doesn't exists, don't include it.
}

Categories