Creare_Latesttweet - Version 2.0.1

Version Notes

New release

Download this release

Release Info

Developer Robert Kent
Extension Creare_Latesttweet
Version 2.0.1
Comparing to
See all releases


Code changes from version 1.0.0 to 2.0.1

app/code/local/Creare/Latesttweet/Block/Latesttweet.php CHANGED
@@ -9,7 +9,7 @@ class Creare_Latesttweet_Block_Latesttweet extends Mage_Core_Block_Template
9
 
10
  public function isEnabled()
11
  {
12
- if(Mage::getStoreConfig('latesttweet/latesttweet/active')){
13
  return true;
14
  } else {
15
  return false;
@@ -18,54 +18,69 @@ class Creare_Latesttweet_Block_Latesttweet extends Mage_Core_Block_Template
18
 
19
  public function getTwitterId()
20
  {
21
- $twitterid = Mage::getStoreConfig('latesttweet/latesttweet/twitterid');
22
  return $twitterid;
23
  }
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  public function getNoFollow()
26
  {
27
- $nofollow = Mage::getStoreConfig('latesttweet/latesttweet/usenofollow');
28
  return $nofollow;
29
  }
30
 
31
  public function getNumberOfTweets()
32
  {
33
- $numberoftweets = Mage::getStoreConfig('latesttweet/latesttweet/numberoftweets');
34
  return $numberoftweets;
35
  }
36
 
 
 
 
 
 
 
37
  public function getTagPref()
38
  {
39
- $tagpref = Mage::getStoreConfig('latesttweet/latesttweet/showlinks');
40
  return $tagpref;
41
  }
42
 
43
  public function getNewWindow()
44
  {
45
- $tagpref = Mage::getStoreConfig('latesttweet/latesttweet/opennew');
46
  return $tagpref;
47
  }
48
 
49
- private function getTweetData($tweetxml)
50
- {
51
-
52
- $xmlDoc = new DOMDocument();
53
- $xmlDoc->load($tweetxml);
54
-
55
- $x = $xmlDoc->getElementsByTagName("entry"); // get all entries
56
- $tweets = array();
57
- foreach($x as $item){
58
- $tweet = array();
59
-
60
- if($item->childNodes->length) {
61
- foreach($item->childNodes as $i){
62
- $tweet[$i->nodeName] = $i->nodeValue;
63
- }
64
- }
65
- $tweets[] = $tweet;
66
- }
67
-
68
- return $tweets;
69
  }
70
 
71
  private function cleanTwitterName($twitterid)
@@ -80,7 +95,7 @@ class Creare_Latesttweet_Block_Latesttweet extends Mage_Core_Block_Template
80
 
81
  }
82
 
83
- private function changeLink($string, $tags=true, $nofollow=true, $newwindow=true)
84
  {
85
  if(!$tags){
86
  $string = strip_tags($string);
@@ -94,23 +109,9 @@ class Creare_Latesttweet_Block_Latesttweet extends Mage_Core_Block_Template
94
  return $string;
95
  }
96
 
97
- private function getTweetArray($tweets)
98
  {
99
-
100
- $data = array();
101
-
102
- if(empty($tweets)) {
103
- return false;
104
- }
105
- for($i=0;$i<count($tweets);$i++){
106
- $tweettag = $tweets[$i];
107
- /********************** Getting Times (Hours/Minutes/Days) */
108
- $tweetdate = $tweettag["published"];
109
- $tweet = $tweettag["content"];
110
- $timedate = explode("T",$tweetdate);
111
- $date = $timedate[0];
112
- $time = substr($timedate[1],0, -1);
113
- $tweettime = (strtotime($date." ".$time))+3600; // This is the value of the time difference - UK + 1 hours (3600 seconds)
114
  $nowtime = time();
115
  $timeago = ($nowtime-$tweettime);
116
  $thehours = floor($timeago/3600);
@@ -137,28 +138,72 @@ class Creare_Latesttweet_Block_Latesttweet extends Mage_Core_Block_Template
137
  } else {
138
  $timemessage = $thedays." days ago";
139
  }
140
- }
141
- $data[$i]["tweet"] = $this->changeLink($tweet, $this->getTagPref(), $this->getNoFollow(), $this->getNewWindow());
142
- $data[$i]["time"] = $timemessage;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
-
145
- return $data;
146
- }
147
 
148
  public function getLatestTweets()
149
  {
 
 
 
 
 
150
 
151
- $twitterid = $this->getTwitterId();
152
- $not = $this->getNumberOfTweets();
 
 
153
 
154
- if (!$twitterid){
155
  return false;
156
  }
157
 
158
- $twitterid = $this->cleanTwitterName($twitterid);
159
- $tweetxml = "http://search.twitter.com/search.atom?q=from:" . $twitterid . "&rpp=" . $not . "";
160
- $tweets = $this->getTweetData($tweetxml);
161
- return($this->getTweetArray($tweets));
 
 
 
162
 
163
  }
164
  }
9
 
10
  public function isEnabled()
11
  {
12
+ if(Mage::getStoreConfig('latesttweet/twittersettings/active')){
13
  return true;
14
  } else {
15
  return false;
18
 
19
  public function getTwitterId()
20
  {
21
+ $twitterid = Mage::getStoreConfig('latesttweet/twittersettings/twitterid');
22
  return $twitterid;
23
  }
24
 
25
+ public function getKeys()
26
+ {
27
+ $cs = Mage::getStoreConfig('latesttweet/twittersettings/consumerkey');
28
+ $csk = Mage::getStoreConfig('latesttweet/twittersettings/consumersecret');
29
+ $at = Mage::getStoreConfig('latesttweet/twittersettings/accesstoken');
30
+ $ats = Mage::getStoreConfig('latesttweet/twittersettings/accesstokensecret');
31
+
32
+ if($cs && $csk && $at && $ats){
33
+ return array(
34
+ 'consumerkey' => $cs,
35
+ 'consumersecret' => $csk,
36
+ 'accesstoken' => $at,
37
+ 'accesstokensecret' => $ats
38
+ );
39
+ } else {
40
+ return false;
41
+ }
42
+ }
43
+
44
  public function getNoFollow()
45
  {
46
+ $nofollow = Mage::getStoreConfig('latesttweet/displaysettings/usenofollow');
47
  return $nofollow;
48
  }
49
 
50
  public function getNumberOfTweets()
51
  {
52
+ $numberoftweets = Mage::getStoreConfig('latesttweet/displaysettings/numberoftweets');
53
  return $numberoftweets;
54
  }
55
 
56
+ public function showFollowButton()
57
+ {
58
+ $tagpref = Mage::getStoreConfig('latesttweet/displaysettings/showfollow');
59
+ return $tagpref;
60
+ }
61
+
62
  public function getTagPref()
63
  {
64
+ $tagpref = Mage::getStoreConfig('latesttweet/displaysettings/showlinks');
65
  return $tagpref;
66
  }
67
 
68
  public function getNewWindow()
69
  {
70
+ $tagpref = Mage::getStoreConfig('latesttweet/displaysettings/opennew');
71
  return $tagpref;
72
  }
73
 
74
+ public function getHashtags()
75
+ {
76
+ $tagpref = Mage::getStoreConfig('latesttweet/displaysettings/hashtags');
77
+ return $tagpref;
78
+ }
79
+
80
+ public function getAttags()
81
+ {
82
+ $tagpref = Mage::getStoreConfig('latesttweet/displaysettings/attags');
83
+ return $tagpref;
 
 
 
 
 
 
 
 
 
 
84
  }
85
 
86
  private function cleanTwitterName($twitterid)
95
 
96
  }
97
 
98
+ private function changeLink($string, $tags=true, $nofollow=true, $newwindow=true, $attags=true, $hashtags=true)
99
  {
100
  if(!$tags){
101
  $string = strip_tags($string);
109
  return $string;
110
  }
111
 
112
+ private function getTimeAgo($time)
113
  {
114
+ $tweettime = strtotime($time); // This is the value of the time difference - UK + 1 hours (3600 seconds)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  $nowtime = time();
116
  $timeago = ($nowtime-$tweettime);
117
  $thehours = floor($timeago/3600);
138
  } else {
139
  $timemessage = $thedays." days ago";
140
  }
141
+ }
142
+ return $timemessage;
143
+ }
144
+
145
+ public function getTweets($tweets)
146
+ {
147
+ $t = array();
148
+ $i = 0;
149
+ foreach($tweets as $tweet)
150
+ {
151
+ $text = $tweet->text;
152
+ $urls = $tweet->entities->urls;
153
+ $mentions = $tweet->entities->user_mentions;
154
+ $hashtags = $tweet->entities->hashtags;
155
+ if($urls){
156
+ foreach($urls as $url){
157
+ if(strpos($text,$url->url) !== false){
158
+ $text = str_replace($url->url,'<a href="'.$url->url.'">'.$url->url.'</a>',$text);
159
+ }
160
+ }
161
+ }
162
+ if($mentions && $this->getAttags()){
163
+ foreach($mentions as $mention){
164
+ if(strpos($text,$mention->screen_name) !== false){
165
+ $text = str_replace("@".$mention->screen_name." ",'<a href="http://twitter.com/'.$mention->screen_name.'">@'.$mention->screen_name.'</a> ',$text);
166
+ }
167
+ }
168
+ }
169
+ if($hashtags && $this->getHashtags()){
170
+ foreach($hashtags as $hashtag){
171
+ if(strpos($text,$hashtag->text) !== false){
172
+ $text = str_replace('#'.$hashtag->text." ",'<a href="http://twitter.com/search?q=%23'.$hashtag->text.'">#'.$hashtag->text.'</a> ',$text);
173
+ }
174
+ }
175
+ }
176
+ $t[$i]["tweet"] = trim($this->changeLink($text, $this->getTagPref(), $this->getNoFollow(), $this->getNewWindow()));
177
+ $t[$i]["time"] = trim($this->getTimeAgo($tweet->created_at));
178
+ $i++;
179
  }
180
+ return $t;
181
+ }
 
182
 
183
  public function getLatestTweets()
