Using PHP DOMDocument to search for one class among many - php

I have some elements in my DOM with multiple classes one of which is .dictionary_entry. I need to look for any instance of this class in my DOM and I am using the following PHP code for that:
$divs = $dom->getElementsByTagName('div');
$check = 0;
for ($i = 0; $i < $divs->length; $i++) {
$node = $divs->item($i);
if ($node->getAttribute('class') == 'cross-entry') { $check = 1; }
}
However, this doesn't work since the div in question has other classes as well, e.g., <div class="cross-entry cross-one one-more-class">
Is there any workaround?

Check for whitespace in the string.
If it exists, explode the classes on whitespace.
Check if the class you want is in the array
Otherwise, check if the single class that exists matches
Otherwise, set $check to 0.
That would look like this:
$class = $node->getAttribute('class');
$is_whitespace = preg_match('/\s/', $class);
if($is_whitespace){
$classes = explode(' ', $class);
if(in_array('cross-entry', $classes)){
$check = 1;
}
} elseif($class == 'cross-entry'){
$check = 1;
} else {
$check = 0;
}

Related

looping through txt file to use specific part of a string

I am new to Php and can't seem to figure this out no matter how much I've googled.
So I've opened the txt file (which consists of multiple lines of this type of string unique Identifier IMEI in bold:
Rx:00:39:54 06/09/2015:+RESP:GTEPS,210101,863286020022449,,8296,01,1,3,0.0,0,1031.1,29.367950,-30.799161,20150906003710,,,,,,2857.9,20150906003710,8038$) There are different strings with different IMEIs but i only want to use a specific one.
My question is, how do I extract/only use the string with the same Unique identifier and then loop through those to use in another function?
My function has different cases and each case has different calculations, so I'll need to loop through the txt file (with e.g. 863286020022449 as Identifier, ignoring other identifiers/IMEIs) in order to use the string in my function as below:
This is my starter function:
function GetParam($unknownFunction, $numberCommas) {
$returnString = "";
$foundSting = 0;
$numberFound = 0;
$len = strlen($unknownFunction);
for ($i = 0; $i < $len; ++$i) {
if ($Rawline[$i] == ",") {
++$numberFound;
if ($numberFound > $numberCommas)
break;
if ($numberFound == $numberCommas)
$foundSting = 1;
}
else if ($foundSting == 1) {
$returnString .= $unknownFunction[$i];
}
}
return $returnString;
echo $returnString;
}
$i = strpos($unknownFunction, ":GT");
$p = substr($unknownFunction, $i+3,3);
$Protocol = GetParam($unknownFunction, 1);
//this switch reads the differences in the message types (e.g. HBD- in this case is a heartbeat message type and would thus have a different amount of commas in the string and has different definitions of the characters within the commas)
switch ($p) {
case 'HBD':
//+ACK:GTHBD,220100,135790246811220,,20100214093254,11F0$
//This is an example of an HBD message
$result2["Type"] = 'Heart beat';
$IMEI = GetParam($unknownFunction, 2);
$mDate = GetParam($unknownFunction, 4);
$mDate = substr($mDate,0,4).'-'.substr($mDate,4,2).'-
'.substr($mDate,6,2).'
'.substr($mDate,8,2).':'.substr($mDate,10,2).':'.substr($mDate,12,2);
break;
This is the biggest problem I am facing at the moment and when I print the different lines, it indicates the correct IMEI but it does not loop through the whole file to use each string that belongs to that IMEI.
Your assistance would be greatly appreciated.
Thank you so much.
Example of input file:
Rx:00:00:00 28/02/2018:+RESP:GTFRI,3C0103,862045030241360,,14067,11,1,1,29.7,320,151.1,30.949307,-29.819685,20180227235959,0655,0001,013A,87B6,00,35484.1,01500:51:31,,,100,220101,,,,20180228000000,3461$
Rx:00:00:01 28/02/2018:+RESP:GTERI,380201,869606020047340,gv65,00000002,14076,10,1,1,119.0,119,24.3,18.668516,-34.016808,20180227235955,0655,0001,00F7,2DC9,00,98912.0,02235:20:25,0,100,220101,0,0,20180227235958,FF20$
Rx:00:00:03 28/02/2018:+RESP:GTERI,380201,869606020162990,,00000002,12912,10,1,1,0.0,230,1127.3,30.846671,-27.674206,20180227235956,0655,0001,013E,88B0,00,106651.1,03546:44:42,0,100,210101,0,0,20180227235959,6190$
Rx:00:00:03 28/02/2018:+ACK:GTHBD,450102,865084030005340,gb100,20180228000003,CC61$
Rx:00:00:03 28/02/2018:+RESP:GTERI,380201,869606020115980,,00000002,13640,10,1,1,12.1,353,1663.1,28.580726,-28.162208,20180227235957,,,,,,37599.6,02422:07:24,0,100,220101,0,0,20180228000000,1937$
Rx:00:00:04 28/02/2018:+RESP:GTERI,380502,869606020276840,gv65,00000002,12723,10,1,1,0.0,106,1232.8,22.878013,-27.951762,20180227235952,0655,0001,0204,63C5,00,13808.9,00778:32:20,0,100,210100,0,0,20180228000002,2C50$
Rx:00:00:04 28/02/2018:+RESP:GTERI,380502,869606020274530,gv65,00000002,12683,10,1,1,0.0,91,1213.7,24.863444,-28.174319,20180227235956,0655,0001,0203,69F1,00,9753.2,00673:49:21,0,100,210100,0,0,20180228000003,8AC7$
Rx:00:00:05 28/02/2018:+ACK:GTHBD,380201,863286023083810,,20180228000003,0D87$
Rx:00:00:06 28/02/2018:+RESP:GTFRI,3C0103,862045030241360,,14086,10,1,1,34.0,327,152.0,30.949152,-29.819501,20180228000002,0655,0001,013A,87B6,00,35484.1,01500:51:36,,,100,220101,,,,20180228000005,3462$
Rx:00:00:06 28/02/2018:+ACK:GTHBD,060228,862894021626380,,20180228000007,F9A5$
Rx:00:00:07 28/02/2018:+RESP:GTERI,380201,869606020019430,,00000002,12653,10,1,1,0.0,219,1338.7,26.882063,-28.138099,20180228000002,,,,,,86473.7,05645:48:34,0,93,210101,0,0,20180228000003,0FA5$
Rx:00:00:09 28/02/2018:+ACK:GTHBD,380502,869606020233940,gv65,20180228000008,7416$
Rx:00:00:10 28/02/2018:+RESP:GTAIS,380201,869606020171710,,11,11,1,1,0.0,95,281.2,30.855164,-29.896575,20180228000009,0655,0001,0156,9A9F,00,156073.7,20180228000008,F9A4$
Each GT message means something which is why i need to extract only one specific IMEI and use the result in my function as a breakdown of what every set of numbers between the commas actually mean. The end result needs to be populated in an excel spreadsheet but that's a different issue.
Nested foreach, keeping tracking of the IMEIs you've already gone through. Or something like this.
<?php
$filename = 'info.txt';
$contents = file($filename);
foreach ($contents as $line) {
$doneAlreadyArray = array();
$IMEI = GetParam($line, 2);
foreach ($contents as $IMEIline){
$thisIMEI = GetParam($IMEIline,2);
//check if already done the IMEI previously
if (!in_array($thisIMEI, $doneAlreadyArray)){
//matching IMEIs?
if ($thisIMEI == $IMEI){
//run new function with entire $IMEIline
new_function($IMEIline);
}
}
}
//add IMEI to doneAlreadyArray
array_push($doneAlreadyArray,$IMEI);
}
?>
If I've understood your question right and you want to extract the string(line) with the same Unique identifier, this may be useful for your needs as a strating point.
The example is very basic, and use data from your question:
<?php
// Read the file.
$filename = 'input.txt';
$file = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// Each item of $output will contain an array of lines:
$output = array();
foreach ($file as $row) {
$a = explode(',', $row);
$imei = $a[2];
if (!array_key_exists($imei, $output)) {
$output[$imei] = array();
}
$output[$imei][] = $row;
}
// Then do what you want ...
foreach ($output as $key=>$value) {
echo 'IMEI: '.$key.'</br>';
foreach($value as $row) {
// Here you can call your functions. I just echo the row:
echo $row.'</br>';
}
}
?>
thank you for the feedback.
Ryan Dewberry ended up helping me.
The fix was simpler than I thought too :)
//Unknownfunction is now $line
function GetParam($line, $numberCommas) {
$returnString = "";
$foundSting = 0;
$numberFound = 0;
$len = strlen($line);
for ($i = 0; $i < $len; ++$i) {
if ($line[$i] == ",") {
++$numberFound;
if ($numberFound > $numberCommas)
break;
if ($numberFound == $numberCommas)
$foundSting = 1;
}
else if ($foundSting == 1) {
$returnString .= $line[$i];
}
}
return $returnString;
// print $returnString;
}
//this is new - makes sure I use the correct IMEI
$contents = file($fileName);
foreach ($contents as $line){
$haveData = 0;
$IMEI = GetParam($line, 2);
if ($IMEI == $gprsid){
$i = strpos($line, ":GT");
$p = substr($line, $i+3,3);
$Protocol = GetParam($line, 1);
//this is the part I struggled with as well - This is an array of all of my
//calculation
//results and in printing it out I can see that everything is working
$superResult = array();
array_push($superResult,$result2);
print_r($superResult);
}
}
Much appreciated. Thank you!

