Wednesday, October 10, 2012

QR code的安全性问题


不知何时,QR 码(Quick Response code,二维条形码的一种)不再陌生——虽然还带着一丝神秘。虽然早在1994年该项技术就已经被发明,且早就被广泛应用于各行各业,但真正流行还是在手机上读码应用出现之后。比起在手机上一个字符一个字符地输入网址、名片、优惠券编号、或者地理坐标,QR码实在是有点方便。只要用手机拍一张QR码的照片,籍由手机内的QR解码应用,便能即刻存贮或使用信息。

对于市场营销来说,QR码简直是技术带来的新福音。通过在报纸、海报、网站甚至电视上放置QR码广告,可以有效地激活不同地点、不同类别的客户群。通常客户用手机解码QR码的时候,会打开一个网页,并可以同时传送一些客户终端数据给网站。这些客户数据又将反馈给营销人员,做出更好的营销策划。

看上去很美,不是么?有什么问题?不久以前,网络营销人员曾经为email欢呼过。通过email发出最新的商品目录和链接。客户点击链接,就可以进入网点购买,甚至享受优惠。直到——有人利用浏览器或网页的漏洞,骗取客户电脑上的信息,这就是所谓Phishing攻击。这些营销email就被无情地归类为垃圾邮件了。

这次不同。因为Phishing更简单了。第一,链接是可读的,有经验的人可以从网址上大约看出链接是不是可信的;QR码不可读,没人可以一眼看出QR码会把你带去哪个网站。第二,相比email局限于电子终端,QR码可以无处不在。第三,手机上记载的个人信息会远远多于电脑上的。第四,我们听说过很多电脑上的防毒软件防火墙之类,但有人听说过手机上的防毒软件么?第五,对于客户来说,QR码由于往往出现在传统媒体上,会更容易被客户信任,认为是
安全的。

QR码的流行意味着更大的商机,更大的目标群体,当然更多人会愿者上钩。谁来保护我们?目前为止,我们最好自己输入网址,而不是让QR码帮你走捷径。

Tuesday, August 7, 2012

Read Write Cookie with PHP

Save cookie
(before the body tag, set variables and the save cookie function for page postback)

if(isset($_GET['save_cookie']))
{
   setcookie("event[$id]","$time:$page:$link",time()+(86400*7),'/',$domain);
}

(within the body, use a form to incur post back)
<form class="add" method="get">
<input name="save_cookie" type="hidden" />

<input type="submit" value="+ Add to your day" />

<span class="ic-addtoyourday">Add to your day</span>
</form>

Read cookie
(loop through the cookie array)
    
    foreach ($_COOKIE['event'] as $key => $value)
    {
        //echo "$key:$value";
        $arr = explode(':', $value);
        echo '<a href="'.$arr[2].'">'; // link
        echo $arr[1]; // title
    }
    
    if(!isset($_COOKIE['event']))
    {
        echo 'You have not added any events.';
    }
    

Thursday, July 19, 2012

Get most popular pages in Sitecore