184
  {
185
+ require_once('twitteroauth/twitteroauth.php');
186
+
187
+ $screen_name = $this->getTwitterId();
188
+ $not = $this->getNumberOfTweets();
189
+ $keys = $this->getKeys();
190
 
191
+ $consumerkey = $keys['consumerkey'];
192
+ $consumersecret = $keys['consumersecret'];
193
+ $accesstoken = $keys['accesstoken'];
194
+ $accesstokensecret = $keys['accesstokensecret'];
195
 
196
+ if (!$screen_name){
197
  return false;
198
  }
199
 
200
+ $twitterconn = new TwitterOAuth($consumerkey, $consumersecret, $accesstoken, $accesstokensecret);
201
+
202
+ $latesttweets = $twitterconn->get("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=".$screen_name."&count=".$not);
203
+
204
+ if(!$latesttweets->errors){
205
+ return($this->getTweets($latesttweets));
206
+ }
207
 
208
  }
209
  }
app/code/local/Creare/Latesttweet/Block/_notes/dwsync.xml ADDED
@@ -0,0 +1 @@
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
app/code/local/Creare/Latesttweet/Helper/_notes/dwsync.xml ADDED
@@ -0,0 +1 @@
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
app/code/local/Creare/Latesttweet/Model/Adminhtml/System/Config/Source/Display.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Creare_Latesttweet_Model_Adminhtml_System_Config_Source_Display
3
+ {
4
+ public function toOptionArray()
5
+ {
6
+ $array = array(
7
+ array('value'=>'right', 'label'=>'Right'),
8
+ array('value'=>'left', 'label'=>'Left'),
9
+ array('value'=>'custom', 'label'=>'Custom')
10
+ );
11
+ return $array;
12
+ }
13
+ }
app/code/local/Creare/Latesttweet/Model/Adminhtml/System/Config/Source/_notes/dwsync.xml ADDED
@@ -0,0 +1 @@
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
app/code/local/Creare/Latesttweet/etc/_notes/dwsync.xml ADDED
@@ -0,0 +1 @@
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
app/code/local/Creare/Latesttweet/etc/config.xml CHANGED
@@ -1,108 +1,105 @@
1
- <?xml version="1.0"?>
2
- <!--
3
- /**
4
- * @category Creare
5
- * @package Creare_Latesttweet
6
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
- */
8
- -->
9
- <config>
10
- <modules>
11
- <Creare_Latesttweet>
12
- <version>0.1.0</version>
13
- </Creare_Latesttweet>
14
- </modules>
15
- <frontend>
16
- <layout>
17
- <updates>
18
- <latesttweet>
19
- <file>latesttweet.xml</file>
20
- </latesttweet>
21
- </updates>
22
- </layout>
23
- </frontend>
24
- <adminhtml>
25
- <layout>
26
- <updates>
27
- <latesttweet>
28
- <file>latesttweet.xml</file>
29
- </latesttweet>
30
- </updates>
31
- </layout>
32
- </adminhtml>
33
- <global>
34
- <models>
35
- <latesttweet>
36
- <class>Creare_Latesttweet_Model</class>
37
- <resourceModel>latesttweet_mysql4</resourceModel>
38
- </latesttweet>
39
- <latesttweet_adminhtml>
40
- <class>Creare_Latesttweet_Model_Adminhtml</class>
41
- </latesttweet_adminhtml>
42
- <latesttweet_mysql4>
43
- <class>Creare_Latesttweet_Model_Mysql4</class>
44
- <entities>
45
- <latesttweet>
46
- <table>latesttweet</table>
47
- </latesttweet>
48
- </entities>
49
- </latesttweet_mysql4>
50
- </models>
51
- <resources>
52
- <creare_latesttweet_setup>
53
- <setup>
54
- <module>Creare_Latesttweet</module>
55
- </setup>
56
- <connection>
57
- <use>core_setup</use>
58
- </connection>
59
- </creare_latesttweet_setup>
60
- </resources>
61
- <blocks>
62
- <latesttweet>
63
- <class>Creare_Latesttweet_Block</class>
64
- </latesttweet>
65
- </blocks>
66
- <helpers>
67
- <latesttweet>
68
- <class>Creare_Latesttweet_Helper</class>
69
- </latesttweet>
70
- </helpers>
71
- </global>
72
- <default>
73
- <latesttweet>
74
- <latesttweet>
75
- <active>1</active>
76
- <twitterid>magentofox</twitterid>
77
- <numberoftweets>1</numberoftweets>
78
- <showlinks>1</showlinks>
79
- <usenofollow>1</usenofollow>
80
- <opennew>1</opennew>
81
- </latesttweet>
82
- </latesttweet>
83
- </default>
84
- <adminhtml>
85
- <acl>
86
- <resources>
87
- <all>
88
- <title>Allow Everything</title>
89
- </all>
90
- <admin>
91
- <children>
92
- <system>
93
- <children>
94
- <config>
95
- <children>
96
- <latesttweet>
97
- <title>CreareGroup - All</title>
98
- </latesttweet>
99
- </children>
100
- </config>
101
- </children>
102
- </system>
103
- </children>
104
- </admin>
105
- </resources>
106
- </acl>
107
- </adminhtml>
108
- </config>
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * @category Creare
5
+ * @package Creare_Latesttweet
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ -->
9
+ <config>
10
+ <modules>
11
+ <Creare_Latesttweet>
12
+ <version>2.0.1</version>
13
+ </Creare_Latesttweet>
14
+ </modules>
15
+ <global>
16
+ <models>
17
+ <latesttweet>
18
+ <class>Creare_Latesttweet_Model</class>
19
+ <resourceModel>latesttweet_mysql4</resourceModel>
20
+ </latesttweet>
21
+ <latesttweet_adminhtml>
22
+ <class>Creare_Latesttweet_Model_Adminhtml</class>
23
+ </latesttweet_adminhtml>
24
+ <latesttweet_mysql4>
25
+ <class>Creare_Latesttweet_Model_Mysql4</class>
26
+ <entities>
27
+ <latesttweet>
28
+ <table>latesttweet</table>
29
+ </latesttweet>
30
+ </entities>
31
+ </latesttweet_mysql4>
32
+ </models>
33
+ <resources>
34
+ <creare_latesttweet_setup>
35
+ <setup>
36
+ <module>Creare_Latesttweet</module>
37
+ </setup>
38
+ <connection>
39
+ <use>core_setup</use>
40
+ </connection>
41
+ </creare_latesttweet_setup>
42
+ </resources>
43
+ <blocks>
44
+ <latesttweet>
45
+ <class>Creare_Latesttweet_Block</class>
46
+ </latesttweet>
47
+ </blocks>
48
+ <helpers>
49
+ <latesttweet>
50
+ <class>Creare_Latesttweet_Helper</class>
51
+ </latesttweet>
52
+ </helpers>
53
+ </global>
54
+ <frontend>
55
+ <layout>
56
+ <updates>
57
+ <latesttweet>
58
+ <file>creare_latesttweet.xml</file>
59
+ </latesttweet>
60
+ </updates>
61
+ </layout>
62
+ </frontend>
63
+ <default>
64
+ <latesttweet>
65
+ <twittersettings>
66
+ <active>0</active>
67
+ <twitterid>crearegroup</twitterid>
68
+ </twittersettings>
69
+ <displaysettings>
70
+ <showright>1</showright>
71
+ <numberoftweets>3</numberoftweets>
72
+ <showlinks>1</showlinks>
73
+ <usenofollow>1</usenofollow>
74
+ <opennew>1</opennew>
75
+ <attags>1</attags>
76
+ <hashtags>1</hashtags>
77
+ <showfollow>1</showfollow>
78
+ </displaysettings>
79
+ </latesttweet>
80
+ </default>
81
+ <adminhtml>
82
+ <acl>
83
+ <resources>
84
+ <all>
85
+ <title>Allow Everything</title>
86
+ </all>
87
+ <admin>
88
+ <children>
89
+ <system>
90
+ <children>
91
+ <config>
92
+ <children>
93
+ <latesttweet>
94
+ <title>CreareGroup - Latest Tweets</title>
95
+ </latesttweet>
96
+ </children>
97
+ </config>
98
+ </children>
99
+ </system>
100
+ </children>
101
+ </admin>
102
+ </resources>
103
+ </acl>
104
+ </adminhtml>
105
+ </config>
 
 
 