Add new member to a variable in an array

I want to append new member to element which is in an array. Without array it's simple to write. for example:
$exp["app_form_id"] = $form_id;
But when I want add new member 'app_form_id' to all object of an array it not insert them and also there's not any error with them. I tried do it by 2 way, but none of them not worked:
1)
foreach ($exps as $exp) {
$exp["app_form_id"] = $form_id;
}
2)
for ($i = 0; $i < count($exps); $i++) {
$exps[i]["app_form_id"] = $form_id;
}
Your #1 method will work if you pass by reference (&):
foreach ($exps as &$exp) {
$exp["app_form_id"] = $form_id;
}
Try like this,
foreach ($exps as &$exp) {
$exp->app_form_id = $form_id;
}
I feel you are having manipulation with an object.
Give it a try, it should work.
Whatever you are changing inside block is limited to the block and not changing back, Try like this
$newExps = array();
foreach ($exps as $exp) {
$exp["app_form_id"] = $form_id;
$newExps[] = $exp;
}
print_r($newExps);

Multiple returning

Could anyone help me.
I need to return multiple img's, but with this code, only one of two is returning.
What is the solution.
Thank you in advance.
$test = "/claim/img/box.png, /claim/img/box.png";
function test($test)
{
$photo = explode(',', $test);
for ($i = 0; $i < count($photo); $i++)
{
$returnas = "<img src=".$photo[$i].">";
return $returnas;
}
}
This might be a good opportunity to learn about array_map.
function test($test) {
return implode("",array_map(function($img) {
return "<img src='".trim($img)."' />";
},explode(",",$test)));
}
Many functions make writing code a lot simpler, and it's also faster because it uses lower-level code.
While we're on the subject of learning things, PHP 5.5 gives us generators. You could potentially use one here. For example:
function test($test) {
$pieces = explode(",",$test);
foreach($pieces as $img) {
yield "<img src='".trim($img)."' />";
}
}
That yield is where the magic happens. This makes your function behave like a generator. You can then do this:
$images = test($test);
foreach($images as $image) echo $image;
Personally, I think this generator solution is a lot cleaner than the array_map one I gave earlier, which in turn is tidier than manually iterating.
Modify your code that way
function test($test)
{
$returnas = '';
$photo = explode(',', $test);
for ($i = 0; $i < count($photo); $i++)
{
$returnas .= "<img src=".$photo[$i].">";
}
return $returnas;
}
Your code didn't work since you were returning inside the loop immediatly. Every programming language support "only a return for call". In my solution you're appendig a string that has an img tag each time you enter the loop and return it after every photo is "passed" into the loop
You could even use the foreach() construct, of course
Bonus answer
If you don't know the difference between ...
for ($i = 0; $i < count($photo); $i++)
and
for ($i = 0, $count = count($photo); $i < $<; $i++)
Well, in first case you'll evaluate count($photo) every single time the for is called whereas the second time, it is evaluated only once.
This could be used for optimization porpuses (even if php, internally, stores the length of an array so it is accesible in O(1))
The function breaks after the first return statement. You need to save what you want to return in some structure, an array eg, and return this.
function test($test)
{
$result = array();
$photo = explode(',', $test);
for ($i = 0; $i < count($photo); $i++)
{
$returnas = "<img src=".$photo[$i].">";
$result[] = $returnas;
}
return $result;
}

