I'm working on a QR code parser and I'm wondering if anyone knows of a MeCard library, or code that converts a MeCard to a VCard. If not, is there an official specification doc for MeCard out there? I know NTT DoCoMo created it, but I can't find any kind of RFC on it.
From http://code.google.com/p/zxing/wiki/BarcodeContents, I found a link to DoCoMo's specification for MeCard, at http://www.nttdocomo.co.jp/english/service/developer/make/content/barcode/function/application/addressbook/index.html. It is pretty dirt simple and converting it to a VCard with a function call should be pretty trivial.
== EDIT ==
I wrote a little conversion function. Just in case anyone in the future wants the code, it is below:
private function MeCardtoVCard($mecard_text)
{
// Useful References:
// http://www.nttdocomo.co.jp/english/service/developer/make/content/barcode/function/application/addressbook/index.html
// http://code.google.com/p/zxing/wiki/BarcodeContents
// http://en.wikipedia.org/wiki/VCard
// https://theqrplace.wordpress.com/2011/05/02/qr-code-tech-info-mecard-format/
$vcard = '';
if (stripos($mecard_text, "mecard") === 0)
{
$mecard_text = str_replace("\n", "", $mecard_text); // Strip out newlines
$mecard_text = substr($mecard_text,7); // Strip off the MECARD: header
$lines = explode(";", $mecard_text);
if (count($lines) > 0)
{
// Using Version 2.1 because it is the most commonly supported.
$vcard = "BEGIN:VCARD\nVERSION:3.0\n";
foreach($lines as $l)
{
$line_elements = explode(":",$l);
if (count($line_elements) > 1)
{
// Must split into two parts. Not sure how DoCoMo escapes
// data that actually contains a ":", so for now we are presuming
// that the first token is the property name and all other elements
// are the value
$property = $line_elements[0];
$value = implode(":", array_slice($line_elements,1));
if ($property != '' && $value != '')
{
if ($property == 'N')
{
// MeCards only support first and last name.
$tmp = explode(",",$value);
if (count ($tmp) == 1)
{
$vcard .= "N:;" . $tmp[0] . "\n";
}
else
{
$vcard .= "N:" . implode(";",explode(",",$value)) . "\n";
}
}
if ($property == 'TEL')
{
// MeCard does not use card types, so we will presume all of them are type CELL
$vcard .= "TEL:" . $value . "\n";
}
if ($property == 'ADR')
{
// MeCard: "The fields divided by commas (,) denote PO box, room number, house number, city, prefecture, zip code and country, in order."
// VCard: "...post office box; the extended address; the street address; the locality (e.g., city); the region (e.g., state or province); the postal code; the country name" See http://www.ietf.org/rfc/rfc2426.txt 3.2.1
$vcard .= "ADR:" . implode(";",explode(",",$value)) . "\n";
}
if (in_array($property, array('NOTE', 'BDAY', 'URL', 'NICKNAME')))
{
$vcard .= $property . ':' . $value . "\n";
}
}
}
}
$vcard .= "END:VCARD\n";
return $vcard;
}
else
{
return false;
}
}
return false;
}
Related
Right now my breadcrumbs are showing up like Home > Services > X-Ray, but I would like them to just show up like Home > Services, is there a way to customize Breadcrumbs NavXT to do this this?
go in /wp-content/plugins/breadcrumb-navxt/class.bcn_breadcrumb_trail.php
find function display and replace it with:
public function display($return = false, $linked = true, $reverse = false)
{
//Set trail order based on reverse flag
$this->order($reverse);
//Initilize the string which will hold the assembled trail
$trail_str = '';
$position = 1;
//The main compiling loop
foreach($this->breadcrumbs as $key => $breadcrumb)
{
//We do different things for the separator based on the breadcrumb order
if($reverse)
{
//Add in the separator only if we are the 2nd or greater element
if($key > 0)
{
$trail_str .= $this->opt['hseparator'];
}
}
else
{
if($key == 0 ) continue;
//Only show the separator when necessary
if($key < count($this->breadcrumbs) - 1)
{
$trail_str .= $this->opt['hseparator'];
}
}
//Trim titles, if needed
if($this->opt['blimit_title'] && $this->opt['amax_title_length'] > 0)
{
//Trim the breadcrumb's title
$breadcrumb->title_trim($this->opt['amax_title_length']);
}
//Place in the breadcrumb's assembled elements
$trail_str .= $breadcrumb->assemble($linked, $position);
$position++;
}
//Should we return or echo the assembled trail?
if($return)
{
return $trail_str;
}
else
{
//Helps track issues, please don't remove it
$credits = "<!-- Breadcrumb NavXT " . $this::version . " -->\n";
echo $credits . $trail_str;
}
}
if you use a different version i have add this row:
if($key == 0 ) continue;
I need create a function that checks a parsed value to see if it matches a few other values and then return that match. For example I am trying to match video urls correctly. So if it's youtube do this or if it's vimeo do this or if it's nothing do this. I know how to create a function but I'm not sure what to use for the parse, would it be parse_url?
For my test cases I need to send in the right parameter and then see that the returned values are matching what I want them to be.
Here's what I've tried so far:
function get_video_embed_string($videostring) {
$video_url_parse = parse_url( $videostring, PHP_URL_HOST ); //get the input string ready to parse
$returnstring = ""; //default return string to empty string
if ($video_url_parse === 'vimeo.com') {
$returnstring = str_replace( 'vimeo.com', 'player.vimeo.com', $video_url_parse );
} else if ($video_url_parse === 'youtube.com') {
$returnstring = str_replace( 'youtube.com', 'youtube.com/embed/', $video_url_parse );
} else {
//do nothing
}
return $returnstring;
}
parse_str($returnstring);
//now setup your test cases and see what echos out of the above method
if ($returnstring === 'player.vimeo.com') {
echo "vimeo: <" . get_video_embed_string ("https://vimeo.com/abcdefg123") . ">";
} else if ($returnstring === 'youtube.com/embed/'){
echo "youtube: <" . get_video_embed_string ("https://youtube.com/abcdefg123") . ">";
} else if($returnstring === '' ){
echo "nothing: <" . get_video_embed_string ("https://abc123.com/abcdefg123") . ">";
} else {
echo "empty:< " . get_video_embed_string ("") . ">";
}
I think you're on the right track using parse_url, but I have a couple suggestions for improvement:
instead of the run-on if/elseif chain, use a switch
the str_replace isn't working well as is because you're replacing the parsed host, so why spend the overhead searching again for the string to replace when you've already found it.
in the user comments for parse_url, there's an excellent example to reconstruct the parsed url. this will avoid string replacements where the host name is also part of the url (www.youtube.com/youtubevideo123)
simplify your test cases by just calling your function for each case instead of another if/else chain check.
function get_video_embed_string($videostring) {
$video_url_parse = parse_url($videostring); //get the input string ready to parse
switch ($video_url_parse['host']) {
case 'vimeo.com':
$video_url_parse['host'] = 'player.vimeo.com';
return unparse_url($video_url_parse);
case 'youtube.com':
$video_url_parse['host'] = 'youtube.com/embed';
return unparse_url($video_url_parse);
default:
return unparse_url($video_url_parse);
}
}
function unparse_url($parsed_url) {
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass#" : '';
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return "$scheme$user$pass$host$port$path$query$fragment";
}
//now setup your test cases and see what echos out of the above method
echo "vimeo: <" . get_video_embed_string ("https://vimeo.com/abcdefg123") . ">\n";
echo "youtube: <" . get_video_embed_string ("https://youtube.com/abcdefg123") . ">\n";
echo "nothing: <" . get_video_embed_string ("https://abc123.com/abcdefg123") . ">\n";
echo "empty:< " . get_video_embed_string ("") . ">\n";
This will result in the following output in source:
vimeo: <https://player.vimeo.com/abcdefg123>
youtube: <https://youtube.com/embed/abcdefg123>
nothing: <https://abc123.com/abcdefg123>
empty:< >
parse_url() is very good for parsing URLs and - in your case - extract the host name from it.
Your example is a little messed up. $returnstring is not defined outside of your function. You should turn error reporting on, so you will see NOTICE messages on this kind of errors.
I assume, your function should return the video embed url, not only the host name. So you should do your replace on $videostring, not $video_url_parse:
function get_video_embed_string($videostring) {
$video_url_parse = parse_url( $videostring, PHP_URL_HOST ); //get the input string ready to parse
$returnstring = ""; //default return string to empty string
if ($video_url_parse === 'vimeo.com') {
$returnstring = str_replace( 'vimeo.com', 'player.vimeo.com', $videostring );
} else if ($video_url_parse === 'youtube.com') {
$returnstring = str_replace( 'youtube.com', 'youtube.com/embed', $videostring );
} else {
//do nothing
}
return $returnstring;
}
This will give you this output:
echo get_video_embed_string("https://vimeo.com/abcdefg123"); // https://player.vimeo.com/abcdefg123
echo get_video_embed_string("https://youtube.com/abcdefg123"); // https://youtube.com/embed/abcdefg123
echo get_video_embed_string("https://abc123.com/abcdefg123"); // <empty string>
[For a more robust approach, I would probably try to extract the video ID from all known valid URL schemes using regexp and just insert this ID in the embed url.]
I'm working on a little project and I've gone brain dead, so I'm hoping someone here can help me defeat my coders block.
I'm trying to create a page using php that changes its content display depending on what (if any) value is passed to the page (Locations). I have created a safelist array which I've stored the different locations. First I check any value passed against the safe list, if its a match I display one set of content.
If it doesn't match I'm running a similarity test to check if theres maybe a simple typo and can still navigate people to the page I think they wanted but this is where I'm getting stuck.
I'm hoping that someone could type
www.example.co.uk/location.php <---- to load a generic location page
www.example.co.uk/location.php?loc=Bishops-Stortford <---- to load a targeted location page
www.example.co.uk/location.php?loc=Bishop-Stortford <---- to load a targeted location page despite mispelling providing its a 90% or more match
www.example.co.uk/location.php?loc=?php echo "I hacked your site"; ?> ---- hopefully my system will disarm nasty code injection
I'll post my code below so you can see what I've got.
<?php
$loc = "";
$safelist = array("Bishops Stortford", "Braintree", "Chelmsford", "Dunmow", "Harlow", "Hertford", "Saffron Walden", "Sawbridgeworth", "Stansted", "Ware",
"Essex", "Hertfordshire");
if(isset($_GET["loc"])) {
/* Gets the value of loc if set, replaces hyphens with spaces and capitalises first letters of words converting the rest to lowercase. */
$loc = ucwords(strtolower(str_replace("-", " ", $_GET["loc"])));
}
/* Is word in safelist */
if (in_array($loc, $safelist)) {
/* Yes */
if (($loc == "Essex") or ($loc == "Hertfordshire")) {
$county = True;
} else {
$county = False;
}
if ($county == False) {
echo "\"" . $loc . "\" is not a county";
}else{
echo "\"" . $loc . "\" is a county";
}
} else {
/* No, Is string 90% similar to any entry within the safelist? */
foreach ($safelist as $safeword) {
similar_text($safeword, $loc, $percent);
echo $safeword . " " . $loc . " " . $percent . "<br />";
if ($percent >= 90) {
}
}
?>
I can't think what to do for the if ($percent >=90). I know I want to exit the loop and get the result from the first 90% or more match I find but am not 100% sure how to do this.
Also whats the best way to deal with code injection like www.example.co.uk/location.php?loc=?php echo "I hacked your site"; ?>
I think this is what you want:
foreach ($safelist as $safeword) {
similar_text($safeword, $loc, $percent);
echo $safeword . " " . $loc . " " . $percent . "<br />";
if ($percent >= 90) {
$loc = $safeword;
$county = true;
break;
}
}
As long as you don't call eval() on user input, you don't have to worry about them injecting PHP statements. When you echo something, it's sent to the browser, it's not executed again by PHP. However, you should still sanitize the output, because it might contain HTML markup, perhaps even Javascript, which could hijack the user's browser. When displaying output on the page, use htmlentities() to encode it:
echo "Greetings, " . htmlentities($first_name);
To answer the second part of your question, I use htmlentities to output data directly to the screen from input and something like this function on the data before a save to a database:
function escape_value($value)
{
if($this->real_escape_string_exists)
{
if($this->magic_quotes_active){$value = stripslashes($value);}
$value = mysql_real_escape_string($value);
}
else
{
if(!$this->magic_quotes_active){$value = addslashes($value);}
}
return $value;
}
I think I would restructure it, something like this:
$loc = "";
$safelist = array("Bishops Stortford", "Braintree", "Chelmsford", "Dunmow", "Harlow", "Hertford", "Saffron Walden", "Sawbridgeworth", "Stansted", "Ware",
"Essex", "Hertfordshire");
if(isset($_GET["loc"])) {
/* Gets the value of loc if set, replaces hyphens with spaces and capitalises first letters of words converting the rest to lowercase. */
$loc = ucwords(strtolower(str_replace("-", " ", $_GET["loc"])));
}
$good = '';
if (in_array($loc, $safelist)) {
$good = $loc;
} else {
foreach ($safelist as $safeword) {
similar_text($safeword, $loc, $percent);
echo $safeword . " " . $loc . " " . $percent . "<br />";
if ($percent >= 90) {
$good = $safeword;
}
}
}
if ( ! empty($good)){
/* Yes */
if (($good == "Essex") or ($good == "Hertfordshire")) {
$county = True;
} else {
$county = False;
}
if ($county == False) {
echo "\"" . $good . "\" is not a county";
}else{
echo "\"" . $good . "\" is a county";
}
//And whatever else you want to do with the good location...
}
Like Barmar said, since you're not doing anything with the input value except for comparing it to an array, there's no risk of an attack in that way.
I have magento, and I'm posting a request via the soap v2 api to get the address of an order.
With that I get the following object which contains the street name + housenumber(God knows why these fields are not seperate...)
$shipping_address->street = "4th avenue 108";
Now what I want is to have the housenumber 108.
How do I get this house number without getting the 4?
(if someone has a more reliable function/piece of code than the one I post below, please feel free to post it.)
What you basically have to do is check for the first number occurence with a space in front of it.
This way you minimse the risk of fetching the wrong number:
// Code by Michael Dibbets
// shared under creative commons Attribution 3.0 Unported (CC BY 3.0 http://creativecommons.org/licenses/by/3.0/ )
$value = "4th street26";
$spl = str_split($value);
$pos = 0;
$location = 0;
// simple loop to find the first character with space + integer
foreach($spl as $char)
{
if(is_numeric($char) && $spl[$pos-1]==' ')
{
$location = $pos;
break;
}
$pos++;
}
// If we didn't encounter the space + integer combination
if(!$location)
{
// is the last character an integer? Assume that the last numbers are house numbers
if(is_numeric($spl[count($spl)-1]))
{
for($c=count($spl)-1;$c>0;$c--)
{
if(is_numeric($spl[$c]))
{
continue;
}
else
{
$location = $c+1;
break;
}
}
}
}
if($location)
{
$street = substr($value,0,$location);
$number = substr($value,$location);
}
else
{
$street = $value;
$number = null;
}
// echoing the results. The number should appear after the dash.
echo $street . ' - ' . $number;
I'm using the jquery address plugin to build an ajax driven site, and i've got it working! Yay! For the purposes of this question we can use the test site:
http://www.asual.com/jquery/address/samples/crawling
http://www.asual.com/download/jquery/address
(I had to remove two calls to urlencode() to make the crawling example work.)
I'm encountering a problem with the $crawling->nav() call. It basically uses js and php to load parts of an xml file into the dom. I (mostly) understand how it works, and I would like to modify the example code to include sub pages.
For example, I would like to show 'subnav-project.html' at '/!#/project' and '/!#/project/blue', but not at '/!#/contact'. To do this, I figure php should 'know' what page the user is on, that way I can base my logic off of that.
Is this crazy? Can php ever know the current state of the site if I'm building it this way? If not, how does one selectively load html snippets, or modify what links are shown in navigation menus?
I've never gotten too crazy with ajax before, so any feedback at all would be helpful.
EDIT
This is the crawling class.
class Crawling {
const fragment = '_escaped_fragment_';
function Crawling(){
// Initializes the fragment value
$fragment = (!isset($_REQUEST[self::fragment]) || $_REQUEST[self::fragment] == '') ? '/' : $_REQUEST[self::fragment];
// Parses parameters if any
$this->parameters = array();
$arr = explode('?', $fragment);
if (count($arr) > 1) {
parse_str($arr[1], $this->parameters);
}
// Adds support for both /name and /?page=name
if (isset($this->parameters['page'])) {
$this->page = '/?page=' . $this->parameters['page'];
} else {
$this->page = $arr[0];
}
// Loads the data file
$this->doc = new DOMDocument();
$this->doc->load('data.xml');
$this->xp = new DOMXPath($this->doc);
$this->nodes = $this->xp->query('/data/page');
$this->node = $this->xp->query('/data/page[#href="' . $this->page . '"]')->item(0);
if (!isset($this->node)) {
header("HTTP/1.0 404 Not Found");
}
}
function base() {
$arr = explode('?', $_SERVER['REQUEST_URI']);
return $arr[0] != '/' ? preg_replace('/\/$/', '', $arr[0]) : $arr[0];
}
function title() {
if (isset($this->node)) {
$title = $this->node->getAttribute('title');
} else {
$title = 'Page not found';
}
echo($title);
}
function nav() {
$str = '';
// Prepares the navigation links
foreach ($this->nodes as $node) {
$href = $node->getAttribute('href');
$title = $node->getAttribute('title');
$str .= '<li><a href="' . $this->base() . ($href == '/' ? '' : '?' . self::fragment . '=' .html_entity_decode($href)) . '"'
. ($this->page == $href ? ' class="selected"' : '') . '>'
. $title . '</a></li>';
}
echo($str);
}
function content() {
$str = '';
// Prepares the content with support for a simple "More..." link
if (isset($this->node)) {
foreach ($this->node->childNodes as $node) {
if (!isset($this->parameters['more']) && $node->nodeType == XML_COMMENT_NODE && $node->nodeValue == ' page break ') {
$str .= '<p><a href="' . $this->page .
(count($this->parameters) == 0 ? '?' : '&') . 'more=true' . '">More...</a></p>';
break;
} else {
$str .= $this->doc->saveXML($node);
}
}
} else {
$str .= '<p>Page not found.</p>';
}
echo(preg_replace_callback('/href="(\/[^"]+|\/)"/', array(get_class($this), 'callback'), $str));
}
private function callback($m) {
return 'href="' . ($m[1] == '/' ? $this->base() : ($this->base() . '?' . self::fragment . '=' .$m[1])) . '"';
}
}
$crawling = new Crawling();
You won't be able to make server-side decisions using the fragment-identifier (i.e., everything to the right of the # character). This is because browsers don't send fragment-identifiers to the server. If you're going to want to make server-side decisions, you'll need to use some JavaScript assistance (including AJAX) to communicate what the current fragment-identifier is.