Assume you have installed the DMS package and it is working. In other words, you can see some data generating in the dbo.Pages table from the your analytics database.
(How to make sure DMS is installed correctly:
http://www.sitecore.net/deutsch/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/08/Troubleshooting-Analytics-is-Disabled-with-the-Sitecore-Customer-Engagement-Platform.aspx)

Now we need to get the most popular pages (i.e., most viewed pages) or its statistics in Sitecore. Of course, it is easier to expose the relavant tables in the database in your solution using entity framework. However it is a really bad idea; because you don't really want to allow any other operations except retrieval.

So it is better to create a view in the database, fast and readonly ensured. In my case, I actually created a view outside any Sitecore default database. The query is something like:

SELECT     TOP (100) PERCENT pa.ItemId, it.TemplateID, pa.PageViewCount
FROM         (SELECT     ItemId, COUNT(*) AS PageViewCount
                       FROM          My_Sitecore_Analytics.dbo.Pages
                       GROUP BY ItemId) AS pa INNER JOIN
                      My_Sitecore_Master.dbo.Items AS it ON pa.ItemId = it.ID
ORDER BY pa.PageViewCount DESC

Then include this view in your solution using entity framework. You can freely query the view using Linq.

Tuesday, July 10, 2012

Extracting Twitter Posts and Twitter Mentions

    public class Twitter
    {
        private static XDocument xDoc = null;
 
        public Int32 TweetCount { getset; }
        public String TwitterProfileName { getset; }
 
        public List<Tweet> Tweets
        {
            get
            {
                XDocument xml = LoadTweetXML(false);
 
                if (xml == null)
                    throw new Exception(String.Format("Failed to get tweets from {0}", TwitterProfileName));
 
                var query = from e in xml.Descendants("item")
                            select new Tweet
                            {
                                Id = e.Element("guid").Value,
                                Title = e.Element("title").Value
                                        .Replace(String.Format("{0}: ", TwitterProfileName), String.Empty),
                                Link = e.Element("link").Value,
                                Content = e.Element("description").Value,
                                Published = Convert.ToDateTime((e.Descendants("pubDate").First().Value)),
                            };
 
                return query.ToList();
            }
        }
 
        public List<Tweet> TweetMentions
        {
            get
            {
                XDocument xml = LoadTweetXML(true);
 
                if (xml == null)
                    throw new Exception(String.Format("Failed to get tweets mentions from {0}", TwitterProfileName));
 
                XNamespace ns = "http://www.w3.org/2005/Atom";
 
                var query = from item in xml.Descendants(ns + "entry").Take(TweetCount)
                            select new Tweet
                            {
                                Id = item.Element(ns + "id").Value,
                                Published = DateTime.Parse(item.Element(ns + "published").Value),
                                Title = item.Element(ns + "title").Value,
                                Content = item.Element(ns + "content").Value,
                                Link = (from XElement x in item.Descendants(ns + "link")
                                        where x.Attribute("type").Value == "text/html"
                                        select x.Attribute("href").Value).First(),
                                Image = (from XElement x in item.Descendants(ns + "link")
                                         where x.Attribute("type").Value == "image/png"
                                         select x.Attribute("href").Value).First(),
                                Author = new Author()
                                {
                                    Name = item.Element(ns + "author").Element(ns + "name").Value,
                                    Uri = item.Element(ns + "author").Element(ns + "uri").Value
                                }
                            };
 
                return query.ToList();
            }
        }
 
        public Twitter(string screenName, int numTweets = 10)
        {
            TwitterProfileName = screenName;
            TweetCount = numTweets;
        }
 
        private XDocument LoadTweetXML(bool isMentions)
        {
            try
            {
                string url;
                if (isMentions)
                    url = String.Format(
                        "http://search.twitter.com/search.atom?lang=en&q={0}",
                        System.Web.HttpUtility.UrlEncode(TwitterProfileName));
                else
                    url = String.Format(
                        "http://api.twitter.com/statuses/user_timeline.rss?screen_name={0}&count={1}",
                        TwitterProfileName, TweetCount);
                xDoc = XDocument.Load(url);
                return xDoc;
            }
            catch
            {
                return null;
            }
        }
 
        public class Tweet
        {
            public string Id { getset; }
            public DateTime Published { getset; }
            public string Title { getset; }
            public string Content { getset; }
            public string Link { getset; }
            public Author Author { getset; }
            public string Image { getset; }
        }
 
        public class Author
        {
            public string Name { getset; }
            public string Uri { getset; }
        }
    }

Thursday, January 26, 2012

Singleton in Objective C

Method 1:
@interface SomeManager : NSObject
+ (id)sharedManager;
@end

@implementation SomeManager

+ (id)sharedManager {
    static id sharedManager = nil;

    if (sharedManager == nil) {
        sharedManager = [[self alloc] init];
    }

    return sharedManager;
}

@end
The astute reader will notice, of course, that this isn’t thread-safe. I got rid of the @synchronized (self)because it won’t do the right thing; depending on what actual class is sent +sharedManager, the value of self will be different!
Method 2:
One way to do this would be to create your singleton instance in +initialize since it will always be run, on a single thread, before any other methods in your class:

@implementation SomeManager

static id sharedManager = nil;

+ (void)initialize {
    if (self == [SomeManager class]) {
        sharedManager = [[self alloc] init];
    }
}

+ (id)sharedManager {
    return sharedManager;
}

@end
By doing this, you avoid the performance bottleneck of @synchronized taking a recursive lock every time+sharedManager is invoked.


Method 3 (ARC version):

+ (id)sharedInstance
{
  static dispatch_once_t pred = 0;
  __strong static id _sharedObject = nil;
  dispatch_once(&pred, ^{
    _sharedObject = [[self alloc] init]; // or some other init method
  });
  return _sharedObject;
}

iOS Callbacks

A nice post from Bynomial Code:


A callback is a method that you think of as being called from outside your code.
More formally, a callback is a method that can be called by other classes which may be created after, or independently of, your class.  These methods are named callbacks because we have to explicitly provide a pointer to the caller so they can “call us back” later.  Two classic examples: an asynchronous NSURLConnection needs a way to report back when it’s done loading a page, and a UIButton needs a way to report that a user pressed the button.

Types of Callbacks

Delegation or Formal Protocols

Delegation is one of the most common callback mechanisms in current Objective-C code.  The use of formal protocols (or just “protocols” in the language spec) is almost synonymous with delegates, so I’ll group them together here; although you can use protocols for non-delegate purposes, too.
To use this method, you declare a set of methods in a @protocol block, and require the class getting called back to be set as your delegate object – generally this is a weak reference (not retained) to an id type.  When you want to call the callback, you can simple execute a [delegate doMyCallbackWithObject:x] statement on required methods.  For optional methods, first check that they’re implemented, and either call them or execute your default behavior.
UITableViewDelegate is a good example protocol for this callback mechanism.

Target/Action Pairs

UIControl and therefore its subclasses – including UIButton, UISwitch, and UISlider, to name a few – all use a target/action pair method to handle callbacks.
To use this method, the class getting called back must specify both a selector (the action) and an object pointer (the target) that you can call at any time.  It is up to the target to make sure the signature (i.e. the set of input and output parameters) of the action is something useful to your class.  Notice that each selector has to be registered separately, as opposed to the delegate method which registers all the callbacks in one set.

Informal Protocols or Category Callbacks

Objective-C didn’t always have the @optional keyword for @protocols, which makes delegation very practical.  Before @optional, it was common to add a category to NSObject which implemented the callbacks you needed – this is an informal protocol.  This is similar to a formal callback in that all the names and signatures of the methods are fixed and available in a header file, but it differs in that all objects necessarily have a default implementation (no required or optional distinction) and a class can’t officially declare that it overrides these methods (but we can still find out at runtime of course).
Apple is phasing out informal protocols in favor of formal ones, although they can still be useful in situations where you’d prefer all objects to have easy access to default implementation of the protocol.
NSURLConnection is an example of an informal protocol callback mechanism.

Notifications

Notifications are ideal for broadcasting messages (one-caller-to-many-callback-receivers) or for some decoupling of the caller and receiver.
To use this method, the caller simply posts an NSNotification object to an NSNotificationCenter; any classes that are interested in being called from this must have previously registered themselves as an observer of that notification.  Notifications are identified by strings, and there is no formal way to declare which notifications your code produces – this communication must happen in comments/documentation (or by hand-parsing the code if you have to).
UIKeyboardWillShowNotification is an example notification name (it’s a string) that is posted when the keyboard is about to show up.  This gives UI elements a chance to react by moving important views so they’re not obstructed by the keyboard.

Choosing a type of callback

Each approach has pros and cons.  To help see this, consider the use cases for UITableViewDelegate (delegation), UIButton (target/action), NSURLConnection (informal protocol), and UIKeyboardWillShowNotification (notification).
Delegation Pros: One object pointer connects all the methods, signatures and names of methods are clearly documented, required and optional method distinction.  Cons: Impractical to be a delegate for multiple objects, subclassing the called back class is challenging.
Target/Action Pros: Easy to work with multiple objects giving callbacks, flexible signatures, only one method at a time is required.  Cons: Practical only for small sets of methods, signatures are not formally declared, receiver must unregister itself before it’s gone.
Informal Protocol Pros: Default implementation always available, possible to avoid specifying a target.  Cons: No compile-time declaration of following an informal protocol, fills up the method namespace, no required/optional distinction.
Notification Pros: There can easily be many targets, caller doesn’t need any pointers to targets, receiver and target can be created in any order.  Cons: Input parameters must be packaged in a userInfo dictionary, notification names are not formally declared, receiver must unregister itself before it’s gone, slightly longer calling time due to indirection.
How to choose?
If you might have many callers for the same target (such as a custom UI control), then target/action is probably good.
If you might have many targets for a single caller, then a notification is probably good, although you could also handle this with target/action if tighter coupling is preferred.
If you expect a one-to-one pairing between caller and target, then a delegate is probably the way to go.
Are there still times to use informal protocols?  Some folks might say no, but I’ll argue against that.
A case for informal protocols
When would you like to use informal protocols?  I suggest using them when you want to implement a simple asynchronous interface with optional callbacks for a universally usable piece of functionality.
For example, suppose you’re writing a serialization method that uses Objective-C’s reflection to convert any class into a string (your own version of NSCoding, basically).  You’d like to allow any object to be able to call:
[self writeToURL:myURL];
And have this work out.  In this case, a category on NSObject is perfect.  Now, suppose you want to give users a chance to react to an error asynchronously, but only if they want to.  Then you could implement your own version of [NSObject writeToURLFailedWithError:(NSError *)error], which simply NSLogs the error, and allow users to override this method.  This is nice because the user’s class never has to specify itself as a delegate or a target/action – you’re aware of both the target (since you have access to self in writeToURL:) and the action (since you name the selector in your category).  In other words, we’ve just made using this functionality a little easier by using an informal protocol.

Resources

  1. Cocoa Fundamentals Guide: Object Communications – The best general documentation for all this stuff.
  2. A concise explanation of formal vs. informal protocols
  3. The Objective-C language spec for protocols
  4. The Target-Action Mechanism – part of the UIControl class reference
  5. Notification Programming Guide
  6. NSKeyValueObserving Protocol Reference – An example informal protocol, and can be used to essentially create yet another type of callback mechanism – although, that’s a subject for another pos