Checking for empty attributes while parsing an XML file - php

A critical function in a PHP script I am debugging get's two attributes from an XML file on an external site. The attributes are labeled 'code' and 'locationCode' within a tag called Channel. The issue is that sometimes the locationCode is posted as an empty string ('') or not defined at all by the site for channels I cannot use, so I need to loop through the channels until I find a non-empty locationCode string. To do this, I created a while loop, but my current implementation does not successfully loop through the location codes. Is there a better way to implement this?
Current code:
public function setChannelAndLocation(){
$channelUrl="http://service.iris.edu/fdsnws/station/1/query?net=".$this->nearestNetworkCode.
"&sta=".$this->nearestStationCode."&starttime=2013-06-07T01:00:00&endtime=".$this->impulseDate.
"&level=channel&format=xml&nodata=404";
$channelXml= file_get_contents($channelUrl);
$channel_table = new SimpleXMLElement($channelXml);
$this->channelUrlTest=$channelUrl;
//FIXME: Check for empty locationCode string
$this->channelCode = $channel_table->Network->Station->Channel[0]['code'];
$this->locationCode = $channel_table->Network->Station->Channel[0]['locationCode'];
$i = 1;
while($this->locationCode=''){
$this->channelCode = $channel_table->Network->Station->Channel[$i]['code'];
$this->locationCode = $channel_table->Network->Station->Channel[$i]['locationCode'];
$i++;
}
}
sample XML file for code: http://service.iris.edu/fdsnws/station/1/query?net=PS&sta=BAG&starttime=2013-06-07T01:00:00&endtime=2013-10-12T18:47:09.5000&level=channel&format=xml&nodata=404