Parsing empty XML elements in PHP

PHP newbie here. I'm parsing a long XML file, setting each tag to a variable. If the element's tag is empty, I want to assign it the value "N/A"
I'm wondering if there's a more concise way to do this than my current approach:
$elements = array()
$propertyOwner = $report->PropertyProfile->PrimaryOwnerName[0];
array[] = $propertyOwner;
$propertyAddress = $report->PropertyProfile->SiteAddress[0];
array[] = $propertyAddress;
...
for($i=0; $i<count($elements); $i++) {
if (array[i] === '') {
array[i] = 'N/A');
}
}
The way the code was written originally (without $s in front of each variable) you'd probably be getting errors all day. Hope this helps simplify:
$array[] = '';
$elements = array();
$propertyOwner = $report->PropertyProfile->PrimaryOwnerName[0];
$elements[] = $propertyOwner;
$propertyAddress = $report->PropertyProfile->SiteAddress[0];
$elements[] = $propertyAddress;
//...
// IF THEN ELSE
$array[] = !empty($elements) ? $elements : 'N/A';

Using PHP to recursively replace HTML elements and their values for sanitization

I am working ona project that involves HTML input from users using TinyMCE. At this point, the only way I can think of validating/sanitizing the HTML data is to use DomDocument in PHP and a whitelist of allowed HTML tags.
So using DomDocument, I first loop through all the tags, looking only for the specific tags that are allowed (the 'whitelist'), and replace them with new elements and their allowed attributes, obviously copying the values from the old tags entered by the user.
This way, not only can I control the tags that are entered by the user, but their attributes as well and there will hopefully be no 'leaks.'
So far, I have managed to use a class I found on PHP.net to loop through the body of this HTMLinput:
class ArrayNode{
public $nodeName, $nodeValue;
}
function getChildNodeElements( $domNode ){
$nodes = array();
for( $i=0; $i < $domNode->childNodes->length; $i++){
$cn = $domNode->childNodes->item($i);
if( $cn->nodeType == 1){
$nodes[] = $cn;
}
}
return $nodes;
}
function getArrayNodes( $domDoc ){
$res = array();
for( $i=0; $i < $domDoc->childNodes->length; $i++){
$cn = $domDoc->childNodes->item($i);
# The first is the root tag...
if( $cn->nodeType == 1){
# But we want it's childNodes.
$sub_cn = getChildNodeElements( $cn);
# Found the tagName:
$baseItemTagName = $sub_cn[0]->nodeName;
break;
}
}
$dnl = $domDoc->getElementsByTagName( $baseItemTagName);
for( $i=0; $i< $dnl->length; $i++){
$arrayNode = new ArrayNode();
# Summary
$arrayNode->nodeName = $dnl->item($i)->nodeName;
$arrayNode->nodeValue = $dnl->item($i)->nodeValue;
# Child Nodes
$cn = $dnl->item($i)->childNodes;
for( $k=0; $k<$cn->length; $k++){
if( $cn->item($k)->nodeName == "#text" && trim($cn->item($k)->nodeValue) == "") continue;
$arrayNode->{$cn->item($k)->nodeName} = $cn->item($k)->nodeValue;
}
# Attributes
$attr = $dnl->item($i)->attributes;
for( $k=0; $k < $attr->length; $k++){
if(! is_null($attr)){
if( $attr->item($k)->nodeName == "#text" && trim($attr->item($k)->nodeValue) == "") continue;
$arrayNode->{$attr->item($k)->nodeName} = $attr->item($k)->nodeValue;
}
}
$res[] = $arrayNode;
}
return $res;
}
Is this approach the right way for sanitizing HTML input entered using TinyMCE? How does Stackoverflow deal with this? Also, how does one go about replacing elements recursively inside such HTML so that the positions of the tag elements remains unchanged?
Any help with this would be so much appreciated.

Categories