I have the following script that uses the api on hostip.info. The page parses an xml readout of a user location based on the ip address. In my function everything is working except for the city.
preg_match("#<Hostip>(\s)*<gml:name>(.*?)</gml:name>#si",$xml,$city_match);
I have narrowed it down to my preg_match being wrong but I'm not sure how to fix it. Here is a sample xml output: http://api.hostip.info/?ip=12.215.42.19
<?php
function getCountryCity()
{
if(isset($_SERVER['REMOTE_ADDR']) && strlen($_SERVER['REMOTE_ADDR']) > 0) {
$ipAddr = $_SERVER['REMOTE_ADDR'];
// verify the IP address
ip2long($ipAddr)== -1 || ip2long($ipAddr) === false ? trigger_error("Invalid IP", E_USER_ERROR) : "";
$ipDetail=array();
// get the XML result from hostip.info
$xml = file_get_contents("http://api.hostip.info/?ip=".$ipAddr);
// get the city name inside the node <gml:name> and </gml:name>
preg_match("#<Hostip>(\s)*<gml:name>(.*?)</gml:name>#si",$xml,$city_match);
$ipDetail['city'] = $city_match[1];
// get the country name inside the node <countryName> and </countryName>
preg_match("#<countryName>(.*?)</countryName>#si",$xml,$country_match);
$ipDetail['country'] = $country_match[1];
// get the country name inside the node <countryName> and </countryName>
preg_match("#<countryAbbrev>(.*?)</countryAbbrev>#si",$xml,$cc_match);
$ipDetail['country_code'] = $cc_match[1];
// return the array containing city, country and country code
return $ipDetail;
} else {
return false;
}
}
$ipDetail = getCountryCity();
$user_city = $ipDetail['city'];
$user_country = $ipDetail['country'];
$user_cc = $ipDetail['country_code'];
echo $user_country.' ('.$user_cc.')';
echo $user_city;
?>
XPATH is a dream for this kind of stuff. Google "SimpleXML PHP Tutorial" if this is new to you. Basically:
$xml = new SimpleXMLElement($yourXML);
$user_city = $xml->xpath('//gml:name/text()');
$user_country= $xml->xpath('//countryName/text()');
$cc= $xml->xpath('//countryAbbrev/text()');
I find XPATH queries to be much easier to write than RegEx.
Sorry this doesn't answer your question as directly as you want. tried to post in a comment but the formatting gets totally screwed up
preg_match_all("#<gml:name>(.*?)</gml:name>#si",$xml,$city_match);
just remove <Hostip>(\s)* and use preg_match_all it will take all the tags. Then you can select one you need in array.
function getCountryCity() {
if(isset($_SERVER['REMOTE_ADDR']) && strlen($_SERVER['REMOTE_ADDR']) > 0) {
$user_ip = $_SERVER['REMOTE_ADDR'];
$response = file_get_contents('http://api.hostip.info/?ip='.$user_ip);
$user_details = array();
$xml = new DOMDocument();
$xml->loadXml($response);
$xpath = new DOMXpath($xml);
$path = '/HostipLookupResultSet/gml:featureMember/Hostip/';
// create values for array
$ip = $xpath->evaluate($path . 'ip')->item(0)->nodeValue;
$city = $xpath->evaluate($path . 'gml:name')->item(0)->nodeValue;
$countryName = $xpath->evaluate($path . 'countryName')->item(0)->nodeValue;
$countryAbbrev = $xpath->evaluate($path . 'countryAbbrev')->item(0)->nodeValue;
// assign values to array
$user_details['ip'] = $ip;
$user_details['city'] = $city;
$user_details['countryName'] = $countryName;
$user_details['countryAbbrev'] = $countryAbbrev;
return $user_details;
} else {
return false;
}
}
Related
I'm trying to get the total times two authors have edited or coauthored books. (They are selected by a user using checkboxes, so I've used GET to see if the checkbox is selected).
I am cross referencing the authors 'a' (mj) and 'b' (ms) from 'a's' (mj) xml doc that features all their publishing information.
Currently I have this:
if ($_GET['author'] == 'mj55'){
$getMj = new DOMDocument();
$getMj->load("Margret-Jane.xml");
$mjxpath = new DOMXpath($getMj);
$mjAuth = $mjxpath->query("////author[#id = 'mj55']")->length;
$mjEdit = $mjxpath->query("////editor[#id = 'mj55']")->length;
$mjResult = ($mjAuth + $mjEdit);
if ($_GET['author'] == 'ms10' ) {
$mjmsA = $mjxpath->query("////author[#id = 'ms10']")->length;
$mjmsE = $mjxpath->query("////editor[#id = 'ms10']")->length;
$mjmsTotal = ($mjmsA + $mjmsE);
echo $mjmsTotal;
}
}
if I put an echo $mjResult at the end of the first if statement, I get the correct output. But I don't get any output at all from the echo $mjmsTotal
you used a nested if and that's why you are getting a result of only first if.. try to use both the if statement totally independent with each other. Here is an example-
$getMj = new DOMDocument();
$getMj->load("Margret-Jane.xml");
$mjxpath = new DOMXpath($getMj);
if ($_GET['author'] == 'mj55'){
$mjAuth = $mjxpath->query("////author[#id = 'mj55']")->length;
$mjEdit = $mjxpath->query("////editor[#id = 'mj55']")->length;
$mjResult = ($mjAuth + $mjEdit);
}
if ($_GET['author'] == 'ms10' ) {
$mjmsA = $mjxpath->query("////author[#id = 'ms10']")->length;
$mjmsE = $mjxpath->query("////editor[#id = 'ms10']")->length;
$mjmsTotal = ($mjmsA + $mjmsE);
echo $mjmsTotal;
}
You can reduce this to one condition, this saves having to hard code all of the different authors/editors.
First check if the author is set, then include this value in the XPath expressions...
if ( !empty($_GET['author'])) {
$getMj = new DOMDocument();
$getMj->load("Margret-Jane.xml");
$mjxpath = new DOMXpath($getMj);
$mjAuth = $mjxpath->query("//author[#id = '{$_GET['author']}']")->length;
$mjEdit = $mjxpath->query("//editor[#id = '{$_GET['author']}']")->length;
$mjResult = ($mjAuth + $mjEdit);
echo $mjResult;
}
I'm trying to build a script that will download users from a db table and attach a new random IP to each user based on his state.
The problem is that I wrote a lot of code and there is still much Copy/Paste job to be done if I keep it with this approach.
Can someone point me to the right direction on how to properly do that?
So first I have 50 of these:
$California_Text = file_get_contents('state/California.txt');
$California_textArray = explode("\n", $California_Text);
$Idaho_Text = file_get_contents('state/Idaho.txt');
$Idaho_textArray = explode("\n", $Idaho_Text);
$Illinois_Text = file_get_contents('state/Illinois.txt');
$Illinois_textArray = explode("\n", $Illinois_Text);
$Indiana_Text = file_get_contents('state/Illinois.txt');
$Indiana_textArray = explode("\n", $Indiana_Text);
$Iowa_Text = file_get_contents('state/Iowa.txt');
Then I have 50 of these:
while($row = $result->fetch_assoc()) {
if (isset($row["state"])) {
foreach ($row as $value){
$California_randArrayIndexNum = array_rand($California_textArray);
$p_California = $California_textArray[$California_randArrayIndexNum];
$Texas_randArrayIndexNum = array_rand($Texas_textArray);
$p_Texas = $Texas_textArray[$Texas_randArrayIndexNum];
$Alabama_randArrayIndexNum = array_rand($Alabama_textArray);
$p_Alabama = $Alabama_textArray[$Alabama_randArrayIndexNum];
$Alaska_randArrayIndexNum = array_rand($Alaska_textArray);
$p_Alaska = $Texas_textArray[$Alaska_randArrayIndexNum];
$Arizona_randArrayIndexNum = array_rand($Arizona_textArray);
$p_Arizona = $California_textArray[$Arizona_randArrayIndexNum];
.....
Then I have 50 of these:
if ($row["state"] == "california") {
$stateip = $p_California;
}
else if ($row["state"] == "texas") {
$stateip = $p_Texas;
}
else if ($row["state"] == "alabama") {
$stateip = $p_Alabama;
}
else if ($row["state"] == "alaska") {
$stateip = $p_Alaska;
}
I'm pretty much sure that it's a bad approach.. Maybe there's a way to do all this with like 3 lines of foreach?
Something like this:
// holds your content
$state_content = [];
while($row = $result->fetch_assoc()) {
// check do we have state set
if (!empty($row["state"])) {
$stateip = getStateIpByName($row["state"]);
}
}
/**
* Returns random IP
*/
function getStateIpByName($state_name) {
$content = getStateContent($state_name);
return $content[array_rand($content)];
}
/**
* Returns your's state content by state name
*/
function getStateContent($state_name) {
// checks do we already have content for this state
if(!isset($state_content[$state_name])) {
// generate file name
$file_name = "state/";
$file_name .= str_replace(" ", "", ucwords($state_name));
$file_name .= ".txt";
$state_text = file_get_contents($file_name);
$state_content[$state_name] = explode("\n", $state_text);
}
return $state_content[$state_name];
}
There are probably some errors but you will get idea.
Store all states in an array and do all operations within a foreach block
$states=['california',..];
foreach($states as $state){
//Your code for one state
//Replace state name with $state variable
}
I am using the MODX cms to output data from a third party, and I am stumped on how to return a nested array, currently I am only getting it to return the first array or NULL. Here is a sample of the code I am using:
$datastream = '[{"id":57,
"offer_info":{"offer_headline":"Main Offer Headline",
"published_title":"Displayed Main Title"},
// My issue is here with the nested array
"service_categories":[{"service_category_code":"D",
"headline":"My Headline for D",
"midline":"Middle copy",
"footline":"Footer copy for D"},
{"service_category_code":"T",
"headline":"My Headline for T",
"image":"image.svg",
"footline":"Footer copy for T"}]}]';
$output_json = json_decode($datastream);
$output_json = json_decode($datastream, true); // this returns null for everything
foreach($output_json as $component) {
$productid = $component->id; // this returns ok
$offer_headline = $component->offer_info->offer_headline; // this returns ok
$published_title = $component->offer_info->published_title; // this returns ok
$service_categories_category_code = $component->service_categories[0]->service_category_code; // this only returns first value
$service_categories_category_code = $component->service_categories->service_category_code; // this returns NULL
var_dump($service_categories_category_code);
I am able to take the values that return ok and place them in my code, but the nested array is only returning the first value, and I'm not sure if I am doing this correctly:
if ($service_categories_category_code = "D") {
$d_details_headline = $component->service_categories[0]->headline;
$d_details_midline = $component->service_categories[0]->midline;
$d_footline = $component->service_categories[0]->footline;
} elseif ($service_categories_category_code = "T") {
$t_details_headline = $component->service_categories[0]->headline;
$t_details_image = $component->service_categories[0]->image;
$t_details_footline = $component->service_categories[0]->footline;
};
Thank you very much in advance for any help
Hope this helps You :
<?php
$datastream = '[{"id":57,"offer_info":{"offer_headline":"Main Offer
Headline","published_title":"Displayed Main
Title"},"service_categories":[{"service_category_code":"D",
"headline":"My Headline for D","midline":"Middle
copy","footline":"Footer copy for D"},{"service_category_code":"T",
"headline":"My Headline for T",
"image":"image.svg",
"footline":"Footer copy for T"}]}]';
$output_json = json_decode($datastream);
//$output_json = json_decode($datastream, true); // this returns null for everything
$data = array();
foreach($output_json as $component) {
$productid = $component->id; // this returns ok
$offer_headline = $component->offer_info->offer_headline; // this returns ok
$published_title = $component->offer_info->published_title; // this returns ok
$data['productid'] = $component->id;
$data['offer_info']['offer_headline'] = $component->offer_info->offer_headline;
$data['offer_info']['published_title'] = $component->offer_info->published_title;
foreach ($component->service_categories as $comp) {
if ($comp->service_category_code == 'D') {
$data['D']['service_category_code'] = $comp->service_category_code;
$data['D']['headline'] = $comp->headline;
$data['D']['midline'] = $comp->midline;
$data['D']['footline'] = $comp->footline;
} elseif ($comp->service_category_code == 'T') {
$data['T']['service_category_code'] = $comp->service_category_code;
$data['T']['headline'] = $comp->headline;
$data['T']['image'] = $comp->headline;
$data['T']['footline'] = $comp->footline;
}
}
print_r($data);
}
I'm using a script from this site. This script works fine for me and it does what its need to do but I have one problem. When a track finishes on my Icecast server it doesn't get updates on the site. So if my song is 'Stole the show' than it says 'Stole the show' the page but when the song finished and e.g. 'Thinking out loud' starts the page still says 'Stole the show' on a refresh it will update. But how to make it so the page auto updates itself so the users doesn't have to refresh manually?
PHP
<?php
// include the class file
include( 'icecast.php' );
// instantiate class
$stream = new IceCast();
// set server and mount
$server = 'http://radio.finioxfm.com:8000';
$file = '/status.xsl';
// set the url
$stream->setUrl($server,$file);
// get status info
$radio = $stream->getStatus();
// assign array to variables
extract($radio);
// echo the status
echo $status.'<br/>';
// display more stats if ON AIR
if ($status=='ON AIR') :
echo $listeners.' listeners<br/>';
echo $title.'<br/>';
echo $genre.'<br/>';
for ($i=0; $i < 1; $i++) {
echo $now_playing['artist'].'<br/>';
echo $now_playing['track'].'<br/>';
}
endif;
?>
icecast.php script
<?php
class IceCast {
var $server = "http://radio.finioxfm.com:8000";
var $stats_file = "/status.xsl";
var $radio_info=array();
function __construct() {
// build array to store our Icecast stats
$this->radio_info['server'] = $this->server;
$this->radio_info['title'] = '';
$this->radio_info['description'] = '';
$this->radio_info['content_type'] = '';
$this->radio_info['mount_start'] = '';
$this->radio_info['bit_rate'] = '';
$this->radio_info['listeners'] = '';
$this->radio_info['most_listeners'] = '';
$this->radio_info['genre'] = '';
$this->radio_info['url'] = '';
$this->radio_info['now_playing'] = array();
$this->radio_info['now_playing']['artist'] = 'Unknown';
$this->radio_info['now_playing']['track'] = 'Unknown';
$this->radio_info['status'] = 'OFF AIR';
}
function setUrl($url,$file) {
$this->server=$url;
$this->stats_file=$file;
$this->radio_info['server'] = $this->server;
}
private function fetch() {
// create a new curl resource
$ch = curl_init();
// set the url
curl_setopt($ch,CURLOPT_URL,$this->server.$this->stats_file);
// return as a string
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
// $output = the status.xsl file
$output = curl_exec($ch);
// close curl resource to free up system resources
curl_close($ch);
return $output;
}
function getStatus() {
$output=$this->fetch();
// loop through $output and sort arrays
$temp_array = array();
$search_for = "<td\s[^>]*class=\"streamdata\">(.*)<\/td>";
$search_td = array('<td class="streamdata">','</td>');
if(preg_match_all("/$search_for/siU",$output,$matches)) {
foreach($matches[0] as $match) {
$to_push = str_replace($search_td,'',$match);
$to_push = trim($to_push);
array_push($temp_array,$to_push);
}
}
if(count($temp_array)) {
//sort our temp array into our ral array
$this->radio_info['title'] = $temp_array[0];
$this->radio_info['description'] = $temp_array[1];
$this->radio_info['content_type'] = $temp_array[2];
$this->radio_info['mount_start'] = $temp_array[3];
$this->radio_info['bit_rate'] = $temp_array[4];
$this->radio_info['listeners'] = $temp_array[5];
$this->radio_info['most_listeners'] = $temp_array[6];
$this->radio_info['genre'] = $temp_array[7];
$this->radio_info['url'] = $temp_array[8];
if(isset($temp_array[9])) {
$x = explode(" - ",$temp_array[9]);
$this->radio_info['now_playing']['artist'] = $x[0];
$this->radio_info['now_playing']['track'] = $x[1];
}
$this->radio_info['status'] = 'ON AIR';
}
return $this->radio_info;
}
}
?>
First of all, I have to point out that you shouldn't use this script. It works by parsing the Icecast Status page, which we highly discourage, as it may change. For example in Icecast 2.4 we re-made the complete web interface, so chances are that this script breaks.
You should actually parse the XML Icecast provides at http://icecast.tld:8000/admin/stats. It contains everything you need. If you can't access Icecast's Admin page for some reason, you can use the JSON at http://icecast.tld:8000/status-json.xsl, which is there since Icecast 2.4 exactly for the purpose you describe.
To get the site display new metadata information without refreshing, you need to use an AJAX call which either loads directly the status-json.xsl and extracts the metadata and updates it on the page, or if you use the admin XML you need to write a PHP script which returns json, that you can fetch via AJAX and update accordingly.
A lot of people in the past have spoken about setting up node.js (if you have a server doing your streaming).
Personally I have gone with a jquery solution; which just compares the last fetched data with the live data every 10 seconds. That way it loads in almost 'real time'.
You can find my solution here broken down here http://www.radiodj.ro/community/index.php?topic=7471.0
I have a latitude and a longitude, and I need to fetch country.
I am using this:
$geocode_stats = file_get_contents("http://maps.googleapis.com/maps/api/geocode/json?latlng=".$deal_lat.",".$deal_long . "&sensor=false");
$output_deals = json_decode($geocode_stats);
$country = $output_deals->results[2]->address_components[4]->long_name;
Sometimes it gives a correct country name, but sometimes it gives blank values, and sometimes it returns a city name.
Can anybody help?
I wrote a function to make it easy. Simply pass in your geo-address which can be a full address, zip code, or in your case latitude and longitude. It will then search through the address component array for the country. In the case that it is unable to find the county it will simply return null, you can change that to an empty string ("") if you need to.
function getGeoCounty($geoAddress) {
$url = 'http://maps.google.com/maps/api/geocode/json?address=' . $geoAddress .'&sensor=false';
$get = file_get_contents($url);
$geoData = json_decode($get);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \InvalidArgumentException('Invalid geocoding results');
}
if(isset($geoData->results[0])) {
foreach($geoData->results[0]->address_components as $addressComponent) {
if(in_array('administrative_area_level_2', $addressComponent->types)) {
return $addressComponent->long_name;
}
}
}
return null;
}
Get complete Address from latitude and longitude.
$url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.trim($lat).','.trim($lng).'&sensor=false';
$json = #file_get_contents($url);$data=json_decode($json);
echo $data->results[0]->formatted_address;
$deal_lat=30.469301;
$deal_long=70.969324;
$geocode=file_get_contents('http://maps.googleapis.com/maps/api/geocode/json?latlng='.$deal_lat.','.$deal_long.'&sensor=false');
$output= json_decode($geocode);
for($j=0;$j<count($output->results[0]->address_components);$j++){
$cn=array($output->results[0]->address_components[$j]->types[0]);
if(in_array("country", $cn)){
$country= $output->results[0]->address_components[$j]->long_name;
}
}
echo $country;
$deal_lat=30.469301;
$deal_long=70.969324;
$geocode=file_get_contents('http://maps.googleapis.com/maps/api/geocode/json?latlng='.$deal_lat.','.$deal_long.'&sensor=false');
$output= json_decode($geocode);
for($j=0;$j<count($output->results[0]->address_components);$j++){
$cn=array($output->results[0]->address_components[$j]->types[0]);
if(in_array("country", $cn)){
$country= $output->results[0]->address_components[$j]->long_name;
}
}
echo $country;
I did take the code of matwonk as base.
function getGeoCounty($geoAddress) {
$url = 'http://maps.google.com/maps/api/geocode/json?address=' . urlencode($geoAddress) .'&sensor=false';
$get = file_get_contents($url);
$geoData = json_decode($get);
if(isset($geoData->results[0])) {
$return = array();
foreach($geoData->results[0]->address_components as $addressComponet) {
if(in_array('political', $addressComponet->types)) {
if($addressComponet->short_name != $addressComponet->long_name)
$return[] = $addressComponet->short_name. " - " . $addressComponet->long_name;
else
$return[] = $addressComponet->long_name;
}
}
return implode(", ",$return);
}
return null;
}
The code return in format: neighborhood, City, State, Country
if detect a shortname (as country code or state code) appear in format CODE - NAME.
$latlng = '22.7314,75.88243';
$request_url = "http://maps.googleapis.com/maps/api/geocode /xml?latlng=".$latlng."&sensor=true";
$xml = simplexml_load_file($request_url);
if($xml->status == "OK") {
$address = $xml->result->formatted_address;
foreach ($xml->result->address_component as $address) {
if("country" == trim($address->type)) {
$country = $address->short_name;
}
}
}