There are two problems I can see with this line:
while($this->locationCode=''){
Firstly, you have typed an assignment (=) when what you wanted was a comparison (==). So instead of testing the condition, this line is over-writing the current value of $this->locationCode and then testing the "truthiness" of '', which evaluates to false, so the while loop never runs.
Secondly, the sample XML file shows that the attribute is not in fact empty, but contains some whitespace. Assuming these are the values you want to ignore (there are none in the sample right now which have any other value), you can use trim() to eliminate the whitespace from the comparison, giving you this:
while( trim($this->locationCode) == '' ) {

Related

I need to change the php code in the file so instead of the current json output

So i am using this PHP code to create the json output, and I am having an issue where it’s creating an array of array with the info. I would like to get rid of one array and just display the list of API’s thats been used and number that has been used.
Looks as though the difference is you have...
"apis":[{"item_search":"0\n"},{"item_recommended":"0\n"}]
and want
"apis":{"item_search":"0\n","item_recommended":"0\n"}
If this is the case, you need to change the way you build the data from just adding new objects each time to setting the key values directly in the array...
$zone_1 = [];
foreach($zone_1_apis as $api_name ) {
$zone_1[substr($api_name, 0,-5)] = file_get_contents('keys/'.$_GET['key'].'/zone_1/'.$api_name);
}
You also need to do the same for $zone_2 as well.
It may also be good to use trim() round some of the values as they also seem to contain \n characters, so perhaps...
trim(file_get_contents('keys/'.$_GET['key'].'/zone_1/'.$api_name))

Wordpress $wpdb->get_results(...) issues with comparing strings

I am trying to iterate through the rows in a phpbb table called phpbb_posts and extract each entry in phpbb's "post_subject" column and compare its value with a predefined string in Wordpress PHP file but I am having some issues - the expressions don't evaluate to true.
My phpBB's tables are installed in WP's database so I have full access to the values.
See the code below to demonstrate the issue I am having.
function matchPhpBBTopic()
{
global $wpdb;
$wp_post_title_string = get_the_title();
$result = $wpdb->get_results("SELECT * FROM phpbb_posts");
foreach($result as $row)
{
$phpbb_post_title_array = array($row->post_subject);
$phpbb_post_title_string = implode("", $phpbb_post_title_array);
// One of the values in $row->post_subject contains
// the value in $wp_post_title_string
if (strcmp($wp_post_title_string, $phpbb_post_title_string) == 0)
{
// This line never runs but the $wp_post_title_string value
// is there, in the table, I've printed it and it's there
echo 'We found a match!<br>';
}
}
}
Any assistance would be appreciated.
So in other words, I have a topic posted in WP and I have exactly the same topic posted in phpBB and I want to iterate through the phpBB's table and when I find the topic, I want to run some code. I don't understand why the "if" expression does not run.
Couldn't you just do:
if ($wp_post_title_string == $phpbb_post_title_string) {}
I don't think strcmp() is appropriate. It converts the string to encoding numbers.
http://us1.php.net/strcmp
Also check for lower and upper case, spaces, and different encodings.
Do strtolower() and trim() first and see what you get.
Also looks like you're imploding subject and title, so don't think they'll match.

PHP eval() function

The PHP function eval() appears to be a rather interesting function. Can someone explain why it works in this given situaton, on line: 14
function Parse($inFrontEnd)
{
// Now create an array holding translation tokens with some from above
// Load translation table into buffer
$tableLines = file(Utilities::GetRelativePath(TTABLE_DIR).TTABLE); // Array of lines from TTable.cfg
// Explode by whitespace
foreach($tableLines as $aLine)
{
$lineParts = EXPLODE(' ', $aLine);
$word = "/".$lineParts[0]."/";
$definition = $lineParts[1];
// Add key (word) => value (definition) to array
// Eval() to return value of the const
Main::$translateChars[$word] = eval("return $definition;");
}
// Read data from template file
$parseArray = file($inFrontEnd); // Load FrontEnd source code into array ready for parse
/* Perform the translation of template by the translation table defined data */
$parseArray = preg_replace(array_keys(Main::$translateChars), array_values(Main::$translateChars), $parseArray);
return $parseArray;
}
So what I'm doing here is reading in a template from a template directory. The templatename.php file comprises of text tokens written constant-like, which are then translated by regular expressions replacing the tokens with the data the constants with their names hold, thus returning a fully validated page of a webpage, which is printed for the user to view. This allows pages to be very dynamic by allowing the reuse of these tokens over many webpages (templates).
My question is: I had trouble for a while with the line that uses eval(). What I'm trying to do there is fill an array with each key being the name of the constant read in from, what I've named, the translation table (TTable.cfg), which holds the name of each token and the constant associated with it:
TITLE TITLE
CSS_INCLUDE CSS_INCLUDE
SHOW_ALL_POSTS SHOW_ALL_POSTS
...
So with the protocol [TOKEN] [CONSTANT][CR][LF]
The keys within the array would be created fine, but the values would return null or break my code when I had the key be associated with: constant($definition);
It complained it couldn't find the constants being declared. However, when I use eval as is on this line, each key associated with: eval("return $definition;");
it works as I want it - the values as their corresponding constant's data.
I do apologise for the length of this post. I couldn't find any other example for my question other than the case I found it in.
The value of the variable $definition is replaced into the string definition "return $definition;", as you're using double quotes. Hence, what is passed to eval is essential something like this: "return FOO;", where FOO is the value of the variable $definition.
Now, that code is evaluated using eval(), and the result is returned as the result of the evaluation, which is the value of the constant FOO (different in each iteration).
Using the constant in this case makes more sense: It is faster, potentially securer, and more readable.
if ( defined( $definition ) ) {
$constval = constant( $definition );
}
else {
$constval = $definition;
}
This will also give you some insight of why it works when using eval() and not just constant(); PHP replaces unknown constants with their respective names, thus eval works in your case. However, any other way would raise warnings and be a bad practice, as it doesn't make clear what's going on to the reader.
Remember, eval is evil, so don't use it, when you can avoid it. Here you could just use constant instead.
The tiniest of oversights. I forgot to clean $definition after I exploded it from each line of the translation table. So a simple trim() has solved the problem.
constant($definition);
Now works.
Crazy :D

Erratic behaviour when comparing PHP imploded arrays with form field values using JavaScript

I've got a PHP Object, whose properties are initialized the following way:
$this->contact = implode(PHP_EOL,$description->getContact()) . PHP_EOL;
The only exceptions are two properties named version and bugs.
This object is then encoded into a JSON object and passed into the following javascript, which compare the JSON object with value from a form.
function compareEntry(data){
var dataProperties = ["version", "bugs", "scenario", "exception", "instruction", "sources", "risks", "test", "contact"];
var hasChanged = false;
for(var i = 0; i < dataProperties.length; i++){
var dataProperty = dataProperties[i];
alert("Original: '" + data[dataProperty] + "'\nModified: '" + document.myform[dataProperty].value + "'\nTest Value: " + (!data[dataProperty].localeCompare(document.myform[dataProperty].value)));
if(!data[dataProperty].localeCompare(document.myform[dataProperty].value)){
hasChanged = true;
}
}
[...]
In the exception of version and bugs, all other properties are compared with the value in the textarea.
The form fields are initialized with the value of the PHP object. When I submit the form the function is called. If I submit the form without changing any value, it still give me a false when comparing a property with the value of a textarea. Why and how could I correctly compare them?
Notes: The PHP Object is a reflection of a MySQL entry which was created with the same form. In between, the information was encrypted and decrypted. But it shouldn't play a role, because the PHP/JSon object and the initial value of the form are from the same source.
EDIT
After the explanation of Frode, I changed my testing statement to:
data[dataProperty].localeCompare(document.myform[dataProperty].value)!=0
But afterwards I noted two discrepencies.
Properties version and bugs which until then returned true when tested return now false. But in the contrary to the other properties, I don't manipulate the values when I'm retrieving them from the database. The value of the property version is stored in a select tag in the form.
And weirder is, when I'm changing one of the value in the textarea, instead of giving me false, it gives me true.
It occured to me that it may be due to the implementation of javascript of the browser I use. But the result I got is not quite as I expected it. Whereas, I've got the described behaviour in Firefox and Chrome, IE and Opera throw always false (with the notable exception of the comparing the version, which gave me true in IE, although he couldn't retrieve the value of the select tag).
Should I maybe use some other method to compare my strings?
EDIT 2
After taking the suggestion of WoLpH, I changed the test condition to:
data[dataProperty].trim() document.myform[dataProperty].trim()
Where trim() is the function described in this other question. And the result are the inverse of what I had in the first EDIT. Except for Chrome who seems to assign it's boolean in random. There seems to be something really wrong in my data in a way.
Here is an example of a JSON object as I can see it in Firefox (variable data in the code snippet).
{"version":"REL-773","bugs":"20831","scenario":"THIS IS A TEST\r\n\r\nThis is the what happens: stuffs.\r\n","exception":"N\/A\r\n","instruction":"1. First Step.\r\n2. Second Step.\r\n2. Third Step\r\nIt is longer.\r\n4. Fourth Step.\r\n5. Fifth Step.\r\n6. Sixth Step.\r\n","sources":"me\r\n","risks":"High risks as it is just for testing of the web application.\r\n","test":"1. Select an entry\r\n2. Change some data such as <HOME>\/path\/\r\n3. See if the application run as expected!\r\n","contact":"me#web.de\r\n"}
EDIT 3
Using the function escape() to escape all special characters of the two strings, I noticed that in the character %OA is written as %OD%OA in the JSON object. It made me suspect that my trimming function doesn't replace correctly the \r\n by \n. (trimming function that I added after the suggestion of the posters here.)
Here is the function I use:
if(typeof(String.prototype.trim) === "undefined")
{
String.prototype.trim = function()
{
return String(this).replace(/^\s+|\s+$/g, '').replace(/\r\n/g,"\n");
};
}
First, Disclaimer: I have the feeling that maybe this isn't the definite answer but more of a workaround. As this is the only way I could deal with this problem.
Now, since I had posted this question, I learned that client-side form validation is not enough. Not only it not enough, but in my case it is not needed as it wouldn't bring anything in the user experience to know that a value has been changed. It is much more interesting for the user to know that a value is not well formatted or just plain wrong. So I migrated the comparison check to the server side.
First I encase my PHP information in a json string, being sure to escape all the relevant characters. I first ensured that the quote symbol was escape correctly, and then I replaced characters which could be problematic by there unicode equivalent, before putting the resulting string in a hidden input of my form.
//escaping ",' and other throublesome characters properly for json
$json_string = str_replace('\'', "\\'", json_encode($objEncasing));
$json_string = str_replace(array('\\"', '\\\'', '&','<','>'), array('\\u0022', '\\\u0027', '\\u0026', '\\u003C', '\\u003E'), $json_string);
echo "<input name='json' type='hidden' value='".$json_string."' />";
One should note that the json object correspond to the information before any change are made in the form, thus why the json string is formatted in PHP. The form information is then sent through POST to a new script which will do all the necessary work.
Now first thing I do in the receiving script, is retrieve the json variable, but one should not forget to check for magic quotes:
if(get_magic_quotes_gpc()){
$json_string = stripslashes($_POST['json']);
}else{
$json_string = $_POST['json'];
}
Now to convert the json object into an array and the you can compare it to the $_POST array (with the exception of the json value):
if(!empty($json_string)){
$json_encasing = json_decode($json_string, true);
$gotChange = false;
foreach($_POST as $key => $value){
if($key != "json"){
//Compare the value, if something change set $gotChange to true
$value = stripslashes($value);
if($value != $json_encasing[$key]){
$json_encasing[$key] = $value;
$gotChange = true;
}
}
}
if($gotChange){
//Do your stuff
}
}
As I'm doing that on my Server, I don't need to anticipate several different behaviour. So my advice is, if you can help it, do your stuff server-side.
Javascript's string.localeCompare returns 0 if the strings compared are identical, and -1 or 1 otherwise. So your if clause:
if(!data[dataProperty].localeCompare(document.myform[dataProperty].value)){
hasChanged = true;
}
.. will in fact set hasChanged to true when the strings are equal. Try removing the ! and see if it behaves as you expect.

how do i use php to read an external file and put insides into variables?

I had no idea to correctly form the title of this question, because I don't even know if what I'm trying to do has a name.
Let's say I've got an external file (called, for instance, settings.txt) with the following in it:
template:'xaddict';
editor:'true';
wysiwyg:'false';
These are simple name:value pairs.
I would like to have php take care of this file in such a way that I end up with php variables with the following values:
$template = 'xaddict';
$editor = 'true';
$wysiwyg = 'false';
I don't know how many of these variables I'll have.
How should i go and do this?
The data inside the file is in simple name:value pairs. No nesting, no complex data. All the names need to be converted to $name and all the values need to be converted to 'value', disregarding whether it is truly a string or not.
$settings = json_decode(file_get_contents($filename));
assuming your file is in valid JSON format. If not, you can either massage it so it is or you'll have to use a different approach.
Do you want 'true' in "editor:'true'" to be interpreted as a string or as a boolean? If sometimes string, sometimes boolean, how do you know which?
If you have "number='9'" do you want '9' interpreted as a string or an as an integer? Would '09' be a decimal number or octal? How about "number='3.14'": string or float? If sometimes one, sometimes the other, how do you know which?
If you have "'" (single quote) inside a value is it escaped? If so, how?
Is there any expectation of array data?
Etc.
Edit: This would be the simplest way, imo, to use your example input to retrieve your example data:
$file = 'test.csv';
$fp = fopen($file, 'r');
while ($line = fgetcsv($fp, 1024, ':')) {
$$line[0] = $line[1];
}
If you use JSON, you can use something like:
extract(json_decode(file_get_contents('settings.json')));
Using extract may be dangerous, so I suggest to store these settings in an array:
$settings = json_decode(file_get_contents('settings.json'));
You should read your file to an array, with the file() function, then you should cycle on it: for each line (the file() function will return an array, one line per item), check if the line is not blank, then explode() on the ":" character, trim the pieces, and put them into an array.
You will end up win an array like this:
[template] = xaddict
[editor] = true
then you can use this information.
Do not automatically convert this into local variables: it's a great way to introduce security risks, and potentially very obscure bugs (local variables obscured by those introduced by this parsing).

Categories