Textpattern CMS support forum
You are not logged in. Register | Login | Help
- Topics: Active | Unanswered
Beta testers for new weather plugin needed
Hello,
I’ve been using for a while an adapted version of Simons old snt_weather plugin.
After Google weather API stopped working, I adapted it again to worldweatheronline.com API and maybe it is also useful for others, but should be tested first.
It simply puts out a table with some weather stations and has some formatting options. I put the weather icons from worldweatheronline together to a sprite-image and implemented also a second icon set.
get it here
Just install and activate.
You have to register at http://worldweatheronline.com/register.aspx
In Zip-File you can find two iconsets with 25px icons.
One iconset is from here: http://xiao4.deviantart.com/art/tick-weather-icons-96294478
the other from worldweatheronline.com.
Use weather_sprite.css and weather-sprite.png in your layout, adapt it to your needs.
You can find a list of weather codes and the names of the icons here.
For city code look here: http://www.worldweatheronline.com/country.aspx
Please note, that you have to use a caching plugin like aks_cache, to stay within the limit of 500 requests per hour!
Example use:
<txp:weather names="Town_1,City_2" codes="town1,city2" key="your_key" />
Parameters:
names: name of the city/town how you want to see it on your site, not obligatory, if not declared location code (see next line) is used
codes: location code of the city/town on worldweatheronline.com
The number of city codes has to be equal to the number of names of these locations!
key: the API-key you got, after registering on worldweatheronline.com
image: wether to show icons or not (“0” or “1”), default is “1”
sprite_image: wether to use css_sprite file on your server (“1”) or to request the icons from worldweatheronline (“0”), default is “1”
wind_unit: show wind speed in km/h or mph, choose between “k” or “m”, default is “k”
temperature_unit: use Fahrenheit or Celsius scale, “C” or “F”, default is “C”
class: table class, default is “weather”
row_class: row class, default is “weather-row”
place_class: td class for the city, default is “weather”
temperature_class: td class for the temperature, default is “weather”
icon_class: td class for the icons or the sprite_image, default is “weather”
language: what language to use for title texts? Choose between German – “de”, Russian – “ru”, Ukrainian – “ua” and English – “en”, default is English – other language codes you can find here
wait: time to wait between requests for different cities in micro seconds (one millionth of a second). Default is 500000 micro seconds.
Released under the General Public License 2.0
The Iconsets have different licenses!
See:
http://xiao4.deviantart.com/art/tick-weather-icons-96294478
http://www.worldweatheronline.com/free-weather-feed.aspx
Changelog:
// this plugin uses most of the code from
// snt_weather plugin
// by Simon Lindley
// http://www.simonaut.com/
// Version 0.2 – 11/06/2005
// 0.3 enhanced
// 0.3.1 Update 08/07/2009 API-Update
// 0.3.2 error handling
// 0.4.0 use of worldweatheronline api
// 0.5.0 new parameters, code cleaning, parameter “names” is not obligatory, different language strings
// 0.5.1 bugfixes, changed api-server
last change 14.03.2015
Last edited by whocarez (2015-03-14 16:20:14)
Offline
Re: Beta testers for new weather plugin needed
Nice one Andreas. It’s good that there are going to be alternatives filling in the void caused by the killed private API.
Anyway, at the end of the help it states:
Released under the General Public License 3.0
That is not possible as far as I’m aware. Textpattern is licensed under GPLv2, and GPLv3 isn’t compatible with earlier versions. Feel free to use any compatible license, but GPLv3 isn’t.
Please note, that you have to use a caching plugin like aks_cache, to stay within the limit of 500 requests per hour!
But why doesn’t it implement it’s own caching? Implementing caching wouldn’t need more than few lines, which is basically what aks_cache consists of. For example an identifier composed from the attributes (i.e. serialize, md5), set_pref and get_pref would be all that is needed for storing cached XML output in the txp_prefs table.
<txp:weather />
That’s reserving quite the name, I’m afraid. Might be good if both the class and the function were prefixed so that you don’t run into collisions. If you haven’t already, please see Plugin Development Guidelines.
names=“Town_1,City_2” codes=“town1,city2”
If you use do_list(), or array_map with trim as the callback, those two attributes could allow use of white-space. Which can be rather good for usability and formatting.
“<td class=’$temperature_class’ […]
Security wise you should sanitize all values returned to the page template using txpspecialchars() function (or htmlspecialchars() if compatibility with TXP <= 4.4.1 is needed). Especially those values that aren’t going to contain HTML, or do not need rich markup. This is to ensure that nothing bad happens in any situation where the XML feed returns something that it shouldn’t. Remote code executions aren’t really fun.
Output validity-wise, I’m not sure if it actually outputs valid HTML. I haven’t used the plugin itself, but when image
attribute is set 0
, there seems to be unpaired </td>
in the output I’m afraid. When image
is set as 1
there is potential changes of duplicate IDs as the image’s name is used as the id
attribute. Would be good if the ID was prefixed too.
Anyways, anyone wanting different output than a table, there is always smd_xml. Can take any XML input and generate output from it — including this type of weather API feed. Not that this weather plugin would be bad. Being a simple widget, it’s easy to setup if not anything.
Offline
Re: Beta testers for new weather plugin needed
Thank you Jukka for your comments.
The license is changed to v2.0, to be compatible to textpattern.
I’ll think about implementing caching, but my programming abilities are there constricted :-) Maybe it is easier for me to implement a caching in tmp directory.
I changed the function name, so it looks now like that:
<txp:wcz_weather names="Town_1,City_2" codes="town1,city2" key="your_key" />
Whitespaces are really relevant in the location code. “Rio de Janeiro” should be encoded as “Rio+De+Janeiro”, elsewise the url isn’t
working. Because of that, I added an urlencoding for the codes, but it looks not very elegant.
Output is sanitized with htmlentities() ….
Output validity-wise, I’m not sure if it actually outputs valid HTML. I haven’t used the plugin itself, but when
image
attribute is set0
, there seems to be unpaired</td>
in the output I’m afraid. Whenimage
is set as1
there is potential changes of duplicate IDs as the image’s name is used as theid
attribute. Would be good if the ID was prefixed too.
That’s really a problem using sprite images, because every ID is a special part of the image and if you have several weather stations e.g. 12, so it is very likely to repeat an ID. I don’t know any other solution for this problem, than to switch back to single icons, but that means in this case 12 requests for these 12 icons, instead of 1 request for the sprite image.
here is the actual code:
function wcz_weather($atts) {
extract(lAtts(array(
'codes'=>'',
'names'=>'',
'key'=>'',
'forecast'=>'0',
'image'=>'1',
'wind_unit'=>'k',
'temperature_unit'=>'c',
'place_class'=>'weather',
'temperature_class'=>'weather',
'icon_class'=>'weather-sprite',
'row_class'=>'weather',
'class'=>'weather',
'debug'=>'0'
),$atts));
$codes=explode(",",$codes);
$names=explode(",",$names);
class wcz_weather_class {
function wcz_weather_class($loc_code,$key,$forecast,$debug,$wind_unit,$temperature_unit) {
$xml=simplexml_load_string(file_get_contents("http://free.worldweatheronline.com/feed/weather.ashx?q=".$loc_code."&format=xml&num_of_days=".$forecast."&key=".$key));
if ($debug == "1") {print_r($xml);}
if($xml){
if(isset($xml->error))
{
$this->Temperature='-';
$this->Icon='na';
$this->Condition='-';
$this->Humidity='-';
$this->Wind='-';
}
else
{
if ($temperature_unit == "f") {$this->Temperature=htmlspecialchars($xml->current_condition->temp_F);$this->temperature_unit="F";} else {$this->Temperature=htmlspecialchars($xml->current_condition->temp_C);$this->temperature_unit="C";}
if ($wind_unit == "m") {$this->Wind=htmlspecialchars($xml->current_condition->windspeedMiles);$this->wind_unit_table='mph';} else {$this->Wind=htmlspecialchars($xml->current_condition->windspeedKmph); $this->wind_unit_table='km/h';}
$this->Icon=htmlspecialchars($xml->current_condition->weatherIconUrl);
$this->Condition=htmlspecialchars($xml->current_condition->weatherDesc);
$this->Humidity=htmlspecialchars($xml->current_condition->humidity);
if ($debug == "1") {
print_r($this->Temperature);print_r($this->Icon);print_r($this->Condition);print_r($this->Humidity);print_r($this->Wind);print_r($this->temperature_unit);print_r($this->wind_unit);print_r($this->wind_unit_table);
}
}
}
else
{
$this->Temperature='-';
$this->Icon='na';
$this->Condition='-';
$this->Humidity='-';
$this->Wind='-';
}
}
}
$Out=array();
$output=array();
foreach ($codes as &$loc_code) {
$loc_code=urlencode($loc_code);
$output = new wcz_weather_class($loc_code,$key,$forecast,$debug,$wind_unit,$temperature_unit);
$icon = str_replace(array('http://www.worldweatheronline.com/images/wsymbols01_png_64/','.png'),'',substr(strrchr($output->Icon,'/'),1));
if($image == "0") {$Out[] = "<td class='$temperature_class' title='$output->Condition - Humidity $output->Humidity % - Wind $output->Wind $output->wind_unit_table'>".$output->Temperature." °".$output->temperature_unit." </td>";
} else
{
$Out[] = "<td class='$temperature_class' title='$output->Condition - humidity $output->Humidity % - wind $output->Wind $output->wind_unit_table'>".$output->Temperature." °".$output->temperature_unit." </td><td class='$icon_class' title='$output->Condition - Humidity $output->Humidity % - Wind $output->Wind $output->wind_unit_table' id='".$icon."'>";
}
}
foreach($names as $location=>&$place) {
$Out[$location] = "<tr class='$row_class'><td class='$place_class' title='Weather in ".$place."'> ".$place."</td>".$Out[$location]." </td></tr>";
}
$all="<table class='$class'>";
foreach ($Out as $a) {
$all.=$a;
}
$all=$all."</table>";
return($all);
}
Offline
Re: Beta testers for new weather plugin needed
whocarez wrote:
Whitespaces are really relevant in the location code.
Is that directed to the allowing use of white-space in the attributes? That doesn’t affect it in a way or the other. The question is about optional spaces before and after commas, allowing more readable markup formatting.
Speaking of readability, that plugin’s source code is pretty unreadable and inconsistent. Lacks any style ruling.
Output is sanitized with htmlentities() ….
You mean htmlspecialchars()
, because it actually isn’t? You are using single quotes, and by default single-quotes are not converted. This means that the thing is still XSS-able with things as inline JavaScript and styles.
I don’t know any other solution for this problem, than to switch back to single icons
I’m not sure what the issue is. There are classes and an element can have multiple. Turn the ID into a prefixed class and any collisions issues are gone.
Offline
Re: Beta testers for new weather plugin needed
thanks again for your helpful comments and your patience
now I have trimed names and locations.
I implemented a new parameter sprite_image
, which is by default “1”, so the plugin uses the css_sprite
if set to “0” the plugin requests also the original icons from worldweatheronline.
The output with single icons should validate, the css_sprite one is not validating because of the repeated use of identical id’s
<td id="wsymbol_0002_sunny_intervals" title="Partly Cloudy - Humidity 55 % - Wind 26 km/h" class="wetter-sprite"> </td>
Don’t know how to change it, to validate.
I cleaned the code a little bit and hope that is now more readable and consistent.
// this plugin uses most of the code from
// snt_weather plugin
// by Simon Lindley
// http://www.simonaut.com/
// Version 0.2 - 11/06/2005
// 0.3 enhanced
// 0.3.1 Update 08/07/2009 API-Update
// 0.3.2 error handling
// 0.4.0 use of worldweatheronline api
function wcz_weather($atts) {
extract(lAtts(array(
'codes'=>'',
'names'=>'',
'key'=>'',
'forecast'=>'0',
'image'=>'1',
'sprite_image'=>'1',
'wind_unit'=>'k',
'temperature_unit'=>'c',
'place_class'=>'weather',
'temperature_class'=>'weather',
'icon_class'=>'weather-sprite',
'row_class'=>'weather',
'class'=>'weather',
'debug'=>'0'
),$atts));
$codes=explode(",",$codes);
$names=explode(",",$names);
class wcz_weather_class {
// function must have the same name as the class!
function wcz_weather_class($loc_code,$key,$forecast,$debug,$wind_unit,$temperature_unit) {
$xml=simplexml_load_string(file_get_contents("http://free.worldweatheronline.com/feed/weather.ashx?q=".$loc_code."&format=xml&num_of_days=".$forecast."&key=".$key));
if ($debug == "1") {print_r($xml);}
if($xml){
if(isset($xml->error)) {
$this->Temperature='-';
$this->Icon='na';
$this->Condition='-';
$this->Humidity='-';
$this->Wind='-';
}
else
{
if ($temperature_unit == "f") {
$this->Temperature=htmlspecialchars($xml->current_condition->temp_F);
$this->temperature_unit="F";
}
else {
$this->Temperature=htmlspecialchars($xml->current_condition->temp_C);
$this->temperature_unit="C";
}
if ($wind_unit == "m") {
$this->Wind=htmlspecialchars($xml->current_condition->windspeedMiles);
$this->wind_unit_table='mph';
}
else {
$this->Wind=htmlspecialchars($xml->current_condition->windspeedKmph);
$this->wind_unit_table='km/h';
}
$this->Icon=htmlspecialchars($xml->current_condition->weatherIconUrl);
$this->Condition=htmlspecialchars($xml->current_condition->weatherDesc);
$this->Humidity=htmlspecialchars($xml->current_condition->humidity);
if ($debug == "1") {
print_r($this->Temperature);
print_r($this->Icon);
print_r($this->Condition);
print_r($this->Humidity);
print_r($this->Wind);
print_r($this->temperature_unit);
print_r($this->wind_unit);
print_r($this->wind_unit_table);
}
}
}
else
{
$this->Temperature='-';
$this->Icon='na';
$this->Condition='-';
$this->Humidity='-';
$this->Wind='-';
}
// end of the function
}
// end of the class
}
$Out=array();
$output=array();
foreach ($codes as &$loc_code) {
$loc_code=urlencode(trim($loc_code));
$output = new wcz_weather_class($loc_code,$key,$forecast,$debug,$wind_unit,$temperature_unit);
if($image == "0") {
$Out[] = '<td class="'. $temperature_class .'" title="'. $output->Condition .' - Humidity '. $output->Humidity .' % - Wind '. $output->Wind .' '. $output->wind_unit_table .'">'. $output->Temperature .' °'. $output->temperature_unit .'</td>';
}
else {
if($sprite_image == "1") {
$icon = str_replace(array('http://www.worldweatheronline.com/images/wsymbols01_png_64/','.png'),'',substr(strrchr($output->Icon,'/'),1));
$Out[] = '<td class="'. $temperature_class .'" title="'. $output->Condition .' - Humidity '. $output->Humidity .' % - Wind '. $output->Wind .' '. $output->wind_unit_table .'">'. $output->Temperature .' °'. $output->temperature_unit.' </td><td class="'. $icon_class .'" title="'. $output->Condition .' - Humidity '. $output->Humidity .' % - Wind '. $output->Wind .' '. $output->wind_unit_table .'" id="'. $icon .'"> </td>';
}
else {
$Out[] = '<td class="'. $temperature_class .'" title="'. $output->Condition .' - Humidity '. $output->Humidity .' % - Wind '. $output->Wind .' '. $output->wind_unit_table .'">'. $output->Temperature .' °'. $output->temperature_unit .' </td><td title="'. $output->Condition .' - Humidity '. $output->Humidity .' % - Wind '. $output->Wind .' '. $output->wind_unit_table .'"><img src="'. $output->Icon .'" class="'. $icon_class .'" alt="'. weathericon .'" title="'. $output->Condition .' - Humidity '. $output->Humidity .' % - Wind '. $output->Wind . $output->wind_unit_table .'" /></td>';
}
}
}
foreach($names as $location=>&$place) {
$place=trim($place);
$Out[$location] = '<tr class="'. $row_class .'"><td class="'. $place_class .'" title="Weather in '. $place .'">'. $place .'</td>'. $Out[$location] .'</tr>';
}
$all='<table class="'. $class .'">';
foreach ($Out as $a) {
$all.=$a;
}
$all=$all.'</table>';
return($all);
}
Offline
Re: Beta testers for new weather plugin needed
new version with all the above changes and started to integrate different language versions for titles in the table, titles are now only once defined
if parameter names
is not declared, the plugin uses instead the declared location codes
as the name of the city/town
// this plugin uses most of the code from
// snt_weather plugin
// by Simon Lindley
// http://www.simonaut.com/
// Version 0.2 - 11/06/2005
// 0.3 enhanced
// 0.3.1 Update 08/07/2009 API-Update
// 0.3.2 error handling
// 0.4.0 use of worldweatheronline api
// 0.5.0 new parameters, code cleaning, parameter "names" is not obligatory, different language strings
function wcz_weather($atts) {
extract(lAtts(array(
'codes'=>'',
'key'=>'',
'forecast'=>'0',
'image'=>'1',
'sprite_image'=>'1',
'wind_unit'=>'k',
'temperature_unit'=>'c',
'place_class'=>'weather',
'temperature_class'=>'weather',
'icon_class'=>'weather-sprite',
'row_class'=>'weather',
'class'=>'weather',
'language'=>'en',
'debug'=>'0'
),$atts));
$codes=explode(",",$codes);
if (empty($names)) {
$names=$codes;
}
else { $names=explode(",",$names); }
// language part
// German
if ($language=="de"){
$humidity="Luftfeuchtigkeit";
$wind="Windgeschwindigkeit";
$rowtext="Das Wetter in";
}
else {
// Russian
if ($language=="ru"){
$humidity="влажность";
$wind="скорость ветра";
$rowtext="Погода в";
}
else {
// Ukrainian
if ($language=="ua"){
$humidity="вологість";
$wind="швидкість вітру";
$rowtext="Погода в";
}
else {
// English
$humidity="humidity";
$wind="wind speed";
$rowtext="The weather in";
}
}
}
class wcz_weather_class {
// function must have the same name as the class!
function wcz_weather_class($loc_code,$key,$forecast,$debug,$wind_unit,$temperature_unit) {
$xml=simplexml_load_string(file_get_contents("http://free.worldweatheronline.com/feed/weather.ashx?q=".$loc_code."&format=xml&num_of_days=".$forecast."&key=".$key));
if ($debug == "1") {print_r($xml);}
if($xml){
if(isset($xml->error)) {
$this->Temperature='-';
$this->Icon='na';
$this->Condition='-';
$this->Humidity='-';
$this->Wind='-';
}
else
{
if ($temperature_unit == "f") {
$this->Temperature=htmlspecialchars($xml->current_condition->temp_F);
$this->temperature_unit="F";
}
else {
$this->Temperature=htmlspecialchars($xml->current_condition->temp_C);
$this->temperature_unit="C";
}
if ($wind_unit == "m") {
$this->Wind=htmlspecialchars($xml->current_condition->windspeedMiles);
$this->wind_unit_table='mph';
}
else {
$this->Wind=htmlspecialchars($xml->current_condition->windspeedKmph);
$this->wind_unit_table='km/h';
}
$this->Icon=htmlspecialchars($xml->current_condition->weatherIconUrl);
$this->Condition=htmlspecialchars($xml->current_condition->weatherDesc);
$this->Humidity=htmlspecialchars($xml->current_condition->humidity);
if ($debug == "1") {
print_r($this->Temperature);
print_r($this->Icon);
print_r($this->Condition);
print_r($this->Humidity);
print_r($this->Wind);
print_r($this->temperature_unit);
print_r($this->wind_unit);
print_r($this->wind_unit_table);
}
}
}
else
{
$this->Temperature='-';
$this->Icon='na';
$this->Condition='-';
$this->Humidity='-';
$this->Wind='-';
}
// end of the function
}
// end of the class
}
$Out=array();
$output=array();
foreach ($codes as &$loc_code) {
$loc_code=urlencode(trim($loc_code));
$output = new wcz_weather_class($loc_code,$key,$forecast,$debug,$wind_unit,$temperature_unit);
$title=$output->Condition ." - ". $humidity ." ". $output->Humidity ." % - ". $wind ." ". $output->Wind ." ". $output->wind_unit_table;
if($image == "0") {
$Out[] = '<td class="'. $temperature_class .'" title="'. $title .'">'. $output->Temperature .' °'. $output->temperature_unit .'</td>';
}
else {
if($sprite_image == "1") {
$icon = str_replace(array('http://www.worldweatheronline.com/images/wsymbols01_png_64/','.png'),'',substr(strrchr($output->Icon,'/'),1));
$Out[] = '<td class="'. $temperature_class .'" title="'. $title .'">'. $output->Temperature .' °'. $output->temperature_unit.' </td><td class="'. $icon_class .'" title="'. $title .'" id="'. $icon .'"> </td>';
}
else {
$Out[] = '<td class="'. $temperature_class .'" title="'. $title .'">'. $output->Temperature .' °'. $output->temperature_unit .' </td><td title="'. $title .'"><img src="'. $output->Icon .'" class="'. $icon_class .'" alt="'. weathericon .'" title="'. $title .'" /></td>';
}
}
}
foreach($names as $location=>&$place) {
$place=trim($place);
$Out[$location] = '<tr class="'. $row_class .'"><td class="'. $place_class .'" title="'. $rowtext .' '. $place .'">'. $place .'</td>'. $Out[$location] .'</tr>';
}
$all='<table class="'. $class .'">';
foreach ($Out as $a) {
$all.=$a;
}
$all=$all.'</table>';
return($all);
}
Offline
Re: Beta testers for new weather plugin needed
New version is online. See first post …
Worldweatheronline.com changed their api-server.
Offline
Re: Beta testers for new weather plugin needed
The code is also now on github. Follow this link
Offline