app/code/local/Creare/Latesttweet/etc/system.xml CHANGED
@@ -1,90 +1,197 @@
1
- <config>
2
- <tabs>
3
- <creare translate="label" module="latesttweet">
4
- <label>CreareGroup</label>
5
- <sort_order>100</sort_order>
6
- </creare>
7
- </tabs>
8
- <sections>
9
- <latesttweet translate="label" module="latesttweet">
10
- <label>Latest Tweet</label>
11
- <tab>creare</tab>
12
- <sort_order>1000</sort_order>
13
- <show_in_default>1</show_in_default>
14
- <show_in_website>1</show_in_website>
15
- <show_in_store>1</show_in_store>
16
- <groups>
17
- <latesttweet translate="label" module="latesttweet">
18
- <label>Latest Tweet</label>
19
- <frontend_type>text</frontend_type>
20
- <sort_order>1000</sort_order>
21
- <show_in_default>1</show_in_default>
22
- <show_in_website>1</show_in_website>
23
- <show_in_store>1</show_in_store>
24
- <comment>
25
- <![CDATA[<div class="creare-container">
26
- <div class="creare-header">This module was developed by <a href="http://www.e-commercewebdesign.co.uk" target="_blank">www.e-commercewebdesign.co.uk</a> - <strong>Magento Design, Development &amp; Extensions</strong>.</div>
27
- <div class="creare-footer"><a href="http://www.e-commercewebdesign.co.uk" class="ecom-creare" target="_blank" title="E-Commerce Web Design"><span>E-Commerce Web Design</span></a> <a href="http://www.webdesigncreare.co.uk" class="web-creare" target="_blank" title="Web Design &amp; Development"><span>Web Design &amp; Development</span></a> <a href="http://www.seo-creare.co.uk" class="seo-creare" target="_blank" title="SEO &amp; Internet Marketing"><span>SEO (Search Engine Optimisation)</span></a> <span class="uk-flag"><span>Based In The UK</span></span></div>
28
- </div>
29
- <div class="creare-clear"></div>]]>
30
- </comment>
31
- <fields>
32
- <active translate="label">
33
- <label>Enabled</label>
34
- <frontend_type>select</frontend_type>
35
- <source_model>adminhtml/system_config_source_yesno</source_model>
36
- <sort_order>10</sort_order>
37
- <show_in_default>1</show_in_default>
38
- <show_in_website>1</show_in_website>
39
- <show_in_store>1</show_in_store>
40
- </active>
41
- <twitterid translate="label">
42
- <label>Twitter ID</label>
43
- <frontend_type>text</frontend_type>
44
- <sort_order>20</sort_order>
45
- <show_in_default>1</show_in_default>
46
- <show_in_website>1</show_in_website>
47
- <show_in_store>1</show_in_store>
48
- </twitterid>
49
- <numberoftweets translate="label">
50
- <label>Number of Tweets to show</label>
51
- <frontend_type>select</frontend_type>
52
- <source_model>latesttweet_adminhtml/system_config_source_numbers</source_model>
53
- <sort_order>30</sort_order>
54
- <show_in_default>1</show_in_default>
55
- <show_in_website>1</show_in_website>
56
- <show_in_store>1</show_in_store>
57
- </numberoftweets>
58
- <showlinks translate="label">
59
- <label>Show Links In Tweet</label>
60
- <frontend_type>select</frontend_type>
61
- <source_model>adminhtml/system_config_source_yesno</source_model>
62
- <sort_order>40</sort_order>
63
- <show_in_default>1</show_in_default>
64
- <show_in_website>1</show_in_website>
65
- <show_in_store>1</show_in_store>
66
- </showlinks>
67
- <usenofollow translate="label">
68
- <label>Use Nofollow tag in Links</label>
69
- <frontend_type>select</frontend_type>
70
- <source_model>adminhtml/system_config_source_yesno</source_model>
71
- <sort_order>50</sort_order>
72
- <show_in_default>1</show_in_default>
73
- <show_in_website>1</show_in_website>
74
- <show_in_store>1</show_in_store>
75
- </usenofollow>
76
- <opennew translate="label">
77
- <label>Open In New Window</label>
78
- <frontend_type>select</frontend_type>
79
- <source_model>adminhtml/system_config_source_yesno</source_model>
80
- <sort_order>60</sort_order>
81
- <show_in_default>1</show_in_default>
82
- <show_in_website>1</show_in_website>
83
- <show_in_store>1</show_in_store>
84
- </opennew>
85
- </fields>
86
- </latesttweet>
87
- </groups>
88
- </latesttweet>
89
- </sections>
90
- </config>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <tabs>
3
+ <creare translate="label" module="latesttweet">
4
+ <label>CreareGroup</label>
5
+ <sort_order>100</sort_order>
6
+ </creare>
7
+ </tabs>
8
+ <sections>
9
+ <latesttweet translate="label" module="latesttweet">
10
+ <label>Latest Tweet</label>
11
+ <tab>creare</tab>
12
+ <sort_order>1000</sort_order>
13
+ <show_in_default>1</show_in_default>
14
+ <show_in_website>1</show_in_website>
15
+ <show_in_store>1</show_in_store>
16
+ <groups>
17
+ <howto translate="label" module="latesttweet">
18
+ <label>How to set it up</label>
19
+ <frontend_type>text</frontend_type>
20
+ <sort_order>80</sort_order>
21
+ <show_in_default>1</show_in_default>
22
+ <show_in_website>1</show_in_website>
23
+ <show_in_store>1</show_in_store>
24
+ <comment>
25
+ <![CDATA[
26
+ <p>To aquire your API credentials from Twitter please follow these simple steps:</p>
27
+ <ul>
28
+ <li>1. Navigate to <a href="http://dev.twitter.com" target="_blank">http://dev.twitter.com</a> and login using your normal twitter account username/password</li>
29
+ <li>2. Click on your logo (top right) and then click on My Applications</li>
30
+ <li>3. Create a new application - filling in your website and company details</li>
31
+ <li>4. Go to your application page and click "create my access token"</li>
32
+ <li>5. Copy your consumer key, consumer secret, access token, and access token secret and paste them into your Twitter / oAuth settings below</li>
33
+ </ul>
34
+ ]]>
35
+ </comment>
36
+ </howto>
37
+ <twittersettings translate="label" module="latesttweet">
38
+ <label>Twitter / oAuth Settings</label>
39
+ <frontend_type>text</frontend_type>
40
+ <sort_order>90</sort_order>
41
+ <show_in_default>1</show_in_default>
42
+ <show_in_website>1</show_in_website>
43
+ <show_in_store>1</show_in_store>
44
+ <fields>
45
+ <active translate="label">
46
+ <label>Enabled</label>
47
+ <frontend_type>select</frontend_type>
48
+ <source_model>adminhtml/system_config_source_yesno</source_model>
49
+ <sort_order>10</sort_order>
50
+ <show_in_default>1</show_in_default>
51
+ <show_in_website>1</show_in_website>
52
+ <show_in_store>1</show_in_store>
53
+ </active>
54
+ <twitterid translate="label">
55
+ <label>Twitter ID</label>
56
+ <frontend_type>text</frontend_type>
57
+ <sort_order>20</sort_order>
58
+ <show_in_default>1</show_in_default>
59
+ <show_in_website>1</show_in_website>
60
+ <show_in_store>1</show_in_store>
61
+ </twitterid>
62
+ <consumerkey translate="label">
63
+ <label>Consumer Key</label>
64
+ <frontend_type>text</frontend_type>
65
+ <sort_order>30</sort_order>
66
+ <show_in_default>1</show_in_default>
67
+ <show_in_website>1</show_in_website>
68
+ <show_in_store>1</show_in_store>
69
+ </consumerkey>
70
+ <consumersecret translate="label">
71
+ <label>Consumer Secret</label>
72
+ <frontend_type>text</frontend_type>
73
+ <sort_order>40</sort_order>
74
+ <show_in_default>1</show_in_default>
75
+ <show_in_website>1</show_in_website>
76
+ <show_in_store>1</show_in_store>
77
+ </consumersecret>
78
+ <accesstoken translate="label">
79
+ <label>Access Token</label>
80
+ <frontend_type>text</frontend_type>
81
+ <sort_order>50</sort_order>
82
+ <show_in_default>1</show_in_default>
83
+ <show_in_website>1</show_in_website>
84
+ <show_in_store>1</show_in_store>
85
+ </accesstoken>
86
+ <accesstokensecret translate="label">
87
+ <label>Access Token Secret</label>
88
+ <frontend_type>text</frontend_type>
89
+ <sort_order>60</sort_order>
90
+ <show_in_default>1</show_in_default>
91
+ <show_in_website>1</show_in_website>
92
+ <show_in_store>1</show_in_store>
93
+ </accesstokensecret>
94
+ </fields>
95
+ </twittersettings>
96
+ <displaysettings translate="label" module="latesttweet">
97
+ <label>Display Settings</label>
98
+ <frontend_type>text</frontend_type>
99
+ <sort_order>100</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>1</show_in_website>
102
+ <show_in_store>1</show_in_store>
103
+ <comment>
104
+ <![CDATA[
105
+ <p id="custom_code">If you want to display your latest tweets anywhere in your template files then you can use the following code:<br/>
106
+ <span style="font-family: 'Courier New', Courier, monospace; font-size: 11px;">echo Mage::app()->getLayout()->createBlock('latesttweet/latesttweet')->setTemplate('creare/latesttweet/blank.phtml')->toHtml();</span>
107
+ </p>
108
+ ]]>
109
+ </comment>
110
+ <fields>
111
+ <showleft translate="label">
112
+ <label>Show in left sidebar?</label>
113
+ <frontend_type>select</frontend_type>
114
+ <source_model>adminhtml/system_config_source_yesno</source_model>
115
+ <sort_order>10</sort_order>
116
+ <show_in_default>1</show_in_default>
117
+ <show_in_website>1</show_in_website>
118
+ <show_in_store>1</show_in_store>
119
+ </showleft>
120
+ <showright translate="label">
121
+ <label>Show in right sidebar?</label>
122
+ <frontend_type>select</frontend_type>
123
+ <source_model>adminhtml/system_config_source_yesno</source_model>
124
+ <sort_order>20</sort_order>
125
+ <show_in_default>1</show_in_default>
126
+ <show_in_website>1</show_in_website>
127
+ <show_in_store>1</show_in_store>
128
+ </showright>
129
+ <numberoftweets translate="label">
130
+ <label>Number of tweets to show</label>
131
+ <frontend_type>select</frontend_type>
132
+ <source_model>latesttweet_adminhtml/system_config_source_numbers</source_model>
133
+ <sort_order>30</sort_order>
134
+ <show_in_default>1</show_in_default>
135
+ <show_in_website>1</show_in_website>
136
+ <show_in_store>1</show_in_store>
137
+ </numberoftweets>
138
+ <showlinks translate="label">
139
+ <label>Show links in tweet</label>
140
+ <frontend_type>select</frontend_type>
141
+ <source_model>adminhtml/system_config_source_yesno</source_model>
142
+ <sort_order>40</sort_order>
143
+ <show_in_default>1</show_in_default>
144
+ <show_in_website>1</show_in_website>
145
+ <show_in_store>1</show_in_store>
146
+ </showlinks>
147
+ <usenofollow translate="label">
148
+ <label>Use nofollow tag in links</label>
149
+ <frontend_type>select</frontend_type>
150
+ <source_model>adminhtml/system_config_source_yesno</source_model>
151
+ <sort_order>50</sort_order>
152
+ <show_in_default>1</show_in_default>
153
+ <show_in_website>1</show_in_website>
154
+ <show_in_store>1</show_in_store>
155
+ </usenofollow>
156
+ <opennew translate="label">
157
+ <label>Open links in new window</label>
158
+ <frontend_type>select</frontend_type>
159
+ <source_model>adminhtml/system_config_source_yesno</source_model>
160
+ <sort_order>60</sort_order>
161
+ <show_in_default>1</show_in_default>
162
+ <show_in_website>1</show_in_website>
163
+ <show_in_store>1</show_in_store>
164
+ </opennew>
165
+ <attags translate="label">
166
+ <label>Link up @ tags?</label>
167
+ <frontend_type>select</frontend_type>
168
+ <source_model>adminhtml/system_config_source_yesno</source_model>
169
+ <sort_order>70</sort_order>
170
+ <show_in_default>1</show_in_default>
171
+ <show_in_website>1</show_in_website>
172
+ <show_in_store>1</show_in_store>
173
+ </attags>
174
+ <hashtags translate="label">
175
+ <label>Link up # tags?</label>
176
+ <frontend_type>select</frontend_type>
177
+ <source_model>adminhtml/system_config_source_yesno</source_model>
178
+ <sort_order>80</sort_order>
179
+ <show_in_default>1</show_in_default>
180
+ <show_in_website>1</show_in_website>
181
+ <show_in_store>1</show_in_store>
182
+ </hashtags>
183
+ <showfollow translate="label">
184
+ <label>Show twitter follow button?</label>
185
+ <frontend_type>select</frontend_type>
186
+ <source_model>adminhtml/system_config_source_yesno</source_model>
187
+ <sort_order>90</sort_order>
188
+ <show_in_default>1</show_in_default>
189
+ <show_in_website>1</show_in_website>
190
+ <show_in_store>1</show_in_store>
191
+ </showfollow>
192
+ </fields>
193
+ </displaysettings>
194
+ </groups>
195
+ </latesttweet>
196
+ </sections>
197
+ </config>
app/design/frontend/base/default/layout/creare_latesttweet.xml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <layout version="2.0.1">
3
+ <default>
4
+ <reference name="head">
5
+ <action method="addCss"><stylesheet>css/creare_latesttweet.css</stylesheet></action>
6
+ </reference>
7
+
8
+ <reference name="left">
9
+ <block type="latesttweet/latesttweet" name="left.latesttweet" before="-">
10
+ <action method="setTemplate" ifconfig="latesttweet/displaysettings/showleft">
11
+ <template>creare/latesttweet/tweet.phtml</template>
12
+ </action>
13
+ </block>
14
+ </reference>
15
+
16
+ <reference name="right">
17
+ <block type="latesttweet/latesttweet" name="right.latesttweet" before="-">
18
+ <action method="setTemplate" ifconfig="latesttweet/displaysettings/showright">
19
+ <template>creare/latesttweet/tweet.phtml</template>
20
+ </action>
21
+ </block>
22
+ </reference>
23
+ </default>
24
+ </layout>
app/design/frontend/base/default/template/creare/latesttweet/_notes/dwsync.xml ADDED
@@ -0,0 +1 @@
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
app/design/frontend/base/default/template/creare/latesttweet/blank.phtml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Latest Tweet Extension by E-Commerce Web Design (http://www.e-commercewebdesign.co.uk)
4
+ *
5
+ *
6
+ */
7
+ ?>
8
+ <?php if($this->isEnabled() && $tweets = $this->getLatestTweets()): ?>
9
+ <ul class="creare-twitter">
10
+ <?php foreach($tweets as $tweet): ?>
11
+ <li>
12
+ <?php echo (string) trim($tweet["tweet"]); ?>
13
+ <span> - <?php echo (string) trim($tweet["time"]); ?></span>
14
+ </li>
15
+ <?php endforeach; ?>
16
+ <?php if($this->showFollowButton()): ?>
17
+ <li>
18
+ <a href="https://twitter.com/<?php echo $this->getTwitterId() ?>" class="twitter-follow-button" data-show-count="false">Follow @<?php echo $this->getTwitterId() ?></a>
19
+ <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
20
+ </li>
21
+ <?php endif; ?>
22
+ </ul>
23
+ <?php endif; ?>
app/design/frontend/base/default/template/creare/latesttweet/tweet.phtml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Latest Tweet Extension by E-Commerce Web Design (http://www.e-commercewebdesign.co.uk)
4
+ *
5
+ *
6
+ */
7
+ ?>
8
+ <?php if($this->isEnabled() && $tweets = $this->getLatestTweets()): ?>
9
+ <div class="block block-creare-twitter">
10
+ <div class="block-title">
11
+ <strong>
12
+ <span>Our Latest Tweets</span>
13
+ </strong>
14
+ </div>
15
+ <div class="block-content">
16
+ <ul>
17
+ <?php foreach($tweets as $tweet): ?>
18
+ <li>
19
+ <?php echo (string) trim($tweet["tweet"]); ?>
20
+ <span> - <?php echo (string) trim($tweet["time"]); ?></span>
21
+ </li>
22
+ <?php endforeach; ?>
23
+ <?php if($this->showFollowButton()): ?>
24
+ <li>
25
+ <a href="https://twitter.com/<?php echo $this->getTwitterId() ?>" class="twitter-follow-button" data-show-count="false">Follow @<?php echo $this->getTwitterId() ?></a>
26
+ <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
27
+ </li>
28
+ <?php endif; ?>
29
+ </ul>
30
+ </div>
31
+ </div>
32
+
33
+
34
+
35
+ <?php endif; ?>
app/design/frontend/default/default/layout/latesttweet.xml DELETED
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <layout version="0.1.0">
3
- <default>
4
- <reference name="head">
5
- <action method="addCss"><stylesheet>css/latesttweet.css</stylesheet></action>
6
- </reference>
7
-
8
- <reference name="right">
9
- <block type="latesttweet/latesttweet" name="latesttweet" before="-" template="latesttweet/tweet.phtml" />
10
- </reference>
11
- </default>
12
- </layout>
 
 
 
 
 
 
 
 
 
 
 
 
app/design/frontend/default/default/template/latesttweet/tweet.phtml DELETED
@@ -1,26 +0,0 @@
1
- <?php
2
- /*
3
- * Latest Tweet Extension by E-Commerce Web Design (http://www.e-commercewebdesign.co.uk)
4
- *
5
- *
6
- */
7
- ?>
8
- <?php if($this->isEnabled() && $tweets = $this->getLatestTweets()): ?>
9
- <div class="block">
10
- <div class="block-title creare-tweet-bg">
11
- <strong>
12
- <span class="creare-tweet-title">Latest Tweet</span>
13
- </strong>
14
- </div>
15
- <div class="block-content">
16
- <ul class="creare-tweet">
17
- <?php foreach($tweets as $tweet): ?>
18
- <li>
19
- <?php echo $tweet["tweet"]; ?>
20
- <span><?php echo $tweet["time"]; ?></span>
21
- </li>
22
- <?php endforeach; ?>
23
- </ul>
24
- </div>
25
- </div>
26
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/etc/modules/Creare_Latesttweet.xml CHANGED
@@ -1,8 +1,10 @@
1
- <config>
2
- <modules>
3
- <Creare_Latesttweet>
4
- <active>true</active>
5
- <codePool>local</codePool>
6
- </Creare_Latesttweet>
7
- </modules>
 
 
8
  </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Creare_Latesttweet>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ <version>2.0.1</version>
8
+ </Creare_Latesttweet>
9
+ </modules>
10
  </config>
lib/twitteroauth/OAuth.php ADDED
@@ -0,0 +1,874 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // vim: foldmethod=marker
3
+
4
+ /* Generic exception class
5
+ */
6
+ if (!class_exists('OAuthException')) {
7
+ class OAuthException extends Exception {
8
+ // pass
9
+ }
10
+ }
11
+
12
+ class OAuthConsumer {
13
+ public $key;
14
+ public $secret;
15
+
16
+ function __construct($key, $secret, $callback_url=NULL) {
17
+ $this->key = $key;
18
+ $this->secret = $secret;
19
+ $this->callback_url = $callback_url;
20
+ }
21
+
22
+ function __toString() {
23
+ return "OAuthConsumer[key=$this->key,secret=$this->secret]";
24
+ }
25
+ }
26
+
27
+ class OAuthToken {
28
+ // access tokens and request tokens
29
+ public $key;
30
+ public $secret;
31
+
32
+ /**
33
+ * key = the token
34
+ * secret = the token secret
35
+ */
36
+ function __construct($key, $secret) {
37
+ $this->key = $key;
38
+ $this->secret = $secret;
39
+ }
40
+
41
+ /**
42
+ * generates the basic string serialization of a token that a server
43
+ * would respond to request_token and access_token calls with
44
+ */
45
+ function to_string() {
46
+ return "oauth_token=" .
47
+ OAuthUtil::urlencode_rfc3986($this->key) .
48
+ "&oauth_token_secret=" .
49
+ OAuthUtil::urlencode_rfc3986($this->secret);
50
+ }
51
+
52
+ function __toString() {
53
+ return $this->to_string();
54
+ }
55
+ }
56
+
57
+ /**
58
+ * A class for implementing a Signature Method
59
+ * See section 9 ("Signing Requests") in the spec
60
+ */
61
+ abstract class OAuthSignatureMethod {
62
+ /**
63
+ * Needs to return the name of the Signature Method (ie HMAC-SHA1)
64
+ * @return string
65
+ */
66
+ abstract public function get_name();
67
+
68
+ /**
69
+ * Build up the signature
70
+ * NOTE: The output of this function MUST NOT be urlencoded.
71
+ * the encoding is handled in OAuthRequest when the final
72
+ * request is serialized
73
+ * @param OAuthRequest $request
74
+ * @param OAuthConsumer $consumer
75
+ * @param OAuthToken $token
76
+ * @return string
77
+ */
78
+ abstract public function build_signature($request, $consumer, $token);
79
+
80
+ /**
81
+ * Verifies that a given signature is correct
82
+ * @param OAuthRequest $request
83
+ * @param OAuthConsumer $consumer
84
+ * @param OAuthToken $token
85
+ * @param string $signature
86
+ * @return bool
87
+ */
88
+ public function check_signature($request, $consumer, $token, $signature) {
89
+ $built = $this->build_signature($request, $consumer, $token);
90
+ return $built == $signature;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
96
+ * where the Signature Base String is the text and the key is the concatenated values (each first
97
+ * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
98
+ * character (ASCII code 38) even if empty.
99
+ * - Chapter 9.2 ("HMAC-SHA1")
100
+ */
101
+ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
102
+ function get_name() {
103
+ return "HMAC-SHA1";
104
+ }
105
+
106
+ public function build_signature($request, $consumer, $token) {
107
+ $base_string = $request->get_signature_base_string();
108
+ $request->base_string = $base_string;
109
+
110
+ $key_parts = array(
111
+ $consumer->secret,
112
+ ($token) ? $token->secret : ""
113
+ );
114
+
115
+ $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
116
+ $key = implode('&', $key_parts);
117
+
118
+ return base64_encode(hash_hmac('sha1', $base_string, $key, true));
119
+ }
120
+ }
121
+
122
+ /**
123
+ * The PLAINTEXT method does not provide any security protection and SHOULD only be used
124
+ * over a secure channel such as HTTPS. It does not use the Signature Base String.
125
+ * - Chapter 9.4 ("PLAINTEXT")
126
+ */
127
+ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
128
+ public function get_name() {
129
+ return "PLAINTEXT";
130
+ }
131
+
132
+ /**
133
+ * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
134
+ * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
135
+ * empty. The result MUST be encoded again.
136
+ * - Chapter 9.4.1 ("Generating Signatures")
137
+ *
138
+ * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
139
+ * OAuthRequest handles this!
140
+ */
141
+ public function build_signature($request, $consumer, $token) {
142
+ $key_parts = array(
143
+ $consumer->secret,
144
+ ($token) ? $token->secret : ""
145
+ );
146
+
147
+ $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
148
+ $key = implode('&', $key_parts);
149
+ $request->base_string = $key;
150
+
151
+ return $key;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
157
+ * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
158
+ * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
159
+ * verified way to the Service Provider, in a manner which is beyond the scope of this
160
+ * specification.
161
+ * - Chapter 9.3 ("RSA-SHA1")
162
+ */
163
+ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
164
+ public function get_name() {
165
+ return "RSA-SHA1";
166
+ }
167
+
168
+ // Up to the SP to implement this lookup of keys. Possible ideas are:
169
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
170
+ // (2) fetch via http using a url provided by the requester
171
+ // (3) some sort of specific discovery code based on request
172
+ //
173
+ // Either way should return a string representation of the certificate
174
+ protected abstract function fetch_public_cert(&$request);
175
+
176
+ // Up to the SP to implement this lookup of keys. Possible ideas are:
177
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
178
+ //
179
+ // Either way should return a string representation of the certificate
180
+ protected abstract function fetch_private_cert(&$request);
181
+
182
+ public function build_signature($request, $consumer, $token) {
183
+ $base_string = $request->get_signature_base_string();
184
+ $request->base_string = $base_string;
185
+
186
+ // Fetch the private key cert based on the request
187
+ $cert = $this->fetch_private_cert($request);
188
+
189
+ // Pull the private key ID from the certificate
190
+ $privatekeyid = openssl_get_privatekey($cert);
191
+
192
+ // Sign using the key
193
+ $ok = openssl_sign($base_string, $signature, $privatekeyid);
194
+
195
+ // Release the key resource
196
+ openssl_free_key($privatekeyid);
197
+
198
+ return base64_encode($signature);
199
+ }
200
+
201
+ public function check_signature($request, $consumer, $token, $signature) {
202
+ $decoded_sig = base64_decode($signature);
203
+
204
+ $base_string = $request->get_signature_base_string();
205
+
206
+ // Fetch the public key cert based on the request
207
+ $cert = $this->fetch_public_cert($request);
208
+
209
+ // Pull the public key ID from the certificate
210
+ $publickeyid = openssl_get_publickey($cert);
211
+
212
+ // Check the computed signature against the one passed in the query
213
+ $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
214
+
215
+ // Release the key resource
216
+ openssl_free_key($publickeyid);
217
+
218
+ return $ok == 1;
219
+ }
220
+ }
221
+
222
+ class OAuthRequest {
223
+ private $parameters;
224
+ private $http_method;
225
+ private $http_url;
226
+ // for debug purposes
227
+ public $base_string;
228
+ public static $version = '1.0';
229
+ public static $POST_INPUT = 'php://input';
230
+
231
+ function __construct($http_method, $http_url, $parameters=NULL) {
232
+ @$parameters or $parameters = array();
233
+ $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
234
+ $this->parameters = $parameters;
235
+ $this->http_method = $http_method;
236
+ $this->http_url = $http_url;
237
+ }
238
+
239
+
240
+ /**
241
+ * attempt to build up a request from what was passed to the server
242
+ */
243
+ public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
244
+ $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
245
+ ? 'http'
246
+ : 'https';
247
+ @$http_url or $http_url = $scheme .
248
+ '://' . $_SERVER['HTTP_HOST'] .
249
+ ':' .
250
+ $_SERVER['SERVER_PORT'] .
251
+ $_SERVER['REQUEST_URI'];
252
+ @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
253
+
254
+ // We weren't handed any parameters, so let's find the ones relevant to
255
+ // this request.
256
+ // If you run XML-RPC or similar you should use this to provide your own
257
+ // parsed parameter-list
258
+ if (!$parameters) {
259
+ // Find request headers
260
+ $request_headers = OAuthUtil::get_headers();
261
+
262
+ // Parse the query-string to find GET parameters
263
+ $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
264
+
265
+ // It's a POST request of the proper content-type, so parse POST
266
+ // parameters and add those overriding any duplicates from GET
267
+ if ($http_method == "POST"
268
+ && @strstr($request_headers["Content-Type"],
269
+ "application/x-www-form-urlencoded")
270
+ ) {
271
+ $post_data = OAuthUtil::parse_parameters(
272
+ file_get_contents(self::$POST_INPUT)
273
+ );
274
+ $parameters = array_merge($parameters, $post_data);
275
+ }
276
+
277
+ // We have a Authorization-header with OAuth data. Parse the header
278
+ // and add those overriding any duplicates from GET or POST
279
+ if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
280
+ $header_parameters = OAuthUtil::split_header(
281
+ $request_headers['Authorization']
282
+ );
283
+ $parameters = array_merge($parameters, $header_parameters);
284
+ }
285
+
286
+ }
287
+
288
+ return new OAuthRequest($http_method, $http_url, $parameters);
289
+ }
290
+
291
+ /**
292
+ * pretty much a helper function to set up the request
293
+ */
294
+ public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
295
+ @$parameters or $parameters = array();
296
+ $defaults = array("oauth_version" => OAuthRequest::$version,
297
+ "oauth_nonce" => OAuthRequest::generate_nonce(),
298
+ "oauth_timestamp" => OAuthRequest::generate_timestamp(),
299
+ "oauth_consumer_key" => $consumer->key);
300
+ if ($token)
301
+ $defaults['oauth_token'] = $token->key;
302
+
303
+ $parameters = array_merge($defaults, $parameters);
304
+
305
+ return new OAuthRequest($http_method, $http_url, $parameters);
306
+ }
307
+
308
+ public function set_parameter($name, $value, $allow_duplicates = true) {
309
+ if ($allow_duplicates && isset($this->parameters[$name])) {
310
+ // We have already added parameter(s) with this name, so add to the list
311
+ if (is_scalar($this->parameters[$name])) {
312
+ // This is the first duplicate, so transform scalar (string)
313
+ // into an array so we can add the duplicates
314
+ $this->parameters[$name] = array($this->parameters[$name]);
315
+ }
316
+
317
+ $this->parameters[$name][] = $value;
318
+ } else {
319
+ $this->parameters[$name] = $value;
320
+ }
321
+ }
322
+
323
+ public function get_parameter($name) {
324
+ return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
325
+ }
326
+
327
+ public function get_parameters() {
328
+ return $this->parameters;
329
+ }
330
+
331
+ public function unset_parameter($name) {
332
+ unset($this->parameters[$name]);
333
+ }
334
+
335
+ /**
336
+ * The request parameters, sorted and concatenated into a normalized string.
337
+ * @return string
338
+ */
339
+ public function get_signable_parameters() {
340
+ // Grab all parameters
341
+ $params = $this->parameters;
342
+
343
+ // Remove oauth_signature if present
344
+ // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
345
+ if (isset($params['oauth_signature'])) {
346
+ unset($params['oauth_signature']);
347
+ }
348
+
349
+ return OAuthUtil::build_http_query($params);
350
+ }
351
+
352
+ /**
353
+ * Returns the base string of this request
354
+ *
355
+ * The base string defined as the method, the url
356
+ * and the parameters (normalized), each urlencoded
357
+ * and the concated with &.
358
+ */
359
+ public function get_signature_base_string() {
360
+ $parts = array(
361
+ $this->get_normalized_http_method(),
362
+ $this->get_normalized_http_url(),
363
+ $this->get_signable_parameters()
364
+ );
365
+
366
+ $parts = OAuthUtil::urlencode_rfc3986($parts);
367
+
368
+ return implode('&', $parts);
369
+ }
370
+
371
+ /**
372
+ * just uppercases the http method
373
+ */
374
+ public function get_normalized_http_method() {
375
+ return strtoupper($this->http_method);
376
+ }
377
+
378
+ /**
379
+ * parses the url and rebuilds it to be
380
+ * scheme://host/path
381
+ */
382
+ public function get_normalized_http_url() {
383
+ $parts = parse_url($this->http_url);
384
+
385
+ $port = @$parts['port'];
386
+ $scheme = $parts['scheme'];
387
+ $host = $parts['host'];
388
+ $path = @$parts['path'];
389
+
390
+ $port or $port = ($scheme == 'https') ? '443' : '80';
391
+
392
+ if (($scheme == 'https' && $port != '443')
393
+ || ($scheme == 'http' && $port != '80')) {
394
+ $host = "$host:$port";
395
+ }
396
+ return "$scheme://$host$path";
397
+ }
398
+
399
+ /**
400
+ * builds a url usable for a GET request
401
+ */
402
+ public function to_url() {
403
+ $post_data = $this->to_postdata();
404
+ $out = $this->get_normalized_http_url();
405
+ if ($post_data) {
406
+ $out .= '?'.$post_data;
407
+ }
408
+ return $out;
409
+ }
410
+
411
+ /**
412
+ * builds the data one would send in a POST request
413
+ */
414
+ public function to_postdata() {
415
+ return OAuthUtil::build_http_query($this->parameters);
416
+ }
417
+
418
+ /**
419
+ * builds the Authorization: header
420
+ */
421
+ public function to_header($realm=null) {
422
+ $first = true;
423
+ if($realm) {
424
+ $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
425
+ $first = false;
426
+ } else
427
+ $out = 'Authorization: OAuth';
428
+
429
+ $total = array();
430
+ foreach ($this->parameters as $k => $v) {
431
+ if (substr($k, 0, 5) != "oauth") continue;
432
+ if (is_array($v)) {
433
+ throw new OAuthException('Arrays not supported in headers');
434
+ }
435
+ $out .= ($first) ? ' ' : ',';
436
+ $out .= OAuthUtil::urlencode_rfc3986($k) .
437
+ '="' .
438
+ OAuthUtil::urlencode_rfc3986($v) .
439
+ '"';
440
+ $first = false;
441
+ }
442
+ return $out;
443
+ }
444
+
445
+ public function __toString() {
446
+ return $this->to_url();
447
+ }
448
+
449
+
450
+ public function sign_request($signature_method, $consumer, $token) {
451
+ $this->set_parameter(
452
+ "oauth_signature_method",
453
+ $signature_method->get_name(),
454
+ false
455
+ );
456
+ $signature = $this->build_signature($signature_method, $consumer, $token);
457
+ $this->set_parameter("oauth_signature", $signature, false);
458
+ }
459
+
460
+ public function build_signature($signature_method, $consumer, $token) {
461
+ $signature = $signature_method->build_signature($this, $consumer, $token);
462
+ return $signature;
463
+ }
464
+
465
+ /**
466
+ * util function: current timestamp
467
+ */
468
+ private static function generate_timestamp() {
469
+ return time();
470
+ }
471
+
472
+ /**
473
+ * util function: current nonce
474
+ */
475
+ private static function generate_nonce() {
476
+ $mt = microtime();
477
+ $rand = mt_rand();
478
+
479
+ return md5($mt . $rand); // md5s look nicer than numbers
480
+ }
481
+ }
482
+
483
+ class OAuthServer {
484
+ protected $timestamp_threshold = 300; // in seconds, five minutes
485
+ protected $version = '1.0'; // hi blaine
486
+ protected $signature_methods = array();
487
+
488
+ protected $data_store;
489
+
490
+ function __construct($data_store) {
491
+ $this->data_store = $data_store;
492
+ }
493
+
494
+ public function add_signature_method($signature_method) {
495
+ $this->signature_methods[$signature_method->get_name()] =
496
+ $signature_method;
497
+ }
498
+
499
+ // high level functions
500
+
501
+ /**
502
+ * process a request_token request
503
+ * returns the request token on success
504
+ */
505
+ public function fetch_request_token(&$request) {
506
+ $this->get_version($request);
507
+
508
+ $consumer = $this->get_consumer($request);
509
+
510
+ // no token required for the initial token request
511
+ $token = NULL;
512
+
513
+ $this->check_signature($request, $consumer, $token);
514
+
515
+ // Rev A change
516
+ $callback = $request->get_parameter('oauth_callback');
517
+ $new_token = $this->data_store->new_request_token($consumer, $callback);
518
+
519
+ return $new_token;
520
+ }
521
+
522
+ /**
523
+ * process an access_token request
524
+ * returns the access token on success
525
+ */
526
+ public function fetch_access_token(&$request) {
527
+ $this->get_version($request);
528
+
529
+ $consumer = $this->get_consumer($request);
530
+
531
+ // requires authorized request token
532
+ $token = $this->get_token($request, $consumer, "request");
533
+
534
+ $this->check_signature($request, $consumer, $token);
535
+
536
+ // Rev A change
537
+ $verifier = $request->get_parameter('oauth_verifier');
538
+ $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
539
+
540
+ return $new_token;
541
+ }
542
+
543
+ /**
544
+ * verify an api call, checks all the parameters
545
+ */
546
+ public function verify_request(&$request) {
547
+ $this->get_version($request);
548
+ $consumer = $this->get_consumer($request);
549
+ $token = $this->get_token($request, $consumer, "access");
550
+ $this->check_signature($request, $consumer, $token);
551
+ return array($consumer, $token);
552
+ }
553
+
554
+ // Internals from here
555
+ /**
556
+ * version 1
557
+ */
558
+ private function get_version(&$request) {
559
+ $version = $request->get_parameter("oauth_version");
560
+ if (!$version) {
561
+ // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
562
+ // Chapter 7.0 ("Accessing Protected Ressources")
563
+ $version = '1.0';
564
+ }
565
+ if ($version !== $this->version) {
566
+ throw new OAuthException("OAuth version '$version' not supported");
567
+ }
568
+ return $version;
569
+ }
570
+
571
+ /**
572
+ * figure out the signature with some defaults
573
+ */
574
+ private function get_signature_method(&$request) {
575
+ $signature_method =
576
+ @$request->get_parameter("oauth_signature_method");
577
+
578
+ if (!$signature_method) {
579
+ // According to chapter 7 ("Accessing Protected Ressources") the signature-method
580
+ // parameter is required, and we can't just fallback to PLAINTEXT
581
+ throw new OAuthException('No signature method parameter. This parameter is required');
582
+ }
583
+
584
+ if (!in_array($signature_method,
585
+ array_keys($this->signature_methods))) {
586
+ throw new OAuthException(
587
+ "Signature method '$signature_method' not supported " .
588
+ "try one of the following: " .
589
+ implode(", ", array_keys($this->signature_methods))
590
+ );
591
+ }
592
+ return $this->signature_methods[$signature_method];
593
+ }
594
+
595
+ /**
596
+ * try to find the consumer for the provided request's consumer key
597
+ */
598
+ private function get_consumer(&$request) {
599
+ $consumer_key = @$request->get_parameter("oauth_consumer_key");
600
+ if (!$consumer_key) {
601
+ throw new OAuthException("Invalid consumer key");
602
+ }
603
+
604
+ $consumer = $this->data_store->lookup_consumer($consumer_key);
605
+ if (!$consumer) {
606
+ throw new OAuthException("Invalid consumer");
607
+ }
608
+
609
+ return $consumer;
610
+ }
611
+
612
+ /**
613
+ * try to find the token for the provided request's token key
614
+ */
615
+ private function get_token(&$request, $consumer, $token_type="access") {
616
+ $token_field = @$request->get_parameter('oauth_token');
617
+ $token = $this->data_store->lookup_token(
618
+ $consumer, $token_type, $token_field
619
+ );
620
+ if (!$token) {
621
+ throw new OAuthException("Invalid $token_type token: $token_field");
622
+ }
623
+ return $token;
624
+ }
625
+
626
+ /**
627
+ * all-in-one function to check the signature on a request
628
+ * should guess the signature method appropriately
629
+ */
630
+ private function check_signature(&$request, $consumer, $token) {
631
+ // this should probably be in a different method
632
+ $timestamp = @$request->get_parameter('oauth_timestamp');
633
+ $nonce = @$request->get_parameter('oauth_nonce');
634
+
635
+ $this->check_timestamp($timestamp);
636
+ $this->check_nonce($consumer, $token, $nonce, $timestamp);
637
+
638
+ $signature_method = $this->get_signature_method($request);
639
+
640
+ $signature = $request->get_parameter('oauth_signature');
641
+ $valid_sig = $signature_method->check_signature(
642
+ $request,
643
+ $consumer,
644
+ $token,
645
+ $signature
646
+ );
647
+
648
+ if (!$valid_sig) {
649
+ throw new OAuthException("Invalid signature");
650
+ }
651
+ }
652
+
653
+ /**
654
+ * check that the timestamp is new enough
655
+ */
656
+ private function check_timestamp($timestamp) {
657
+ if( ! $timestamp )
658
+ throw new OAuthException(
659
+ 'Missing timestamp parameter. The parameter is required'
660
+ );
661
+
662
+ // verify that timestamp is recentish
663
+ $now = time();
664
+ if (abs($now - $timestamp) > $this->timestamp_threshold) {
665
+ throw new OAuthException(
666
+ "Expired timestamp, yours $timestamp, ours $now"
667
+ );
668
+ }
669
+ }
670
+
671
+ /**
672
+ * check that the nonce is not repeated
673
+ */
674
+ private function check_nonce($consumer, $token, $nonce, $timestamp) {
675
+ if( ! $nonce )
676
+ throw new OAuthException(
677
+ 'Missing nonce parameter. The parameter is required'
678
+ );
679
+
680
+ // verify that the nonce is uniqueish
681
+ $found = $this->data_store->lookup_nonce(
682
+ $consumer,
683
+ $token,
684
+ $nonce,
685
+ $timestamp
686
+ );
687
+ if ($found) {
688
+ throw new OAuthException("Nonce already used: $nonce");
689
+ }
690
+ }
691
+
692
+ }
693
+
694
+ class OAuthDataStore {
695
+ function lookup_consumer($consumer_key) {
696
+ // implement me
697
+ }
698
+
699
+ function lookup_token($consumer, $token_type, $token) {
700
+ // implement me
701
+ }
702
+
703
+ function lookup_nonce($consumer, $token, $nonce, $timestamp) {
704
+ // implement me
705
+ }
706
+
707
+ function new_request_token($consumer, $callback = null) {
708
+ // return a new token attached to this consumer
709
+ }
710
+
711
+ function new_access_token($token, $consumer, $verifier = null) {
712
+ // return a new access token attached to this consumer
713
+ // for the user associated with this token if the request token
714
+ // is authorized
715
+ // should also invalidate the request token
716
+ }
717
+
718
+ }
719
+
720
+ class OAuthUtil {
721
+ public static function urlencode_rfc3986($input) {
722
+ if (is_array($input)) {
723
+ return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
724
+ } else if (is_scalar($input)) {
725
+ return str_replace(
726
+ '+',
727
+ ' ',
728
+ str_replace('%7E', '~', rawurlencode($input))
729
+ );
730
+ } else {
731
+ return '';
732
+ }
733
+ }
734
+
735
+
736
+ // This decode function isn't taking into consideration the above
737
+ // modifications to the encoding process. However, this method doesn't
738
+ // seem to be used anywhere so leaving it as is.
739
+ public static function urldecode_rfc3986($string) {
740
+ return urldecode($string);
741
+ }
742
+
743
+ // Utility function for turning the Authorization: header into
744
+ // parameters, has to do some unescaping
745
+ // Can filter out any non-oauth parameters if needed (default behaviour)
746
+ public static function split_header($header, $only_allow_oauth_parameters = true) {
747
+ $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
748
+ $offset = 0;
749
+ $params = array();
750
+ while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
751
+ $match = $matches[0];
752
+ $header_name = $matches[2][0];
753
+ $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
754
+ if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
755
+ $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
756
+ }
757
+ $offset = $match[1] + strlen($match[0]);
758
+ }
759
+
760
+ if (isset($params['realm'])) {
761
+ unset($params['realm']);
762
+ }
763
+
764
+ return $params;
765
+ }
766
+
767
+ // helper to try to sort out headers for people who aren't running apache
768
+ public static function get_headers() {
769
+ if (function_exists('apache_request_headers')) {
770
+ // we need this to get the actual Authorization: header
771
+ // because apache tends to tell us it doesn't exist
772
+ $headers = apache_request_headers();
773
+
774
+ // sanitize the output of apache_request_headers because
775
+ // we always want the keys to be Cased-Like-This and arh()
776
+ // returns the headers in the same case as they are in the
777
+ // request
778
+ $out = array();
779
+ foreach( $headers AS $key => $value ) {
780
+ $key = str_replace(
781
+ " ",
782
+ "-",
783
+ ucwords(strtolower(str_replace("-", " ", $key)))
784
+ );
785
+ $out[$key] = $value;
786
+ }
787
+ } else {
788
+ // otherwise we don't have apache and are just going to have to hope
789
+ // that $_SERVER actually contains what we need
790
+ $out = array();
791
+ if( isset($_SERVER['CONTENT_TYPE']) )
792
+ $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
793
+ if( isset($_ENV['CONTENT_TYPE']) )
794
+ $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
795
+
796
+ foreach ($_SERVER as $key => $value) {
797
+ if (substr($key, 0, 5) == "HTTP_") {
798
+ // this is chaos, basically it is just there to capitalize the first
799
+ // letter of every word that is not an initial HTTP and strip HTTP
800
+ // code from przemek
801
+ $key = str_replace(
802
+ " ",
803
+ "-",
804
+ ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
805
+ );
806
+ $out[$key] = $value;
807
+ }
808
+ }
809
+ }
810
+ return $out;
811
+ }
812
+
813
+ // This function takes a input like a=b&a=c&d=e and returns the parsed
814
+ // parameters like this
815
+ // array('a' => array('b','c'), 'd' => 'e')
816
+ public static function parse_parameters( $input ) {
817
+ if (!isset($input) || !$input) return array();
818
+
819
+ $pairs = explode('&', $input);
820
+
821
+ $parsed_parameters = array();
822
+ foreach ($pairs as $pair) {
823
+ $split = explode('=', $pair, 2);
824
+ $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
825
+ $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
826
+
827
+ if (isset($parsed_parameters[$parameter])) {
828
+ // We have already recieved parameter(s) with this name, so add to the list
829
+ // of parameters with this name
830
+
831
+ if (is_scalar($parsed_parameters[$parameter])) {
832
+ // This is the first duplicate, so transform scalar (string) into an array
833
+ // so we can add the duplicates
834
+ $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
835
+ }
836
+
837
+ $parsed_parameters[$parameter][] = $value;
838
+ } else {
839
+ $parsed_parameters[$parameter] = $value;
840
+ }
841
+ }
842
+ return $parsed_parameters;
843
+ }
844
+
845
+ public static function build_http_query($params) {
846
+ if (!$params) return '';
847
+
848
+ // Urlencode both keys and values
849
+ $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
850
+ $values = OAuthUtil::urlencode_rfc3986(array_values($params));
851
+ $params = array_combine($keys, $values);
852
+
853
+ // Parameters are sorted by name, using lexicographical byte value ordering.
854
+ // Ref: Spec: 9.1.1 (1)
855
+ uksort($params, 'strcmp');
856
+
857
+ $pairs = array();
858
+ foreach ($params as $parameter => $value) {
859
+ if (is_array($value)) {
860
+ // If two or more parameters share the same name, they are sorted by their value
861
+ // Ref: Spec: 9.1.1 (1)
862
+ natsort($value);
863
+ foreach ($value as $duplicate_value) {
864
+ $pairs[] = $parameter . '=' . $duplicate_value;
865
+ }
866
+ } else {
867
+ $pairs[] = $parameter . '=' . $value;
868
+ }
869
+ }
870
+ // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
871
+ // Each name-value pair is separated by an '&' character (ASCII code 38)
872
+ return implode('&', $pairs);
873
+ }
874
+ }
lib/twitteroauth/_notes/dwsync.xml ADDED
@@ -0,0 +1 @@
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
lib/twitteroauth/twitteroauth.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Abraham Williams (abraham@abrah.am) http://abrah.am
5
+ *
6
+ * The first PHP Library to support OAuth for Twitter's REST API.
7
+ */
8
+
9
+ /* Load OAuth lib. You can find it at http://oauth.net */
10
+ require_once('OAuth.php');
11
+
12
+ /**
13
+ * Twitter OAuth class
14
+ */
15
+ class TwitterOAuth {
16
+ /* Contains the last HTTP status code returned. */
17
+ public $http_code;
18
+ /* Contains the last API call. */
19
+ public $url;
20
+ /* Set up the API root URL. */
21
+ public $host = "https://api.twitter.com/1.1/";
22
+ /* Set timeout default. */
23
+ public $timeout = 30;
24
+ /* Set connect timeout. */
25
+ public $connecttimeout = 30;
26
+ /* Verify SSL Cert. */
27
+ public $ssl_verifypeer = FALSE;
28
+ /* Respons format. */
29
+ public $format = 'json';
30
+ /* Decode returned json data. */
31
+ public $decode_json = TRUE;
32
+ /* Contains the last HTTP headers returned. */
33
+ public $http_info;
34
+ /* Set the useragnet. */
35
+ public $useragent = 'TwitterOAuth v0.2.0-beta2';
36
+ /* Immediately retry the API call if the response was not successful. */
37
+ //public $retry = TRUE;
38
+
39
+
40
+
41
+
42
+ /**
43
+ * Set API URLS
44
+ */
45
+ function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; }
46
+ function authenticateURL() { return 'https://api.twitter.com/oauth/authenticate'; }
47
+ function authorizeURL() { return 'https://api.twitter.com/oauth/authorize'; }
48
+ function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
49
+
50
+ /**
51
+ * Debug helpers
52
+ */
53
+ function lastStatusCode() { return $this->http_status; }
54
+ function lastAPICall() { return $this->last_api_call; }
55
+
56
+ /**
57
+ * construct TwitterOAuth object
58
+ */
59
+ function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
60
+ $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
61
+ $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
62
+ if (!empty($oauth_token) && !empty($oauth_token_secret)) {
63
+ $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
64
+ } else {
65
+ $this->token = NULL;
66
+ }
67
+ }
68
+
69
+
70
+ /**
71
+ * Get a request_token from Twitter
72
+ *
73
+ * @returns a key/value array containing oauth_token and oauth_token_secret
74
+ */
75
+ function getRequestToken($oauth_callback) {
76
+ $parameters = array();
77
+ $parameters['oauth_callback'] = $oauth_callback;
78
+ $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
79
+ $token = OAuthUtil::parse_parameters($request);
80
+ $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
81
+ return $token;
82
+ }
83
+
84
+ /**
85
+ * Get the authorize URL
86
+ *
87
+ * @returns a string
88
+ */
89
+ function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) {
90
+ if (is_array($token)) {
91
+ $token = $token['oauth_token'];
92
+ }
93
+ if (empty($sign_in_with_twitter)) {
94
+ return $this->authorizeURL() . "?oauth_token={$token}";
95
+ } else {
96
+ return $this->authenticateURL() . "?oauth_token={$token}";
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Exchange request token and secret for an access token and
102
+ * secret, to sign API calls.
103
+ *
104
+ * @returns array("oauth_token" => "the-access-token",
105
+ * "oauth_token_secret" => "the-access-secret",
106
+ * "user_id" => "9436992",
107
+ * "screen_name" => "abraham")
108
+ */
109
+ function getAccessToken($oauth_verifier) {
110
+ $parameters = array();
111
+ $parameters['oauth_verifier'] = $oauth_verifier;
112
+ $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
113
+ $token = OAuthUtil::parse_parameters($request);
114
+ $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
115
+ return $token;
116
+ }
117
+
118
+ /**
119
+ * One time exchange of username and password for access token and secret.
120
+ *
121
+ * @returns array("oauth_token" => "the-access-token",
122
+ * "oauth_token_secret" => "the-access-secret",
123
+ * "user_id" => "9436992",
124
+ * "screen_name" => "abraham",
125
+ * "x_auth_expires" => "0")
126
+ */
127
+ function getXAuthToken($username, $password) {
128
+ $parameters = array();
129
+ $parameters['x_auth_username'] = $username;
130
+ $parameters['x_auth_password'] = $password;
131
+ $parameters['x_auth_mode'] = 'client_auth';
132
+ $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
133
+ $token = OAuthUtil::parse_parameters($request);
134
+ $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
135
+ return $token;
136
+ }
137
+
138
+ /**
139
+ * GET wrapper for oAuthRequest.
140
+ */
141
+ function get($url, $parameters = array()) {
142
+ $response = $this->oAuthRequest($url, 'GET', $parameters);
143
+ if ($this->format === 'json' && $this->decode_json) {
144
+ return json_decode($response);
145
+ }
146
+ return $response;
147
+ }
148
+
149
+ /**
150
+ * POST wrapper for oAuthRequest.
151
+ */
152
+ function post($url, $parameters = array()) {
153
+ $response = $this->oAuthRequest($url, 'POST', $parameters);
154
+ if ($this->format === 'json' && $this->decode_json) {
155
+ return json_decode($response);
156
+ }
157
+ return $response;
158
+ }
159
+
160
+ /**
161
+ * DELETE wrapper for oAuthReqeust.
162
+ */
163
+ function delete($url, $parameters = array()) {
164
+ $response = $this->oAuthRequest($url, 'DELETE', $parameters);
165
+ if ($this->format === 'json' && $this->decode_json) {
166
+ return json_decode($response);
167
+ }
168
+ return $response;
169
+ }
170
+
171
+ /**
172
+ * Format and sign an OAuth / API request
173
+ */
174
+ function oAuthRequest($url, $method, $parameters) {
175
+ if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
176
+ $url = "{$this->host}{$url}.{$this->format}";
177
+ }
178
+ $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
179
+ $request->sign_request($this->sha1_method, $this->consumer, $this->token);
180
+ switch ($method) {
181
+ case 'GET':
182
+ return $this->http($request->to_url(), 'GET');
183
+ default:
184
+ return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Make an HTTP request
190
+ *
191
+ * @return API results
192
+ */
193
+ function http($url, $method, $postfields = NULL) {
194
+ $this->http_info = array();
195
+ $ci = curl_init();
196
+ /* Curl settings */
197
+ curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
198
+ curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
199
+ curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
200
+ curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
201
+ curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
202
+ curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
203
+ curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
204
+ curl_setopt($ci, CURLOPT_HEADER, FALSE);
205
+
206
+ switch ($method) {
207
+ case 'POST':
208
+ curl_setopt($ci, CURLOPT_POST, TRUE);
209
+ if (!empty($postfields)) {
210
+ curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
211
+ }
212
+ break;
213
+ case 'DELETE':
214
+ curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
215
+ if (!empty($postfields)) {
216
+ $url = "{$url}?{$postfields}";
217
+ }
218
+ }
219
+
220
+ curl_setopt($ci, CURLOPT_URL, $url);
221
+ $response = curl_exec($ci);
222
+ $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
223
+ $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
224
+ $this->url = $url;
225
+ curl_close ($ci);
226
+ return $response;
227
+ }
228
+
229
+ /**
230
+ * Get the header info to store.
231
+ */
232
+ function getHeader($ch, $header) {
233
+ $i = strpos($header, ':');
234
+ if (!empty($i)) {
235
+ $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
236
+ $value = trim(substr($header, $i + 2));
237
+ $this->http_header[$key] = $value;
238
+ }
239
+ return strlen($header);
240
+ }
241
+ }
package.xml CHANGED
@@ -1,20 +1,18 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Creare_Latesttweet</name>
4
- <version>1.0.0</version>
5
  <stability>stable</stability>
6
- <license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
- <summary>Get Latest Tweet from Twitter. Choose whether to show links, open links in new window, make all links nofollow.</summary>
10
- <description>Get Latest Tweet from Twitter. Choose whether to show links, open links in new window, make all links nofollow.&#xD;
11
- &#xD;
12
- Select to show up to 10 tweets. Visible in your side menu.</description>
13
- <notes>First Release</notes>
14
- <authors><author><name>E-Commerce Web Design</name><user>auto-converted</user><email>dev@e-commercewebdesign.co.uk</email></author></authors>
15
- <date>2012-02-16</date>
16
- <time>10:04:50</time>
17
- <contents><target name="magelocal"><dir name="Creare"><dir name="Latesttweet"><dir name="Block"><file name="Latesttweet.php" hash="37613ce0191e3b9d410ff833a98977a5"/></dir><dir name="Helper"><file name="Data.php" hash="42e5c15537debb7f1c46890ee9dbd559"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Source"><file name="Numbers.php" hash="3a2ee4bf798c5f9e10ad8f8637fe26a5"/></dir></dir></dir></dir></dir><dir name="etc"><file name="config.xml" hash="39481474924477af89890d26514f1e8e"/><file name="system.xml" hash="e2b8fe2b3ae892142ece4c1ac0a8bf9e"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="default"><dir name="default"><dir name="template"><dir name="latesttweet"><file name="tweet.phtml" hash="f3d4b1d71b87d734b54a337935d30231"/></dir></dir><dir name="layout"><file name="latesttweet.xml" hash="4dbedfcb997d97bb6fe6ee21893d50f9"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Creare_Latesttweet.xml" hash="43faaaf27bfb2437089157bdee2439a5"/></dir></target><target name="mageskin"><dir name="frontend"><dir name="default"><dir name="default"><dir name="css"><file name="latesttweet.css" hash="304864cf8d286bf77047432de5c19cea"/></dir><dir name="images"><dir name="latesttweet"><file name="tweet.gif" hash="21edf03982dae158df166cdad0478f91"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="latesttweet"><file name="admin.css" hash="790b7a705efea5b2f7d2f6e657244706"/></dir></dir></dir></dir></target></contents>
18
  <compatible/>
19
- <dependencies/>
20
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Creare_Latesttweet</name>
4
+ <version>2.0.1</version>
5
  <stability>stable</stability>
6
+ <license uri="http://www.opensource.org/licenses/OSL-3.0">OSL v3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
+ <summary>Updated to work with twitter oAuth API 1.1</summary>
10
+ <description>Creare's Latest Tweet extension has now been updated to work with Twitter oAuth 1.1.</description>
11
+ <notes>New release</notes>
12
+ <authors><author><name>Robert Kent</name><user>CreareGroup</user><email>magento@creare.co.uk</email></author></authors>
13
+ <date>2013-07-01</date>
14
+ <time>15:06:17</time>
15
+ <contents><target name="magelib"><dir name="twitteroauth"><file name="OAuth.php" hash="d7b40029f9d61580663a04727d166156"/><dir name="_notes"><file name="dwsync.xml" hash="2cb2384dd4579bf10512d44b946141c9"/></dir><file name="twitteroauth.php" hash="c329e25121783a292524acaea23bb28d"/></dir></target><target name="magelocal"><dir name="Creare"><dir name="Latesttweet"><dir name="Block"><file name="Latesttweet.php" hash="a6779e221df42e91b9713bdfc7904497"/><dir name="_notes"><file name="dwsync.xml" hash="f6aaf926c12333815419dcb7f9c4db97"/></dir></dir><dir name="Helper"><file name="Data.php" hash="42e5c15537debb7f1c46890ee9dbd559"/><dir name="_notes"><file name="dwsync.xml" hash="a45398f7cc572753fb885afbfccb61f2"/></dir></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Source"><file name="Display.php" hash="cf1675d3c9fb4ac9d419e243cc0561d9"/><file name="Numbers.php" hash="3a2ee4bf798c5f9e10ad8f8637fe26a5"/><dir name="_notes"><file name="dwsync.xml" hash="46b1edd7f20802be263e6b512ef94fd6"/></dir></dir></dir></dir></dir></dir><dir name="etc"><dir name="_notes"><file name="dwsync.xml" hash="2ae7a10d04bd48553f6ad6ece8d9ba9c"/></dir><file name="config.xml" hash="41b5ad3c66a49ae3ba5b25246d9ee35e"/><file name="system.xml" hash="b189ba41fea07f46f86f675470fb3979"/></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><file name="creare_latesttweet.css" hash="c63579f27fc01ebe105ac68ff846f82c"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Creare_Latesttweet.xml" hash="cf9e3328cc1629d6b317cde528a3e2b6"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="creare_latesttweet.xml" hash="fe8247231cf881005af0f37706eb16d6"/></dir><dir name="template"><dir name="creare"><dir name="latesttweet"><dir name="_notes"><file name="dwsync.xml" hash="568da61d8e191a35e1f4babcdf6a68cd"/></dir><file name="blank.phtml" hash="f8b2120cda4aa0a29d9400b05ad1e0b0"/><file name="tweet.phtml" hash="1be0fcfc2541fb7a544b76af7c995037"/></dir></dir></dir></dir></dir></dir></target></contents>
 
 
16
  <compatible/>
17
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
18
  </package>
skin/adminhtml/default/default/latesttweet/admin.css DELETED
@@ -1,12 +0,0 @@
1
- /* CSS Document */
2
- .creare-header { width: 100%; }
3
- .creare-footer { width: 100%; padding: 10px 0 0; clear: both; }
4
- .creare-footer a span { display: none; }
5
- .creare-footer a { display: block; float: left; margin-right: 5px; }
6
- .creare-container { background-color:#fff;border:1px solid #CCC;padding:10px;margin-bottom:7px; height: 90px; }
7
- .ecom-creare { background: url(images/creare-ecommerce.gif) no-repeat; width: 150px; height: 55px; }
8
- .seo-creare { background: url(images/creare-seo.gif) no-repeat; width: 150px; height: 55px; }
9
- .web-creare { background: url(images/creare-web.gif) no-repeat; width: 150px; height: 55px;}
10
- .uk-flag { background: url(images/uk-flag.gif) no-repeat; width: 150px; height: 55px; display: block; float: left; }
11
- .uk-flag span { display: none; }
12
- .creare-clear { clear: both; }
 
 
 
 
 
 
 
 
 
 
 
 
skin/frontend/base/default/css/creare_latesttweet.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+ .block-creare-twitter li { padding: 5px 10px; font-size: 11px; }
2
+ .block-creare-twitter li span { display: block; font-weight: bold; }
skin/frontend/default/default/css/latesttweet.css DELETED
@@ -1,5 +0,0 @@
1
- .creare-tweet-title { color: #33ccff!important; }
2
- .creare-tweet-bg { background: url('../images/latesttweet/tweet.gif') top right no-repeat #F8F7F5!important; }
3
- .creare-tweet { padding: 5px; }
4
- .creare-tweet li { border-bottom: 1px bottom #bcbcbc; border-top: 1px solid #d5d5d5; padding: 5px 0; }
5
- .creare-tweet li span { display: block; font-size: 0.8em; font-style:italic; }
 
 
 
 
 
skin/frontend/default/default/images/latesttweet/tweet.gif DELETED
Binary file