├── ajax
├── dojo
│ ├── content.php
│ ├── dojo.js
│ ├── json.php
│ ├── submit.php
│ ├── submitform.php
│ └── testdojo.html
├── jquery
│ ├── ajaxback.php
│ ├── ajaxload.php
│ ├── ajaxtest.html
│ ├── fakepost.php
│ ├── jquery.js
│ ├── json.php
│ ├── serialize.html
│ ├── submit.php
│ └── submitform.php
└── mootools
│ ├── ajaxload.php
│ ├── gets.php
│ ├── json.php
│ ├── mootools-more-1.4.0.1.js
│ ├── mootools.js
│ ├── submitform.php
│ ├── test.html
│ └── test.php
├── ebay_finding_api
├── class.ebay.php
└── ebay_finding_test.php
├── extending_laravels_validation_class
└── application
│ ├── config
│ └── application.php
│ ├── language
│ └── en
│ │ └── validation.php
│ └── libraries
│ └── validator.php
├── getting_started_with_amazon_product_api
├── amazon_product_api_class.php
├── amazon_product_api_signed_request.php
└── index.php
├── getting_started_with_freebase_api
├── class.freebase.php
└── test.freebase.php
├── gmaps
├── index.php
├── js
│ └── jquery172.js
├── places_config.php
├── save_place.php
└── sql
│ └── db.sql
├── mustache
├── data.php
├── data2.php
├── jquery171.js
├── mustache.js
└── test.html
├── readme.md
├── registration_system_using_knockoutjs
├── refresher.css
├── refresher.html
└── refresher_save.php
├── storejs
├── jquery171.js
├── store.js
└── teststore.html
├── sugarjs
├── sugar.js
└── sugartest.html
└── zam
├── js
└── main.js
├── libs
└── twitteroauth
│ ├── OAuth.php
│ └── twitteroauth.php
├── phpunit.xml
├── tests
├── bootstrap.php
└── zam
│ └── zamTest.php
├── zam-options.php
├── zam-tweets-widget.php
└── zam.php
/ajax/dojo/content.php:
--------------------------------------------------------------------------------
1 | names; //that's why we access them like accesing methods or properties from real objects like this
7 | $languages = $obj->languages;
8 | echo "
Names:
";
9 | //we then loop through the items like how were used to with arrays
10 | foreach($names as $row){
11 | echo "".$row."";
12 | }
13 |
14 | echo "Languages:
";
15 | foreach($languages as $row){
16 | echo "".$row."";
17 | }
18 | ?>
--------------------------------------------------------------------------------
/ajax/dojo/json.php:
--------------------------------------------------------------------------------
1 | ['smashing magazine', 'codrops', 'sixrevisions', 'nettuts', 'coding horror'],
4 | 'people'=>['john resig', 'jeffrey way', 'chris coyier', 'jamison dance']
5 | ];
6 | $json_things = json_encode($things);
7 | echo $json_things;
8 | ?>
--------------------------------------------------------------------------------
/ajax/dojo/submit.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/dojo/submitform.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/dojo/testdojo.html:
--------------------------------------------------------------------------------
1 |
12 |
13 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/ajax/jquery/ajaxback.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/jquery/ajaxload.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/ajax/jquery/ajaxtest.html:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
30 |
31 |
--------------------------------------------------------------------------------
/ajax/jquery/fakepost.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/jquery/jquery.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anchetaWern/tutorials/5259e6864d7f5a0a02bbb1f8158dbac90ead065d/ajax/jquery/jquery.js
--------------------------------------------------------------------------------
/ajax/jquery/json.php:
--------------------------------------------------------------------------------
1 | ['smashing magazine', 'codrops', 'sixrevisions', 'nettuts', 'coding horror'],
4 | 'people'=>['john resig', 'jeffrey way', 'chris coyier', 'paul irish']
5 | ];
6 | $json_things = json_encode($things);
7 | echo $json_things;
8 | ?>
--------------------------------------------------------------------------------
/ajax/jquery/serialize.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/ajax/jquery/submit.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/jquery/submitform.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/ajax/mootools/ajaxload.php:
--------------------------------------------------------------------------------
1 | I'm loaded via ajax
--------------------------------------------------------------------------------
/ajax/mootools/gets.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/mootools/json.php:
--------------------------------------------------------------------------------
1 | ['smashing magazine', 'codrops', 'sixrevisions', 'nettuts', 'coding horror'],
4 | 'people'=>['john resig', 'jeffrey way', 'chris coyier', 'jamison dance']
5 | ];
6 | $json_things = json_encode($things);
7 | echo $json_things;
8 | ?>
--------------------------------------------------------------------------------
/ajax/mootools/mootools-more-1.4.0.1.js:
--------------------------------------------------------------------------------
1 | // MooTools: the javascript framework.
2 | // Load this file's selection again by visiting: http://mootools.net/more/512fd1917d2d71d8f22608a7133fe249
3 | // Or build this file again with packager using: packager build More/String.QueryString
4 | /*
5 | ---
6 |
7 | script: More.js
8 |
9 | name: More
10 |
11 | description: MooTools More
12 |
13 | license: MIT-style license
14 |
15 | authors:
16 | - Guillermo Rauch
17 | - Thomas Aylott
18 | - Scott Kyle
19 | - Arian Stolwijk
20 | - Tim Wienk
21 | - Christoph Pojer
22 | - Aaron Newton
23 | - Jacob Thornton
24 |
25 | requires:
26 | - Core/MooTools
27 |
28 | provides: [MooTools.More]
29 |
30 | ...
31 | */
32 |
33 | MooTools.More = {
34 | 'version': '1.4.0.1',
35 | 'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87'
36 | };
37 |
38 |
39 | /*
40 | ---
41 |
42 | script: String.QueryString.js
43 |
44 | name: String.QueryString
45 |
46 | description: Methods for dealing with URI query strings.
47 |
48 | license: MIT-style license
49 |
50 | authors:
51 | - Sebastian Markbåge
52 | - Aaron Newton
53 | - Lennart Pilon
54 | - Valerio Proietti
55 |
56 | requires:
57 | - Core/Array
58 | - Core/String
59 | - /MooTools.More
60 |
61 | provides: [String.QueryString]
62 |
63 | ...
64 | */
65 |
66 | String.implement({
67 |
68 | parseQueryString: function(decodeKeys, decodeValues){
69 | if (decodeKeys == null) decodeKeys = true;
70 | if (decodeValues == null) decodeValues = true;
71 |
72 | var vars = this.split(/[&;]/),
73 | object = {};
74 | if (!vars.length) return object;
75 |
76 | vars.each(function(val){
77 | var index = val.indexOf('=') + 1,
78 | value = index ? val.substr(index) : '',
79 | keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val],
80 | obj = object;
81 | if (!keys) return;
82 | if (decodeValues) value = decodeURIComponent(value);
83 | keys.each(function(key, i){
84 | if (decodeKeys) key = decodeURIComponent(key);
85 | var current = obj[key];
86 |
87 | if (i < keys.length - 1) obj = obj[key] = current || {};
88 | else if (typeOf(current) == 'array') current.push(value);
89 | else obj[key] = current != null ? [current, value] : value;
90 | });
91 | });
92 |
93 | return object;
94 | },
95 |
96 | cleanQueryString: function(method){
97 | return this.split('&').filter(function(val){
98 | var index = val.indexOf('='),
99 | key = index < 0 ? '' : val.substr(0, index),
100 | value = val.substr(index + 1);
101 |
102 | return method ? method.call(null, key, value) : (value || value === 0);
103 | }).join('&');
104 | }
105 |
106 | });
107 |
108 |
--------------------------------------------------------------------------------
/ajax/mootools/submitform.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ajax/mootools/test.html:
--------------------------------------------------------------------------------
1 | fsfsfsffsf
2 |
13 |
14 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ajax/mootools/test.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ebay_finding_api/class.ebay.php:
--------------------------------------------------------------------------------
1 | app_id = $app_id;
13 | $this->global_id = $global_id;
14 | }
15 |
16 | public function findItems($keyword = '', $limit = 2){
17 |
18 | $url = $this->url . '?';
19 | $url .= 'operation-name=findItemsByKeywords';
20 | $url .= '&service-version=' . $this->version;
21 | $url .= '&keywords=' . urlencode($keyword);
22 | $url .= '&paginationInput.entriesPerPage=' . $limit;
23 |
24 | $url .= '&security-appname='. $this->app_id;
25 | $url .= '&response-data-format=' . $this->format;
26 |
27 | return json_decode(file_get_contents($url), true);
28 | }
29 |
30 | public function findItemsAdvanced($keyword = '', $item_sort = 'BestMatch', $item_type = 'FixedPricedItem', $min_price = '0', $max_price = '9999999', $limit = 10){
31 |
32 | $url = $this->url . '?';
33 | $url .= 'operation-name=findItemsAdvanced';
34 | $url .= '&service-version=' . $this->version;
35 | $url .= '&global-id=' . $this->global_id;
36 | $url .= '&keywords=' . urlencode($keyword);
37 |
38 | $url .= '&sortOrder=BestMatch';
39 | $url .= '&itemFilter(0).name=ListingType';
40 | $url .= '&itemFilter(0).value=FixedPrice';
41 | $url .= '&itemFilter(1).name=MinPrice';
42 | $url .= '&itemFilter(1).value=' . $min_price;
43 | $url .= '&itemFilter(2).name=MaxPrice';
44 | $url .= '&itemFilter(2).value=' . $max_price;
45 | $url .= '&paginationInput.entriesPerPage=' . $limit;
46 | $url .= '&descriptionSearch=false';
47 |
48 | $url .= '&security-appname='. $this->app_id;
49 | $url .= '&response-data-format=' . $this->format;
50 |
51 | return json_decode(file_get_contents($url), true);
52 | }
53 |
54 | public function sortOrders(){
55 | $sort_orders = array(
56 | 'BestMatch' => 'Best Match',
57 | 'BidCountFewest' => 'Bid Count Fewest',
58 | 'BidCountMost' => 'Bid Count Most',
59 | 'CountryAscending' => 'Country Ascending',
60 | 'CountryDescending' => 'Country Descending',
61 | 'CurrentPriceHighest' => 'Current Highest Price',
62 | 'DistanceNearest' => 'Nearest Distance',
63 | 'EndTimeSoonest' => 'End Time Soonest',
64 | 'PricePlusShippingHighest' => 'Price Plus Shipping Highest',
65 | 'PricePlusShippingLowest' => 'Price Plus Shipping Lowest',
66 | 'StartTimeNewest' => 'Start Time Newest'
67 | );
68 |
69 | return $sort_orders;
70 | }
71 | }
72 | ?>
--------------------------------------------------------------------------------
/ebay_finding_api/ebay_finding_test.php:
--------------------------------------------------------------------------------
1 | sortOrders();
6 | ?>
7 |
8 |
21 |
22 | findItemsAdvanced($_POST['search'], $_POST['sort']);
27 | $item_count = $results['findItemsAdvancedResponse'][0]['searchResult'][0]['@count'];
28 |
29 |
30 | if($item_count > 0){
31 | $items = $results['findItemsAdvancedResponse'][0]['searchResult'][0]['item'];
32 |
33 | foreach($items as $i){
34 | ?>
35 |
36 |
39 |
40 |
![<?php echo $i['title']; ?>](<?php echo $i['galleryURL'][0]; ?>)
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/extending_laravels_validation_class/application/config/application.php:
--------------------------------------------------------------------------------
1 | '',
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Asset URL
21 | |--------------------------------------------------------------------------
22 | |
23 | | The base URL used for your application's asset files. This is useful if
24 | | you are serving your assets through a different server or a CDN. If it
25 | | is not set, we'll default to the application URL above.
26 | |
27 | */
28 |
29 | 'asset_url' => '',
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Application Index
34 | |--------------------------------------------------------------------------
35 | |
36 | | If you are including the "index.php" in your URLs, you can ignore this.
37 | | However, if you are using mod_rewrite to get cleaner URLs, just set
38 | | this option to an empty string and we'll take care of the rest.
39 | |
40 | */
41 |
42 | 'index' => '',
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Application Key
47 | |--------------------------------------------------------------------------
48 | |
49 | | This key is used by the encryption and cookie classes to generate secure
50 | | encrypted strings and hashes. It is extremely important that this key
51 | | remains secret and it should not be shared with anyone. Make it about 32
52 | | characters of random gibberish.
53 | |
54 | */
55 |
56 | 'key' => 'B8NH7pL6NtQgvxCcbo4lfpn81FIT1WOL',
57 |
58 | /*
59 | |--------------------------------------------------------------------------
60 | | Profiler Toolbar
61 | |--------------------------------------------------------------------------
62 | |
63 | | Laravel includes a beautiful profiler toolbar that gives you a heads
64 | | up display of the queries and logs performed by your application.
65 | | This is wonderful for development, but, of course, you should
66 | | disable the toolbar for production applications.
67 | |
68 | */
69 |
70 | 'profiler' => true,
71 |
72 | /*
73 | |--------------------------------------------------------------------------
74 | | Application Character Encoding
75 | |--------------------------------------------------------------------------
76 | |
77 | | The default character encoding used by your application. This encoding
78 | | will be used by the Str, Text, Form, and any other classes that need
79 | | to know what type of encoding to use for your awesome application.
80 | |
81 | */
82 |
83 | 'encoding' => 'UTF-8',
84 |
85 | /*
86 | |--------------------------------------------------------------------------
87 | | Default Application Language
88 | |--------------------------------------------------------------------------
89 | |
90 | | The default language of your application. This language will be used by
91 | | Lang library as the default language when doing string localization.
92 | |
93 | */
94 |
95 | 'language' => 'en',
96 |
97 | /*
98 | |--------------------------------------------------------------------------
99 | | Supported Languages
100 | |--------------------------------------------------------------------------
101 | |
102 | | These languages may also be supported by your application. If a request
103 | | enters your application with a URI beginning with one of these values
104 | | the default language will automatically be set to that language.
105 | |
106 | */
107 |
108 | 'languages' => array(),
109 |
110 | /*
111 | |--------------------------------------------------------------------------
112 | | SSL Link Generation
113 | |--------------------------------------------------------------------------
114 | |
115 | | Many sites use SSL to protect their users' data. However, you may not be
116 | | able to use SSL on your development machine, meaning all HTTPS will be
117 | | broken during development.
118 | |
119 | | For this reason, you may wish to disable the generation of HTTPS links
120 | | throughout your application. This option does just that. All attempts
121 | | to generate HTTPS links will generate regular HTTP links instead.
122 | |
123 | */
124 |
125 | 'ssl' => true,
126 |
127 | /*
128 | |--------------------------------------------------------------------------
129 | | Application Timezone
130 | |--------------------------------------------------------------------------
131 | |
132 | | The default timezone of your application. The timezone will be used when
133 | | Laravel needs a date, such as when writing to a log file or travelling
134 | | to a distant star at warp speed.
135 | |
136 | */
137 |
138 | 'timezone' => 'UTC',
139 |
140 | /*
141 | |--------------------------------------------------------------------------
142 | | Class Aliases
143 | |--------------------------------------------------------------------------
144 | |
145 | | Here, you can specify any class aliases that you would like registered
146 | | when Laravel loads. Aliases are lazy-loaded, so feel free to add!
147 | |
148 | | Aliases make it more convenient to use namespaced classes. Instead of
149 | | referring to the class using its full namespace, you may simply use
150 | | the alias defined here.
151 | |
152 | */
153 |
154 | 'aliases' => array(
155 | 'Auth' => 'Laravel\\Auth',
156 | 'Authenticator' => 'Laravel\\Auth\\Drivers\\Driver',
157 | 'Asset' => 'Laravel\\Asset',
158 | 'Autoloader' => 'Laravel\\Autoloader',
159 | 'Blade' => 'Laravel\\Blade',
160 | 'Bundle' => 'Laravel\\Bundle',
161 | 'Cache' => 'Laravel\\Cache',
162 | 'Config' => 'Laravel\\Config',
163 | 'Controller' => 'Laravel\\Routing\\Controller',
164 | 'Cookie' => 'Laravel\\Cookie',
165 | 'Crypter' => 'Laravel\\Crypter',
166 | 'DB' => 'Laravel\\Database',
167 | 'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
168 | 'Event' => 'Laravel\\Event',
169 | 'File' => 'Laravel\\File',
170 | 'Filter' => 'Laravel\\Routing\\Filter',
171 | 'Form' => 'Laravel\\Form',
172 | 'Hash' => 'Laravel\\Hash',
173 | 'HTML' => 'Laravel\\HTML',
174 | 'Input' => 'Laravel\\Input',
175 | 'IoC' => 'Laravel\\IoC',
176 | 'Lang' => 'Laravel\\Lang',
177 | 'Log' => 'Laravel\\Log',
178 | 'Memcached' => 'Laravel\\Memcached',
179 | 'Paginator' => 'Laravel\\Paginator',
180 | 'Profiler' => 'Laravel\\Profiling\\Profiler',
181 | 'URL' => 'Laravel\\URL',
182 | 'Redirect' => 'Laravel\\Redirect',
183 | 'Redis' => 'Laravel\\Redis',
184 | 'Request' => 'Laravel\\Request',
185 | 'Response' => 'Laravel\\Response',
186 | 'Route' => 'Laravel\\Routing\\Route',
187 | 'Router' => 'Laravel\\Routing\\Router',
188 | 'Schema' => 'Laravel\\Database\\Schema',
189 | 'Section' => 'Laravel\\Section',
190 | 'Session' => 'Laravel\\Session',
191 | 'Str' => 'Laravel\\Str',
192 | 'Task' => 'Laravel\\CLI\\Tasks\\Task',
193 | 'URI' => 'Laravel\\URI',
194 | 'View' => 'Laravel\\View',
195 | ),
196 |
197 | );
198 |
--------------------------------------------------------------------------------
/extending_laravels_validation_class/application/language/en/validation.php:
--------------------------------------------------------------------------------
1 | "The :attribute must be accepted.",
22 | "active_url" => "The :attribute is not a valid URL.",
23 | "after" => "The :attribute must be a date after :date.",
24 | "alpha" => "The :attribute may only contain letters.",
25 | "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.",
26 | "alpha_num" => "The :attribute may only contain letters and numbers.",
27 | "array" => "The :attribute must have selected elements.",
28 | "before" => "The :attribute must be a date before :date.",
29 | "between" => array(
30 | "numeric" => "The :attribute must be between :min - :max.",
31 | "file" => "The :attribute must be between :min - :max kilobytes.",
32 | "string" => "The :attribute must be between :min - :max characters.",
33 | ),
34 | "confirmed" => "The :attribute confirmation does not match.",
35 | "count" => "The :attribute must have exactly :count selected elements.",
36 | "countbetween" => "The :attribute must have between :min and :max selected elements.",
37 | "countmax" => "The :attribute must have less than :max selected elements.",
38 | "countmin" => "The :attribute must have at least :min selected elements.",
39 | "different" => "The :attribute and :other must be different.",
40 | "email" => "The :attribute format is invalid.",
41 | "exists" => "The selected :attribute is invalid.",
42 | "image" => "The :attribute must be an image.",
43 | "in" => "The selected :attribute is invalid.",
44 | "integer" => "The :attribute must be an integer.",
45 | "ip" => "The :attribute must be a valid IP address.",
46 | "match" => "The :attribute format is invalid.",
47 | "max" => array(
48 | "numeric" => "The :attribute must be less than :max.",
49 | "file" => "The :attribute must be less than :max kilobytes.",
50 | "string" => "The :attribute must be less than :max characters.",
51 | ),
52 | "mimes" => "The :attribute must be a file of type: :values.",
53 | "min" => array(
54 | "numeric" => "The :attribute must be at least :min.",
55 | "file" => "The :attribute must be at least :min kilobytes.",
56 | "string" => "The :attribute must be at least :min characters.",
57 | ),
58 | "not_in" => "The selected :attribute is invalid.",
59 | "numeric" => "The :attribute must be a number.",
60 | "required" => "The :attribute field is required.",
61 | "same" => "The :attribute and :other must match.",
62 | "size" => array(
63 | "numeric" => "The :attribute must be :size.",
64 | "file" => "The :attribute must be :size kilobyte.",
65 | "string" => "The :attribute must be :size characters.",
66 | ),
67 | "unique" => "The :attribute has already been taken.",
68 | "url" => "The :attribute format is invalid.",
69 | "date" => "The :attribute is invalid date",
70 | "arrayfull" => "The :attribute contains empty values",
71 | "arrayunique" => "The :attribute contains duplicate values",
72 | "arraynumeric" => "The :attribute contains non-numeric values",
73 |
74 | /*
75 | |--------------------------------------------------------------------------
76 | | Custom Validation Language Lines
77 | |--------------------------------------------------------------------------
78 | |
79 | | Here you may specify custom validation messages for attributes using the
80 | | convention "attribute_rule" to name the lines. This helps keep your
81 | | custom validation clean and tidy.
82 | |
83 | | So, say you want to use a custom validation message when validating that
84 | | the "email" attribute is unique. Just add "email_unique" to this array
85 | | with your custom message. The Validator will handle the rest!
86 | |
87 | */
88 |
89 | 'custom' => array(),
90 |
91 | /*
92 | |--------------------------------------------------------------------------
93 | | Validation Attributes
94 | |--------------------------------------------------------------------------
95 | |
96 | | The following language lines are used to swap attribute place-holders
97 | | with something more reader friendly such as "E-Mail Address" instead
98 | | of "email". Your users will thank you.
99 | |
100 | | The Validator class will automatically search this array of lines it
101 | | is attempting to replace the :attribute place-holder in messages.
102 | | It's pretty slick. We think you'll like it.
103 | |
104 | */
105 |
106 | 'attributes' => array(),
107 |
108 | );
--------------------------------------------------------------------------------
/extending_laravels_validation_class/application/libraries/validator.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/getting_started_with_amazon_product_api/amazon_product_api_class.php:
--------------------------------------------------------------------------------
1 | public_key = $public;
81 | $this->private_key = $private;
82 | $this->local_site = $local_site;
83 | $this->associate_tag = $associate_tag;
84 |
85 | }
86 |
87 | public function get_local(){
88 | return $this->local_site;
89 | }
90 |
91 | /**
92 | * Check if the xml received from Amazon is valid
93 | *
94 | * @param mixed $response xml response to check
95 | * @return bool false if the xml is invalid
96 | * @return mixed the xml response if it is valid
97 | * @return exception if we could not connect to Amazon
98 | */
99 | private function verifyXmlResponse($response)
100 | {
101 | if ($response === False)
102 | {
103 | throw new Exception("Could not connect to Amazon");
104 | }
105 | else
106 | {
107 | if (isset($response->Items->Item->ItemAttributes->Title))
108 | {
109 | return ($response);
110 | }
111 | else
112 | {
113 | throw new Exception("Invalid xml response.");
114 | }
115 | }
116 | }
117 |
118 |
119 | /**
120 | * Query Amazon with the issued parameters
121 | *
122 | * @param array $parameters parameters to query around
123 | * @return simpleXmlObject xml query response
124 | */
125 | public function queryAmazon($parameters)
126 | {
127 | return amazon_product_api_signed_request($this->local_site, $parameters, $this->public_key, $this->private_key, $this->associate_tag);
128 | }
129 |
130 |
131 | /**
132 | * Return details of products searched by various types
133 | *
134 | * @param string $search search term
135 | * @param string $category search category
136 | * @param string $searchType type of search
137 | * @return mixed simpleXML object
138 | */
139 | public function searchProducts($search, $category, $searchType = "UPC")
140 | {
141 | $allowedTypes = array("UPC", "TITLE", "ARTIST", "KEYWORD");
142 | $allowedCategories = array("Music", "DVD", "VideoGames");
143 |
144 | switch($searchType)
145 | {
146 | case "UPC" : $parameters = array("Operation" => "ItemLookup",
147 | "ItemId" => $search,
148 | "SearchIndex" => $category,
149 | "IdType" => "UPC",
150 | "ResponseGroup" => "Medium");
151 | break;
152 |
153 | case "TITLE" : $parameters = array("Operation" => "ItemSearch",
154 | "Title" => $search,
155 | "SearchIndex" => $category,
156 | "ResponseGroup" => "Medium");
157 | break;
158 |
159 | }
160 |
161 | $xml_response = $this->queryAmazon($parameters);
162 |
163 | return $this->verifyXmlResponse($xml_response);
164 |
165 | }
166 |
167 |
168 |
169 |
170 | public function getBrowseNodeProducts($category, $browseNode = 1000, $searchType = "UPC")
171 | {
172 | $allowedTypes = array("UPC", "TITLE", "ARTIST", "KEYWORD");
173 | $allowedCategories = array("Music", "DVD", "VideoGames");
174 |
175 | $parameters = array(
176 | "Operation" => "ItemSearch",
177 | "BrowseNode" => $browseNode,
178 | "SearchIndex" => $category,
179 | "ResponseGroup" => "Medium,Reviews"
180 | );
181 |
182 | $xml_response = $this->queryAmazon($parameters);
183 |
184 | return $this->verifyXmlResponse($xml_response);
185 |
186 | }
187 |
188 |
189 | /**
190 | * Return details of a product searched by UPC
191 | *
192 | * @param int $upc_code UPC code of the product to search
193 | * @param string $product_type type of the product
194 | * @return mixed simpleXML object
195 | */
196 | public function getItemByUpc($upc_code, $product_type)
197 | {
198 | $parameters = array("Operation" => "ItemLookup",
199 | "ItemId" => $upc_code,
200 | "SearchIndex" => $product_type,
201 | "IdType" => "UPC",
202 | "ResponseGroup" => "Medium");
203 |
204 | $xml_response = $this->queryAmazon($parameters);
205 |
206 | return $this->verifyXmlResponse($xml_response);
207 |
208 | }
209 |
210 |
211 | /**
212 | * Return details of a product searched by ASIN
213 | *
214 | * @param int $asin_code ASIN code of the product to search
215 | * @return mixed simpleXML object
216 | */
217 | public function getItemByAsin($asin_code)
218 | {
219 | $parameters = array("Operation" => "ItemLookup",
220 | "ItemId" => $asin_code,
221 | "ResponseGroup" => "Medium");
222 |
223 | $xml_response = $this->queryAmazon($parameters);
224 |
225 | return $this->verifyXmlResponse($xml_response);
226 | }
227 |
228 |
229 | /**
230 | * Return details of a product searched by keyword
231 | *
232 | * @param string $keyword keyword to search
233 | * @param string $product_type type of the product
234 | * @return mixed simpleXML object
235 | */
236 | public function getItemByKeyword($keyword, $product_type)
237 | {
238 | $parameters = array("Operation" => "ItemSearch",
239 | "Keywords" => $keyword,
240 | "SearchIndex" => $product_type);
241 |
242 | $xml_response = $this->queryAmazon($parameters);
243 |
244 | return $this->verifyXmlResponse($xml_response);
245 | }
246 |
247 | }
248 |
249 | ?>
250 |
--------------------------------------------------------------------------------
/getting_started_with_amazon_product_api/amazon_product_api_signed_request.php:
--------------------------------------------------------------------------------
1 | $value)
65 | {
66 | $param = str_replace("%7E", "~", rawurlencode($param));
67 | $value = str_replace("%7E", "~", rawurlencode($value));
68 | $canonicalized_query[] = $param."=".$value;
69 | }
70 |
71 | $canonicalized_query = implode("&", $canonicalized_query);
72 |
73 | $string_to_sign = $method."\n".$host."\n".$uri."\n".$canonicalized_query;
74 |
75 | /* calculate the signature using HMAC with SHA256 and base64-encoding.
76 | The 'hash_hmac' function is only available from PHP 5 >= 5.1.2.
77 | */
78 | $signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True));
79 |
80 | /* encode the signature for the request */
81 | $signature = str_replace("%7E", "~", rawurlencode($signature));
82 |
83 | /* create request */
84 | $request = "http://".$host.$uri."?".$canonicalized_query."&Signature=".$signature;
85 |
86 | /* I prefer using CURL */
87 | $ch = curl_init();
88 | curl_setopt($ch, CURLOPT_URL,$request);
89 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
90 | curl_setopt($ch, CURLOPT_TIMEOUT, 15);
91 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
92 |
93 | $xml_response = curl_exec($ch);
94 |
95 | /* If cURL doesn't work for you, then use the 'file_get_contents'
96 | function as given below.
97 | */
98 |
99 | if ($xml_response === False)
100 | {
101 | return False;
102 | }
103 | else
104 | {
105 | /* parse XML */
106 | $parsed_xml = @simplexml_load_string($xml_response);
107 | return ($parsed_xml === False) ? False : $parsed_xml;
108 | }
109 | }
110 | ?>
111 |
--------------------------------------------------------------------------------
/getting_started_with_amazon_product_api/index.php:
--------------------------------------------------------------------------------
1 | 'SimilarityLookup',
12 | 'ItemId' => 'B0006N149M',
13 | 'Condition' => 'All',
14 | 'ResponseGroup' => 'Medium'
15 | );
16 |
17 | $result = $amazon->queryAmazon($similar);
18 | $similar_products = $result->Items->Item;
19 |
20 | foreach($similar_products as $si){
21 |
22 | $item_url = $si->DetailPageURL; //get its amazon url
23 | $img = $si->MediumImage->URL; //get the image url
24 |
25 | echo "";
26 | echo "
";
27 | echo "". $si->ASIN . "";
28 | echo $si->ItemAttributes->ListPrice->FormattedPrice; //item price
29 | echo "";
30 | }
31 | ?>
--------------------------------------------------------------------------------
/getting_started_with_freebase_api/class.freebase.php:
--------------------------------------------------------------------------------
1 | api_key;
17 |
18 |
19 | return json_decode(file_get_contents($url), true)['result'];
20 | }
21 |
22 | public function image($entity_id, $max_width = 150, $max_height = 150){
23 |
24 | $url = 'https://usercontent.googleapis.com/freebase/v1/image' . $entity_id;
25 | $url .= '?maxwidth=' . $max_width;
26 | $url .= '&maxheight=' . $max_height;
27 | $url .= '&key=' . $this->api_key;
28 |
29 | return $url;
30 | }
31 |
32 | public function text($entity_id, $max_length = '0'){
33 |
34 | $url = 'https://www.googleapis.com/freebase/v1/text/' . $entity_id;
35 | $url .= '?maxlength=' . $max_length;
36 | $url .= '&lang=fr';
37 | $url .= '&key=' . $this->api_key;
38 |
39 |
40 | return json_decode(file_get_contents($url), true)['result'];
41 | }
42 |
43 | public function topic($entity_id){
44 |
45 | $url = 'https://www.googleapis.com/freebase/v1/topic' . $entity_id;
46 | return json_decode(file_get_contents($url), true);
47 | }
48 | }
49 | ?>
50 |
--------------------------------------------------------------------------------
/getting_started_with_freebase_api/test.freebase.php:
--------------------------------------------------------------------------------
1 | search('Dragon ball z', 'all type:manga');
6 |
7 | foreach($result as $entity){
8 |
9 | $id = $entity['mid'];
10 | $name = $entity['name'];
11 |
12 | $image = $freebase->image($id);
13 | $text = $freebase->text($id);
14 | ?>
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/gmaps/index.php:
--------------------------------------------------------------------------------
1 | query("SELECT * FROM tbl_places");
4 | ?>
5 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
55 |
56 |
57 |
58 |
61 |
--------------------------------------------------------------------------------
/gmaps/places_config.php:
--------------------------------------------------------------------------------
1 | connect_errno){
4 | die('Connect Error: ' . $db->connect_errno);
5 | }
6 | ?>
--------------------------------------------------------------------------------
/gmaps/save_place.php:
--------------------------------------------------------------------------------
1 | query("INSERT INTO tbl_places SET place='$place', description='$description', lat='$latitude', lng='$longitude'");
8 | $place_id = $db->insert_id;
9 | echo $place_id;
10 | ?>
--------------------------------------------------------------------------------
/gmaps/sql/db.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS `tbl_places` (
2 | `place_id` int(10) NOT NULL AUTO_INCREMENT,
3 | `place` varchar(160) NOT NULL,
4 | `description` varchar(200) NOT NULL,
5 | `lat` float(15,11) NOT NULL,
6 | `lng` float(15,11) NOT NULL,
7 | PRIMARY KEY (`place_id`)
8 | ) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=latin1;
9 |
--------------------------------------------------------------------------------
/mustache/data.php:
--------------------------------------------------------------------------------
1 | false, 'magic_word'=>'cool', 'name'=>'naruto', 'skills'=>array('rasenshuriken'=>array('super', 'golden', 'tsukasenmai'), 'rasengan'=>array('abc','def','ghi'), 'kage bunshin'=>array('kame', 'hame', 'wave')));
3 | echo json_encode($ninja);
--------------------------------------------------------------------------------
/mustache/data2.php:
--------------------------------------------------------------------------------
1 | [
3 | 'naruto'=>['name'=>'naruto', 'skills'=>['rasengan', 'kage bunshin']],
4 | 'sasuke'=>['name'=>'sasuke', 'skills'=>['chidori', 'sharingan']],
5 | 'lee'=>['name'=>'lee', 'skills'=>['leaf hurricane', '5 gates']]
6 | ]
7 | ];
8 |
9 | echo json_encode($data2);
--------------------------------------------------------------------------------
/mustache/mustache.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * mustache.js - Logic-less {{mustache}} templates with JavaScript
3 | * http://github.com/janl/mustache.js
4 | */
5 | var Mustache = (typeof module !== "undefined" && module.exports) || {};
6 |
7 | (function (exports) {
8 |
9 | exports.name = "mustache.js";
10 | exports.version = "0.5.1-dev";
11 | exports.tags = ["{{", "}}"];
12 |
13 | exports.parse = parse;
14 | exports.clearCache = clearCache;
15 | exports.compile = compile;
16 | exports.compilePartial = compilePartial;
17 | exports.render = render;
18 |
19 | exports.Scanner = Scanner;
20 | exports.Context = Context;
21 | exports.Renderer = Renderer;
22 |
23 | // This is here for backwards compatibility with 0.4.x.
24 | exports.to_html = function (template, view, partials, send) {
25 | var result = render(template, view, partials);
26 |
27 | if (typeof send === "function") {
28 | send(result);
29 | } else {
30 | return result;
31 | }
32 | };
33 |
34 | var whiteRe = /\s*/;
35 | var spaceRe = /\s+/;
36 | var nonSpaceRe = /\S/;
37 | var eqRe = /\s*=/;
38 | var curlyRe = /\s*\}/;
39 | var tagRe = /#|\^|\/|>|\{|&|=|!/;
40 |
41 | // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
42 | // See https://github.com/janl/mustache.js/issues/189
43 | function testRe(re, string) {
44 | return RegExp.prototype.test.call(re, string);
45 | }
46 |
47 | function isWhitespace(string) {
48 | return !testRe(nonSpaceRe, string);
49 | }
50 |
51 | var isArray = Array.isArray || function (obj) {
52 | return Object.prototype.toString.call(obj) === "[object Array]";
53 | };
54 |
55 | // OSWASP Guidlines: escape all non alphanumeric characters in ASCII space.
56 | var jsCharsRe = /[\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\xFF\u2028\u2029]/gm;
57 |
58 | function quote(text) {
59 | var escaped = text.replace(jsCharsRe, function (c) {
60 | return "\\u" + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
61 | });
62 |
63 | return '"' + escaped + '"';
64 | }
65 |
66 | function escapeRe(string) {
67 | return string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
68 | }
69 |
70 | var entityMap = {
71 | "&": "&",
72 | "<": "<",
73 | ">": ">",
74 | '"': '"',
75 | "'": ''',
76 | "/": '/'
77 | };
78 |
79 | function escapeHtml(string) {
80 | return String(string).replace(/[&<>"'\/]/g, function (s) {
81 | return entityMap[s];
82 | });
83 | }
84 |
85 | // Export these utility functions.
86 | exports.isWhitespace = isWhitespace;
87 | exports.isArray = isArray;
88 | exports.quote = quote;
89 | exports.escapeRe = escapeRe;
90 | exports.escapeHtml = escapeHtml;
91 |
92 | function Scanner(string) {
93 | this.string = string;
94 | this.tail = string;
95 | this.pos = 0;
96 | }
97 |
98 | /**
99 | * Returns `true` if the tail is empty (end of string).
100 | */
101 | Scanner.prototype.eos = function () {
102 | return this.tail === "";
103 | };
104 |
105 | /**
106 | * Tries to match the given regular expression at the current position.
107 | * Returns the matched text if it can match, `null` otherwise.
108 | */
109 | Scanner.prototype.scan = function (re) {
110 | var match = this.tail.match(re);
111 |
112 | if (match && match.index === 0) {
113 | this.tail = this.tail.substring(match[0].length);
114 | this.pos += match[0].length;
115 | return match[0];
116 | }
117 |
118 | return null;
119 | };
120 |
121 | /**
122 | * Skips all text until the given regular expression can be matched. Returns
123 | * the skipped string, which is the entire tail of this scanner if no match
124 | * can be made.
125 | */
126 | Scanner.prototype.scanUntil = function (re) {
127 | var match, pos = this.tail.search(re);
128 |
129 | switch (pos) {
130 | case -1:
131 | match = this.tail;
132 | this.pos += this.tail.length;
133 | this.tail = "";
134 | break;
135 | case 0:
136 | match = null;
137 | break;
138 | default:
139 | match = this.tail.substring(0, pos);
140 | this.tail = this.tail.substring(pos);
141 | this.pos += pos;
142 | }
143 |
144 | return match;
145 | };
146 |
147 | function Context(view, parent) {
148 | this.view = view;
149 | this.parent = parent;
150 | this.clearCache();
151 | }
152 |
153 | Context.make = function (view) {
154 | return (view instanceof Context) ? view : new Context(view);
155 | };
156 |
157 | Context.prototype.clearCache = function () {
158 | this._cache = {};
159 | };
160 |
161 | Context.prototype.push = function (view) {
162 | return new Context(view, this);
163 | };
164 |
165 | Context.prototype.lookup = function (name) {
166 | var value = this._cache[name];
167 |
168 | if (!value) {
169 | if (name === ".") {
170 | value = this.view;
171 | } else {
172 | var context = this;
173 |
174 | while (context) {
175 | if (name.indexOf(".") > 0) {
176 | var names = name.split("."), i = 0;
177 |
178 | value = context.view;
179 |
180 | while (value && i < names.length) {
181 | value = value[names[i++]];
182 | }
183 | } else {
184 | value = context.view[name];
185 | }
186 |
187 | if (value != null) {
188 | break;
189 | }
190 |
191 | context = context.parent;
192 | }
193 | }
194 |
195 | this._cache[name] = value;
196 | }
197 |
198 | if (typeof value === "function") {
199 | value = value.call(this.view);
200 | }
201 |
202 | return value;
203 | };
204 |
205 | function Renderer() {
206 | this.clearCache();
207 | }
208 |
209 | Renderer.prototype.clearCache = function () {
210 | this._cache = {};
211 | this._partialCache = {};
212 | };
213 |
214 | Renderer.prototype.compile = function (tokens, tags) {
215 | var fn = compileTokens(tokens),
216 | self = this;
217 |
218 | return function (view) {
219 | return fn(Context.make(view), self);
220 | };
221 | };
222 |
223 | Renderer.prototype.compilePartial = function (name, tokens, tags) {
224 | this._partialCache[name] = this.compile(tokens, tags);
225 | return this._partialCache[name];
226 | };
227 |
228 | Renderer.prototype.render = function (template, view) {
229 | var fn = this._cache[template];
230 |
231 | if (!fn) {
232 | fn = this.compile(template);
233 | this._cache[template] = fn;
234 | }
235 |
236 | return fn(view);
237 | };
238 |
239 | Renderer.prototype._section = function (name, context, callback) {
240 | var value = context.lookup(name);
241 |
242 | switch (typeof value) {
243 | case "object":
244 | if (isArray(value)) {
245 | var buffer = "";
246 | for (var i = 0, len = value.length; i < len; ++i) {
247 | buffer += callback(context.push(value[i]), this);
248 | }
249 | return buffer;
250 | } else {
251 | return callback(context.push(value), this);
252 | }
253 | break;
254 | case "function":
255 | var sectionText = callback(context, this), self = this;
256 | var scopedRender = function (template) {
257 | return self.render(template, context);
258 | };
259 | return value.call(context.view, sectionText, scopedRender) || "";
260 | break;
261 | default:
262 | if (value) {
263 | return callback(context, this);
264 | }
265 | }
266 |
267 | return "";
268 | };
269 |
270 | Renderer.prototype._inverted = function (name, context, callback) {
271 | var value = context.lookup(name);
272 |
273 | // From the spec: inverted sections may render text once based on the
274 | // inverse value of the key. That is, they will be rendered if the key
275 | // doesn't exist, is false, or is an empty list.
276 | if (value == null || value === false || (isArray(value) && value.length === 0)) {
277 | return callback(context, this);
278 | }
279 |
280 | return "";
281 | };
282 |
283 | Renderer.prototype._partial = function (name, context) {
284 | var fn = this._partialCache[name];
285 |
286 | if (fn) {
287 | return fn(context, this);
288 | }
289 |
290 | return "";
291 | };
292 |
293 | Renderer.prototype._name = function (name, context, escape) {
294 | var value = context.lookup(name);
295 |
296 | if (typeof value === "function") {
297 | value = value.call(context.view);
298 | }
299 |
300 | var string = (value == null) ? "" : String(value);
301 |
302 | if (escape) {
303 | return escapeHtml(string);
304 | }
305 |
306 | return string;
307 | };
308 |
309 | /**
310 | * Low-level function that compiles the given `tokens` into a
311 | * function that accepts two arguments: a Context and a
312 | * Renderer. Returns the body of the function as a string if
313 | * `returnBody` is true.
314 | */
315 | function compileTokens(tokens, returnBody) {
316 | if (typeof tokens === "string") {
317 | tokens = parse(tokens);
318 | }
319 |
320 | var body = ['""'];
321 | var token, method, escape;
322 |
323 | for (var i = 0, len = tokens.length; i < len; ++i) {
324 | token = tokens[i];
325 |
326 | switch (token.type) {
327 | case "#":
328 | case "^":
329 | method = (token.type === "#") ? "_section" : "_inverted";
330 | body.push("r." + method + "(" + quote(token.value) + ", c, function (c, r) {\n" +
331 | " " + compileTokens(token.tokens, true) + "\n" +
332 | "})");
333 | break;
334 | case "{":
335 | case "&":
336 | case "name":
337 | escape = token.type === "name" ? "true" : "false";
338 | body.push("r._name(" + quote(token.value) + ", c, " + escape + ")");
339 | break;
340 | case ">":
341 | body.push("r._partial(" + quote(token.value) + ", c)");
342 | break;
343 | case "text":
344 | body.push(quote(token.value));
345 | break;
346 | }
347 | }
348 |
349 | // Convert to a string body.
350 | body = "return " + body.join(" + ") + ";";
351 |
352 | // Good for debugging.
353 | // console.log(body);
354 |
355 | if (returnBody) {
356 | return body;
357 | }
358 |
359 | // For great evil!
360 | return new Function("c, r", body);
361 | }
362 |
363 | function escapeTags(tags) {
364 | if (tags.length === 2) {
365 | return [
366 | new RegExp(escapeRe(tags[0]) + "\\s*"),
367 | new RegExp("\\s*" + escapeRe(tags[1]))
368 | ];
369 | }
370 |
371 | throw new Error("Invalid tags: " + tags.join(" "));
372 | }
373 |
374 | /**
375 | * Forms the given linear array of `tokens` into a nested tree structure
376 | * where tokens that represent a section have a "tokens" array property
377 | * that contains all tokens that are in that section.
378 | */
379 | function nestTokens(tokens) {
380 | var tree = [];
381 | var collector = tree;
382 | var sections = [];
383 | var token, section;
384 |
385 | for (var i = 0; i < tokens.length; ++i) {
386 | token = tokens[i];
387 |
388 | switch (token.type) {
389 | case "#":
390 | case "^":
391 | token.tokens = [];
392 | sections.push(token);
393 | collector.push(token);
394 | collector = token.tokens;
395 | break;
396 | case "/":
397 | if (sections.length === 0) {
398 | throw new Error("Unopened section: " + token.value);
399 | }
400 |
401 | section = sections.pop();
402 |
403 | if (section.value !== token.value) {
404 | throw new Error("Unclosed section: " + section.value);
405 | }
406 |
407 | if (sections.length > 0) {
408 | collector = sections[sections.length - 1].tokens;
409 | } else {
410 | collector = tree;
411 | }
412 | break;
413 | default:
414 | collector.push(token);
415 | }
416 | }
417 |
418 | // Make sure there were no open sections when we're done.
419 | section = sections.pop();
420 |
421 | if (section) {
422 | throw new Error("Unclosed section: " + section.value);
423 | }
424 |
425 | return tree;
426 | }
427 |
428 | /**
429 | * Combines the values of consecutive text tokens in the given `tokens` array
430 | * to a single token.
431 | */
432 | function squashTokens(tokens) {
433 | var lastToken;
434 |
435 | for (var i = 0; i < tokens.length; ++i) {
436 | var token = tokens[i];
437 |
438 | if (lastToken && lastToken.type === "text" && token.type === "text") {
439 | lastToken.value += token.value;
440 | tokens.splice(i--, 1); // Remove this token from the array.
441 | } else {
442 | lastToken = token;
443 | }
444 | }
445 | }
446 |
447 | /**
448 | * Breaks up the given `template` string into a tree of token objects. If
449 | * `tags` is given here it must be an array with two string values: the
450 | * opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
451 | * course, the default is to use mustaches (i.e. Mustache.tags).
452 | */
453 | function parse(template, tags) {
454 | tags = tags || exports.tags;
455 | var tagRes = escapeTags(tags);
456 |
457 | var scanner = new Scanner(template);
458 |
459 | var tokens = [], // Buffer to hold the tokens
460 | spaces = [], // Indices of whitespace tokens on the current line
461 | hasTag = false, // Is there a {{tag}} on the current line?
462 | nonSpace = false; // Is there a non-space char on the current line?
463 |
464 | // Strips all whitespace tokens array for the current line
465 | // if there was a {{#tag}} on it and otherwise only space.
466 | var stripSpace = function () {
467 | if (hasTag && !nonSpace) {
468 | while (spaces.length) {
469 | tokens.splice(spaces.pop(), 1);
470 | }
471 | } else {
472 | spaces = [];
473 | }
474 |
475 | hasTag = false;
476 | nonSpace = false;
477 | };
478 |
479 | var type, value, chr;
480 |
481 | while (!scanner.eos()) {
482 | value = scanner.scanUntil(tagRes[0]);
483 |
484 | if (value) {
485 | for (var i = 0, len = value.length; i < len; ++i) {
486 | chr = value[i];
487 |
488 | if (isWhitespace(chr)) {
489 | spaces.push(tokens.length);
490 | } else {
491 | nonSpace = true;
492 | }
493 |
494 | tokens.push({type: "text", value: chr});
495 |
496 | if (chr === "\n") {
497 | stripSpace(); // Check for whitespace on the current line.
498 | }
499 | }
500 | }
501 |
502 | // Match the opening tag.
503 | if (!scanner.scan(tagRes[0])) {
504 | break;
505 | }
506 |
507 | hasTag = true;
508 | type = scanner.scan(tagRe) || "name";
509 |
510 | // Skip any whitespace between tag and value.
511 | scanner.scan(whiteRe);
512 |
513 | // Extract the tag value.
514 | if (type === "=") {
515 | value = scanner.scanUntil(eqRe);
516 | scanner.scan(eqRe);
517 | scanner.scanUntil(tagRes[1]);
518 | } else if (type === "{") {
519 | var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1]));
520 | value = scanner.scanUntil(closeRe);
521 | scanner.scan(curlyRe);
522 | scanner.scanUntil(tagRes[1]);
523 | } else {
524 | value = scanner.scanUntil(tagRes[1]);
525 | }
526 |
527 | // Match the closing tag.
528 | if (!scanner.scan(tagRes[1])) {
529 | throw new Error("Unclosed tag at " + scanner.pos);
530 | }
531 |
532 | tokens.push({type: type, value: value});
533 |
534 | if (type === "name" || type === "{" || type === "&") {
535 | nonSpace = true;
536 | }
537 |
538 | // Set the tags for the next time around.
539 | if (type === "=") {
540 | tags = value.split(spaceRe);
541 | tagRes = escapeTags(tags);
542 | }
543 | }
544 |
545 | squashTokens(tokens);
546 |
547 | return nestTokens(tokens);
548 | }
549 |
550 | // The high-level clearCache, compile, compilePartial, and render functions
551 | // use this default renderer.
552 | var _renderer = new Renderer;
553 |
554 | /**
555 | * Clears all cached templates and partials.
556 | */
557 | function clearCache() {
558 | _renderer.clearCache();
559 | }
560 |
561 | /**
562 | * High-level API for compiling the given `tokens` down to a reusable
563 | * function. If `tokens` is a string it will be parsed using the given `tags`
564 | * before it is compiled.
565 | */
566 | function compile(tokens, tags) {
567 | return _renderer.compile(tokens, tags);
568 | }
569 |
570 | /**
571 | * High-level API for compiling the `tokens` for the partial with the given
572 | * `name` down to a reusable function. If `tokens` is a string it will be
573 | * parsed using the given `tags` before it is compiled.
574 | */
575 | function compilePartial(name, tokens, tags) {
576 | return _renderer.compilePartial(name, tokens, tags);
577 | }
578 |
579 | /**
580 | * High-level API for rendering the `template` using the given `view`. The
581 | * optional `partials` object may be given here for convenience, but note that
582 | * it will cause all partials to be re-compiled, thus hurting performance. Of
583 | * course, this only matters if you're going to render the same template more
584 | * than once. If so, it is best to call `compilePartial` before calling this
585 | * function and to leave the `partials` argument blank.
586 | */
587 | function render(template, view, partials) {
588 | if (partials) {
589 | for (var name in partials) {
590 | compilePartial(name, partials[name]);
591 | }
592 | }
593 |
594 | return _renderer.render(template, view);
595 | }
596 |
597 | })(Mustache);
--------------------------------------------------------------------------------
/mustache/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
114 |
115 |
116 | First Timer:
117 |
118 |
119 | Remembering:
120 |
121 |
122 | Experimenting/ Playing:
123 |
124 |
125 |
126 | Diving:
127 |
128 |
129 |
130 | Using HTML:
131 |
132 |
133 |
134 |
135 |
155 |
156 |
170 |
171 |
186 |
187 |
196 |
197 | No templates:
198 |
199 |
200 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## Tutorials
2 |
3 | A collection of code examples from the articles that I have used in my [blog](http://wernancheta.com).
4 |
5 |
6 | ## Donation
7 |
8 | If this project helped you reduce time to develop, please consider buying me a cup of coffee :)
9 |
10 |
11 |
--------------------------------------------------------------------------------
/registration_system_using_knockoutjs/refresher.css:
--------------------------------------------------------------------------------
1 | .new_student {
2 | margin-bottom: 20px;
3 | }
4 |
5 | td, th {
6 | padding: 10px;
7 | }
8 |
9 | .container {
10 | padding: 16px;
11 | }
12 |
13 | thead {
14 | background-color: #ccc;
15 | }
16 |
17 | td {
18 | background-color: #dee;
19 | }
20 |
21 | .age {
22 | width: 37px;
23 | }
24 |
25 | .name {
26 | width: 218px;
27 | }
--------------------------------------------------------------------------------
/registration_system_using_knockoutjs/refresher.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
40 |
41 |
42 |
43 |
44 |
161 |
--------------------------------------------------------------------------------
/registration_system_using_knockoutjs/refresher_save.php:
--------------------------------------------------------------------------------
1 | query("INSERT INTO students SET name = '$name', age = '$age'");
18 | echo $db->insert_id; //last insert id
19 | break;
20 |
21 | case 'update':
22 |
23 | $id = $student['id'];
24 | $db->query("UPDATE students SET name = '$name', age = '$age' WHERE id = '$id'");
25 | break;
26 |
27 | case 'delete':
28 |
29 | $id = $_POST['student_id'];
30 | $db->query("UPDATE students SET status = 0 WHERE id = '$id'");
31 | break;
32 |
33 | default:
34 | $students = $db->query("SELECT * FROM students WHERE status = 1");
35 | $students_r = array();
36 | while($row = $students->fetch_array()){
37 |
38 | $id = $row['id'];
39 | $name = $row['name'];
40 | $age = $row['age'];
41 | $name_update = false;
42 | $age_update = false;
43 | $name_focus = false;
44 | $age_focus = false;
45 |
46 | $students_r[] = array(
47 | 'id' => $id, 'name' => $name, 'age' => $age,
48 | 'nameUpdate' => $name_update, 'ageUpdate' => $age_update,
49 | 'nameHasFocus' => $name_focus, 'ageHasFocus' => $age_focus
50 | );
51 | }
52 |
53 | echo json_encode($students_r);
54 | break;
55 | }
56 | ?>
--------------------------------------------------------------------------------
/storejs/store.js:
--------------------------------------------------------------------------------
1 | //
2 | // store.js by Frank Kohlhepp
3 | // Copyright (c) 2011 - 2012 Frank Kohlhepp
4 | // https://github.com/frankkohlhepp/store-js
5 | // License: MIT-license
6 | //
7 | (function () {
8 | var has = function (object, key) {
9 | return Object.prototype.hasOwnProperty.call(object, key);
10 | };
11 |
12 | var objectGetLength = function (object) {
13 | var count = 0;
14 | for (var key in object) {
15 | if (has(object, key)) { count++; }
16 | }
17 |
18 | return count;
19 | };
20 |
21 | var arrayIndexOf = function (array, item, from) {
22 | var length = array.length >>> 0;
23 | for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
24 | if (array[i] === item) { return i; }
25 | }
26 |
27 | return -1;
28 | };
29 |
30 | var arrayContains = function (array, item, from) {
31 | return arrayIndexOf(array, item, from) !== -1;
32 | };
33 |
34 | var arrayInclude = function (array, item) {
35 | if (!arrayContains(array, item)) { array.push(item); }
36 | return array;
37 | };
38 |
39 | var Store = this.Store = function (name, defaults, watcherSpeed) {
40 | this.name = name;
41 | this.defaults = defaults || {};
42 | this.watcherSpeed = watcherSpeed || 500;
43 | this.listeners = {};
44 |
45 | // Apply defaults
46 | this.applyDefaults();
47 | };
48 |
49 | Store.clear = function () {
50 | localStorage.clear();
51 | };
52 |
53 | Store.prototype.applyDefaults = function () {
54 | for (var key in this.defaults) {
55 | if (has(this.defaults, key) && this.get(key) === undefined) {
56 | this.set(key, this.defaults[key]);
57 | }
58 | }
59 |
60 | return this;
61 | };
62 |
63 | Store.prototype.watcher = function (force) {
64 | if (this.watcherTimer) {
65 | clearTimeout(this.watcherTimer);
66 | }
67 |
68 | if (objectGetLength(this.listeners) || force) {
69 | this.newObject = this.toObject();
70 |
71 | if (this.oldObject) {
72 | for (var key in this.newObject) {
73 | if (has(this.newObject, key) && this.newObject[key] !== this.oldObject[key]) {
74 | this.fireEvent(key, this.newObject[key]);
75 | }
76 | }
77 |
78 | for (var key in this.oldObject) {
79 | if (has(this.oldObject, key) && !has(this.newObject, key)) {
80 | this.fireEvent(key, this.newObject[key]);
81 | }
82 | }
83 | }
84 |
85 | this.oldObject = this.newObject;
86 | var that = this;
87 | this.watcherTimer = setTimeout(function () {
88 | that.watcher();
89 | }, this.watcherSpeed);
90 | }
91 |
92 | return this;
93 | };
94 |
95 | Store.prototype.get = function (name) {
96 | var value = localStorage.getItem("store." + this.name + "." + name);
97 | if (value === null) { return undefined; }
98 | try { return JSON.parse(value); } catch (e) { return null; }
99 | };
100 |
101 | Store.prototype.set = function (name, value) {
102 | if (value === undefined) {
103 | this.remove(name);
104 | } else {
105 | if (typeof value === "function") { value = null; }
106 | try { value = JSON.stringify(value); } catch (e) { value = null; }
107 | localStorage.setItem("store." + this.name + "." + name, value);
108 | }
109 |
110 | return this;
111 | };
112 |
113 | Store.prototype.remove = function (name) {
114 | localStorage.removeItem("store." + this.name + "." + name);
115 | return this.applyDefaults();
116 | };
117 |
118 | Store.prototype.reset = function () {
119 | var name = "store." + this.name + ".";
120 | for (var i = (localStorage.length - 1); i >= 0; i--) {
121 | if (localStorage.key(i).substring(0, name.length) === name) {
122 | localStorage.removeItem(localStorage.key(i));
123 | }
124 | }
125 |
126 | return this.applyDefaults();
127 | };
128 |
129 | Store.prototype.toObject = function () {
130 | var values = {};
131 | var name = "store." + this.name + ".";
132 | for (var i = (localStorage.length - 1); i >= 0; i--) {
133 | if (localStorage.key(i).substring(0, name.length) === name) {
134 | var key = localStorage.key(i).substring(name.length);
135 | var value = this.get(key);
136 | if (value !== undefined) { values[key] = value; }
137 | }
138 | }
139 |
140 | return values;
141 | };
142 |
143 | Store.prototype.fromObject = function (values, merge) {
144 | if (!merge) { this.reset(); }
145 | for (var key in values) {
146 | if (has(values, key)) {
147 | this.set(key, values[key]);
148 | }
149 | }
150 |
151 | return this;
152 | };
153 |
154 | Store.prototype.addEvent = function (selector, callback) {
155 | this.watcher(true);
156 | if (!this.listeners[selector]) { this.listeners[selector] = []; }
157 | arrayInclude(this.listeners[selector], callback);
158 | return this;
159 | };
160 |
161 | Store.prototype.removeEvent = function (selector, callback) {
162 | for (var i = (this.listeners[selector].length - 1); i >= 0; i--) {
163 | if (this.listeners[selector][i] === callback) { this.listeners[selector].splice(i, 1); }
164 | }
165 |
166 | if (!this.listeners[selector].length) { delete this.listeners[selector]; }
167 | return this;
168 | };
169 |
170 | Store.prototype.fireEvent = function (name, value) {
171 | var selectors = [name, "*"];
172 | for (var i = 0; i < selectors.length; i++) {
173 | var selector = selectors[i];
174 | if (this.listeners[selector]) {
175 | for (var j = 0; j < this.listeners[selector].length; j++) {
176 | this.listeners[selector][j](value, name, this.name);
177 | }
178 | }
179 | }
180 |
181 | return this;
182 | };
183 | }());
--------------------------------------------------------------------------------
/storejs/teststore.html:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
44 |
45 |
46 |
47 |
133 |
--------------------------------------------------------------------------------
/sugarjs/sugar.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Sugar Library v1.2.5
3 | *
4 | * Freely distributable and licensed under the MIT-style license.
5 | * Copyright (c) 2012 Andrew Plummer
6 | * http://sugarjs.com/
7 | *
8 | * ---------------------------- */
9 | (function(context){var i=true,j=null,l=false,n=Object,o=Array,p=RegExp,q=Date,r=String,s=Number,t=n.defineProperty&&n.defineProperties;function v(a,b,c,d){var e=b?a.prototype:a,f;w(a,b,d);x(d,function(g,h){f=e[g];if(typeof c==="function")h=aa(e[g],h,c);if(c!==l||!e[g])y(e,g,h);a.SugarMethods[g]={e:b,method:h,g:f}})}
10 | function w(a){if(!a.SugarMethods){y(a,"SugarMethods",{});v(a,l,l,{restore:function(){var b=arguments.length===0,c=z(arguments);x(a.SugarMethods,function(d,e){if(b||c.has(d))y(e.e?a.prototype:a,d,e.method)})},extend:function(b,c,d){a===n&&arguments.length===0?A(C.concat(D),Object):v(a,d!==l,c,b)}})}}function aa(a,b,c){return function(){return a&&(c===i||!c.apply(this,arguments))?a.apply(this,arguments):b.apply(this,arguments)}}
11 | function y(a,b,c){if(t)n.defineProperty(a,b,{value:c,configurable:i,enumerable:l,writable:i});else a[b]=c}function x(a,b){for(var c in a)n.prototype.hasOwnProperty.call(a,c)&&b.call(a,c,a[c])}function E(a,b,c,d){var e=i;if(a===b)return i;else if(n.isRegExp(b))return p(b).test(a);else if(n.isFunction(b))return b.apply(c,[a].concat(d));else if(n.isObject(b)&&n.isObject(a)){x(b,function(f){E(a[f],b[f],c,d)||(e=l)});return!n.isEmpty(b)&&e}else return n.equal(a,b)}
12 | function F(a,b){var c,d,e,f,g,h,k=typeof a;if(k==="string")return a;d=n.prototype.toString.call(a);c=d==="[object Object]";e=d==="[object Array]";if(a!=j&&c||e){b||(b=[]);if(b.length>1)for(g=b.length;g--;)if(b[g]===a)return"CYC";b.push(a);c=r(a.constructor);f=e?a:n.keys(a).sort();for(g=0;g0);return n.keys(a).length==0},equal:function(a,b){return F(a)===F(b)},values:function(a,b){var c=[];x(a,function(d,e){c.push(e);b&&b.call(a,e)});return c},clone:function(a,b){if(a==j||typeof a!=="object")return a;if(o.isArray(a))return a.clone();var c=a.constructor===
18 | M?new M:{};return n.merge(c,a,b)},fromQueryString:function(a,b){var c=n.extended();a=a&&a.toString?a.toString():"";a.replace(/^.*?\?/,"").unescapeURL().split("&").each(function(d){d=d.split("=");d.length===2&&ca(c,d[0],d[1],b)});return c},tap:function(a,b){G(a,b,a,[a]);return a},has:function(a,b){return n.prototype.hasOwnProperty.call(a,b)}});
19 | v(n,l,function(){return arguments.length>1},{keys:function(a,b){if(a==j||typeof a!="object"&&!n.isRegExp(a)&&!n.isFunction(a))throw new TypeError("Object required");var c=[];x(a,function(d,e){c.push(d);b&&b.call(a,d,e)});return c}});function K(a,b,c,d,e){var f,g;N(b);if(c<0)c=a.length+c;g=isNaN(c)?0:parseInt(c>>0);for(c=d===i?a.length+g:a.length;g>0);if(c<0)c=e+c;if(!f&&c<0||f&&c>=e)c=g;for(;f&&c>=0||!f&&c>>0==e&&e!=4294967295&&e>=c&&d.push(e.toNumber());d.sort().each(function(f){return b.call(a,a[f],f,a)});return a}function Q(a,b,c,d){var e=c==="max",f=c==="min",g=e?-Infinity:Infinity,h=[];x(a,function(k){var m=a[k];k=G(m,b,a,d?[m,k.toNumber(),a]:[]);if(k===g)h.push(m);else if(e&&k>g||f&&k0&&!n.isFunction(a[0])},{every:function(a,b){var c=this.length,d=0;for(P(arguments);d0?a.reduce(function(b,c){return b+c}):0},average:function(a){a=a?this.map(a):this;return a.length>0?a.sum()/a.length:0},groupBy:function(a,b){var c=this,d=n.extended(),e;K(c,function(f,g){e=G(f,a,c,[f,g,c]);d[e]||(d[e]=[]);d[e].push(f)});return d.each(b)},inGroups:function(a,b){var c=
32 | arguments.length>1,d=this,e=[],f=(this.length/a).ceil();(0).upto(a-1,function(g){g=g*f;var h=d.slice(g,g+f);c&&h.length0&&c.push(d);return c},
33 | compact:function(a){var b=[];K(this,function(c){if(n.isArray(c))b.push(c.compact());else if(a&&c)b.push(c);else!a&&c!=j&&!n.isNaN(c)&&b.push(c)});return b},isEmpty:function(){return this.compact().length==0},flatten:function(a){return J(this,a)},sortBy:function(a,b){var c=this.clone();c.sort(function(d,e){var f,g;f=G(d,a,c,[d]);g=G(e,a,c,[e]);if(n.isString(f)&&n.isString(g)){f=f;g=g;var h,k,m,u,B=0,R=0;f=ia(f);g=ia(g);do{m=la(f,B);u=la(g,B);h=m?o.AlphanumericSortOrder.indexOf(m):j;k=u?o.AlphanumericSortOrder.indexOf(u):
34 | j;if(h===-1||k===-1){h=f.charCodeAt(B)||j;k=g.charCodeAt(B)||j}m=m!==f.charAt(B);u=u!==g.charAt(B);if(m!==u&&R===0)R=m-u;B+=1}while(h!=j&&k!=j&&h===k);f=h===k?R:hg?1:0;return f*(b?-1:1)});return c},randomize:function(){for(var a=this.concat(),b,c,d=a.length;d;b=parseInt(Math.random()*d),c=a[--d],a[d]=a[b],a[b]=c);return a},zip:function(){var a=I(arguments);return this.map(function(b,c){return[b].concat(a.map(function(d){return c in d?d[c]:j}))})},sample:function(a){var b=[],
35 | c=this.clone(),d;for(a>0||(a=1);b.length0?b:b[0]}});v(o,i,l,{all:o.prototype.every,any:o.prototype.some,has:o.prototype.some,insert:o.prototype.add});function S(a,b,c){c=Math[c||"round"];var d=Math.pow(10,(b||0).abs());if(b<0)d=1/d;return c(a*d)/d}function na(a,b,c,d){var e=[];a=parseInt(a);for(var f=d>0;f&&a<=b||!f&&a>=b;){e.push(a);c&&c.call(this,a);a+=d}return e}
36 | function T(a,b,c,d,e,f){var g=a.toFixed(20),h=g.search(/\./);g=g.search(/[1-9]/);h=h-g;if(h>0)h-=1;e=Math.max(Math.min((h/3).floor(),e===l?c.length:e),-d);d=c.charAt(e+d-1);if(h<-9){e=-3;b=h.abs()-9;d=c.first()}return(a/(f?(2).pow(10*e):(10).pow(e*3))).round(b||0).format()+d.trim()}v(s,l,l,{random:function(a,b){var c;if(arguments.length==1){b=a;a=0}c=Math.min(a||0,H(b)?1:b);return S(Math.random()*(Math.max(a||0,H(b)?1:b)-c)+c)}});
37 | v(s,i,l,{toNumber:function(){return parseFloat(this,10)},abbr:function(a){return T(this,a,"kmbt",0,4)},metric:function(a,b){return T(this,a,"n\u03bcm kMGTPE",4,H(b)?1:b)},bytes:function(a,b){return T(this,a,"kMGTPE",0,H(b)?4:b,i)+"B"},isInteger:function(){return this%1==0},ceil:function(a){return S(this,a,"ceil")},floor:function(a){return S(this,a,"floor")},abs:function(){return Math.abs(this)},pow:function(a){if(H(a))a=1;return Math.pow(this,a)},round:function(a){return S(this,a,"round")},chr:function(){return r.fromCharCode(this)},
38 | isOdd:function(){return!this.isMultipleOf(2)},isEven:function(){return this.isMultipleOf(2)},isMultipleOf:function(a){return this%a===0},upto:function(a,b,c){return na(this,a,b,c||1)},downto:function(a,b,c){return na(this,a,b,-(c||1))},times:function(a){if(a)for(var b=0;b=11&&b<=13)a="th";else switch(a%10){case 1:a="st";break;case 2:a="nd";break;case 3:a="rd";break;
39 | default:a="th"}return this.toString()+a},pad:function(a,b,c){c=c||10;c=this.toNumber()===0?"":this.toString(c).replace(/^-/,"");c=U(c,"0",a-c.replace(/\.\d+$/,"").length,0);if(b||this<0)c=(this<0?"-":"+")+c;return c},format:function(a,b,c){var d,e,f=/(\d+)(\d{3})/;if(r(b).match(/\d/))throw new TypeError("Thousands separator cannot contain numbers.");d=n.isNumber(a)?S(this,a).toFixed(Math.max(a,0)):this.toString();b=b||",";c=c||".";e=d.split(".");d=e[0];for(e=e[1]||"";d.match(f);)d=d.replace(f,"$1"+
40 | b+"$2");if(e.length>0)d+=c+U(e,"0",0,a-e.length);return d},hex:function(a){return this.pad(a||1,l,16)}});function V(){return"\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u2028\u2029\u3000\ufeff"}function oa(a,b,c,d){var e=I(b).join("");e=e.replace(/all/,"").replace(/(\w)lphabet|umbers?|atakana|paces?|unctuation/g,"$1");return a.replace(c,function(f){return d[f]&&(!e||e.has(d[f].type))?d[f].to:f})}
41 | var pa=[{type:"a",shift:65248,start:65,end:90},{type:"a",shift:65248,start:97,end:122},{type:"n",shift:65248,start:48,end:57},{type:"p",shift:65248,start:33,end:47},{type:"p",shift:65248,start:58,end:64},{type:"p",shift:65248,start:91,end:96},{type:"p",shift:65248,start:123,end:126}],qa={},ra={},sa=/[\u0020-\u00A5]|[\uFF61-\uFF9F][\uff9e\uff9f]?/g,ta=/[\u3000-\u301C]|[\u301A-\u30FC]|[\uFF01-\uFF60]|[\uFFE0-\uFFE6]/g,ua=/[\u30ab\u30ad\u30af\u30b1\u30b3\u30b5\u30b7\u30b9\u30bb\u30bd\u30bf\u30c1\u30c4\u30c6\u30c8\u30cf\u30d2\u30d5\u30d8\u30db]/,
42 | va=/[\u30cf\u30d2\u30d5\u30d8\u30db\u30f2]/;function W(a,b,c){qa[b]={type:a,to:c};ra[c]={type:a,to:b}}function U(a,b,c,d){var e=String(b);if(e!=b)e="";n.isNumber(c)||(c=1);n.isNumber(d)||(d=1);return e.repeat(c)+a+e.repeat(d)}var X,Y;
43 | v(r,i,l,{escapeRegExp:function(){return p.escape(this)},escapeURL:function(a){return a?encodeURIComponent(this):encodeURI(this)},unescapeURL:function(a){return a?decodeURI(this):decodeURIComponent(this)},escapeHTML:function(){return this.replace(/&/g,"&").replace(//g,">")},unescapeHTML:function(){return this.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")},encodeBase64:function(){return X(this)},decodeBase64:function(){return Y(this)},capitalize:function(a){return this.toLowerCase().replace(a?
44 | /^\S|\s\S/g:/^\S/,function(b){return b.toUpperCase()})},pad:function(a,b){return U(this,a,b,b)},padLeft:function(a,b){return U(this,a,b,0)},padRight:function(a,b){return U(this,a,0,b)},repeat:function(a){var b="",c=0;if(n.isNumber(a)&&a>0)for(;c0?"_":"")+a.toLowerCase()}).replace(/([A-Z\d]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").toLowerCase()},camelize:function(a){return this.underscore().replace(/(^|_)([^_]+)/g,function(b,c,d,e){b=r.Inflector&&r.Inflector.acronyms&&r.Inflector.acronyms[d];e=a!==l||e>0;if(b)return e?b:b.toLowerCase();return e?d.capitalize():d})},spacify:function(){return this.underscore().replace(/_/g," ")},stripTags:function(){var a=
50 | this;z(arguments.length>0?arguments:[""],function(b){a=a.replace(p("?"+b.escapeRegExp()+"[^<>]*>","gi"),"")});return a},removeTags:function(){var a=this;z(arguments.length>0?arguments:["\\S+"],function(b){b=p("<("+b+")[^<>]*(?:\\/>|>.*?<\\/\\1>)","gi");a=a.replace(b,"")});return a},truncate:function(a,b,c,d){var e="",f="",g=this.toString(),h="["+V()+"]+",k="[^"+V()+"]*",m=p(h+k+"$");d=H(d)?"...":r(d);if(g.length<=a)return g;switch(c){case "left":a=g.length-a;e=d;g=g.slice(a);m=p("^"+k+h);break;
51 | case "middle":a=Math.floor(a/2);f=d+g.slice(g.length-a).trimLeft();g=g.slice(0,a);break;default:a=a;f=d;g=g.slice(0,a)}if(b===l&&this.slice(a,a+1).match(/\S/))g=g.remove(m);return e+g+f},assign:function(){var a=n.extended();z(arguments,function(b,c){if(n.isObject(b))a.merge(b);else a[c+1]=b});return this.replace(/\{(.+?)\}/g,function(b,c){return n.prototype.hasOwnProperty.call(a,c)?a[c]:b})}});
52 | v(r,i,function(a){return n.isRegExp(a)},{split:function(a,b){var c=[],d=0;a=p(a).addFlag("g");var e,f,g,h;p.c||(e=RegExp("^"+a.source+"$(?!\\s)",a.getFlags()));if(H(b)||b<0)b=Infinity;else{b|=0;if(!b)return[]}for(;f=a.exec(this);){g=f.index+f[0].length;if(g>d){c.push(this.slice(d,f.index));!p.c&&f.length>1&&f[0].replace(e,function(){for(var k=1;k1&&f.index=
53 | b)break}a.lastIndex===f.index&&a.lastIndex++}if(d===this.length){if(h||!a.test(""))c.push("")}else c.push(this.slice(d));return c.length>b?c.slice(0,b):c}});v(r,i,l,{insert:r.prototype.add});p.c=H(p("()??").exec("")[1]);function Z(a,b){var c="";if(b=="g"||a.global)c+="g";if(b=="i"||a.ignoreCase)c+="i";if(b=="m"||a.multiline)c+="m";if(b=="y"||a.h)c+="y";return c}v(p,l,l,{escape:function(a){n.isString(a)||(a=String(a));return a.replace(/([\\/'*+?|()\[\]{}.^$])/g,"\\$1")}});
54 | v(p,i,l,{getFlags:function(){return Z(this)},setFlags:function(a){return p(this.source,a)},addFlag:function(a){return this.setFlags(Z(this,a))},removeFlag:function(a){return this.setFlags(Z(this).replace(a,""))}});function $(a,b,c,d,e){if(!a.b)a.b=[];n.isNumber(b)||(b=0);a.b.push(setTimeout(function(){a.b.removeAt(f);c.apply(d,e||[])},b));var f=a.b.length}
55 | v(Function,i,l,{lazy:function(a,b){function c(){if(!(f&&e.length>b-2)){e.push([this,arguments]);g()}}var d=this,e=[],f=l,g,h,k;a=a||1;b=b||Infinity;h=a.ceil();k=S(h/a);g=function(){if(!(f||e.length==0)){for(var m=Math.max(e.length-k,0);e.length>m;)Function.prototype.apply.apply(d,e.shift());$(c,h,function(){f=l;g()});f=i}};return c},delay:function(a){var b=I(arguments,1);$(this,a,this,this,b);return this},throttle:function(a){return this.lazy(a,1)},debounce:function(a){var b=this;return function(){b.cancel();
56 | $(b,a,b,this,arguments)}},cancel:function(){if(n.isArray(this.b))for(;this.b.length>0;)clearTimeout(this.b.shift());return this},after:function(a){var b=this,c=0,d=[];if(n.isNumber(a)){if(a===0){b.call();return b}}else a=1;return function(){var e;d.push(Array.create(arguments));c++;if(c==a){e=b.call(this,d);c=0;d=[];return e}}},once:function(){var a=this;return function(){return n.prototype.hasOwnProperty.call(a,"memo")?a.memo:a.memo=a.apply(this,arguments)}},fill:function(){var a=this,b=I(arguments);
57 | return function(){var c=I(arguments);K(b,function(d,e){if(d!=j||e>=c.length)c.splice(e,0,d)});return a.apply(this,c)}}});(function(){var a={},b;K(["Array","Boolean","Date","Function","Number","String","RegExp"],function(c){b="is"+c;C.push(b);a[b]=function(d){return L(d,c)}});v(Object,l,l,a)})();A(D,M);
58 | (function(a){if(this.btoa){X=this.btoa;Y=this.atob}var b=/[^A-Za-z0-9\+\/\=]/g;X=function(c){var d="",e,f,g,h,k,m,u=0;do{e=c.charCodeAt(u++);f=c.charCodeAt(u++);g=c.charCodeAt(u++);h=e>>2;e=(e&3)<<4|f>>4;k=(f&15)<<2|g>>6;m=g&63;if(isNaN(f))k=m=64;else if(isNaN(g))m=64;d=d+a.charAt(h)+a.charAt(e)+a.charAt(k)+a.charAt(m)}while(u>4;f=(f&15)<<4|h>>2;g=(h&3)<<6|k;d+=e.chr();if(h!=64)d+=f.chr();if(k!=64)d+=g.chr()}while(m0)d.digits+=d.numbers.join("");
88 | else d.numbers=x.split("");d.monthSuffix=e[1]}d.capitalizeUnit=a=="de";d.hasPlural=b(2);d.pastRelativeFormat=d.formats[0];d.futureRelativeFormat=d.formats[b(3)?1:0];d.durationFormat=d.formats[0].replace(/\s*\{sign\}\s*/,"");return d}function R(a){a||(a=Date.currentLocale);return a!="en"&&a!="en-US"}function Q(a){q.merge(this,a)}
89 | q.merge(Q.prototype,{getMonth:function(a){return q.isNumber(a)?a-1:this.months.findIndex(p(a,"i"))%12},l:function(a){return this.weekdays.findIndex(p(a,"i"))%7},k:function(a){var b;return q.isNumber(a)?a:a&&(b=this.numbers.indexOf(a))!==-1?(b+1)%10:1},o:function(a){var b=this;return a.replace(this.numbers[9],"").each(function(d){return b.k(d)}).join("")},n:function(a){return u.units[this.units.indexOf(a)%8]},r:function(a){return this.j(a,a[2]>0?"futureRelativeFormat":"pastRelativeFormat")},duration:function(a){return this.j(T(a),
90 | "durationFormat")},j:function(a,b){var d=a[0],e=a[1],g=a[2],f;if(this.code=="ru"){f=d.toString().from(-1);switch(j){case f==1:f=1;break;case f>=2&&f<=4:f=2;break;default:f=3}}else f=this.hasPlural&&d>1?1:0;f=this.units[f*8+e]||this.units[e];if(this.capitalizeUnit)f=f.capitalize();e=this.modifiers.find(function(h){return h.name=="sign"&&h.value==(g>0?1:-1)});return this[b].assign({num:d,unit:f,sign:e.src})},addFormat:function(a,b,d){var e=[],g=this;d!==k&&g.u.push(a);a=a.replace(/\s+/g,"[-,. ]*");
91 | a=a.replace(/\{(.+?)\}/g,function(f,h){var c=h.match(/\?$/),i=h.match(/(\d)(?:-(\d))?/),m=h.match(/^\d+$/),l=h.replace(/[^a-z]+$/,""),n,r;if(l==="time"){e=e.concat(w);return c?"\\s*(?:(?:t|at |\\s+)(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?)?":"(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?"}if(m)n=g.optionals[m[0]];else if(g[l])n=g[l];
92 | else if(g[l+"s"]){n=g[l+"s"];if(i){r=[];n.forEach(function(z,H){var A=H%(g.units?8:n.length);if(A>=i[1]&&A<=(i[2]||i[1]))r.push(z)});n=r}n=n.compact().join("|")}if(m)return"(?:"+n+")?";else{e.push(l);return"("+n+")"+(c?"?":"")}});M(a,e,b)}});function U(a){var b;if(q.isObject(a[0]))return a;else if(a.length==1&&q.isNumber(a[0]))return[a[0]];b={};D.each(function(d,e){b[d.a]=a[e]});return[b]}
93 | function aa(a,b){if(b!="date"&&b!="month"&&b!="year")return a;return a.replace(B,function(d){return x.indexOf(d)+1||""})}function ba(a,b){var d={},e,g;b.each(function(f,h){e=a[h+1];if(!(e===void 0||e==="")){e=aa(e.hankaku("n"),f);if(f==="year")d.t=e;g=parseFloat(e.replace(/,/,"."));d[f]=!isNaN(g)?g:e.toLowerCase()}});return d}
94 | function V(a,b){var d=new s,e=k,g,f,h,c,i,m,l;if(q.isDate(a))d=a;else if(q.isNumber(a))d=new s(a);else if(q.isObject(a)){d=(new s).set(a,j);c=a}else if(q.isString(a)){L(N(b,j));f=R(b);a=a.trim().replace(/\.+$/,"").replace(/^now$/,"");C.each(function(n){var r=a.match(n.q);if(r){h=n;c=ba(r,h.to);g=N(h.p,j);if(c.timestamp){d.setTime(0);c={milliseconds:c.timestamp};return k}if(h.h&&!q.isString(c.month)&&(q.isString(c.date)||f)){l=c.month;c.month=c.date;c.date=l}if(c.year&&c.t.length===2)c.year=((new s).getFullYear()/
95 | 100).round()*100-(c.year/100).round()*100+c.year;if(c.month){c.month=g.getMonth(c.month);if(c.shift&&!c.unit)c.unit="year"}if(c.weekday&&c.date)delete c.weekday;else if(c.weekday){c.weekday=g.l(c.weekday);if(c.shift&&!c.unit)c.unit="week"}if(c.day&&(l=g.f[c.day])){c.day=l.value;d.resetTime();e=j}else if(c.day&&(l=g.l(c.day))>-1){delete c.day;c.weekday=l}if(c.date&&!q.isNumber(c.date))c.date=g.o(c.date);if(c.meridian)if(c.meridian==="pm"&&c.hour<12)c.hour+=12;if("offset_hours"in c||"offset_minutes"in
96 | c){c.utc=j;c.offset_minutes=c.offset_minutes||0;c.offset_minutes+=c.offset_hours*60;if(c.offset_sign==="-")c.offset_minutes*=-1;c.minute-=c.offset_minutes}if(c.unit){e=j;m=g.k(c.num);i=g.n(c.unit);if(c.shift||c.edge){m*=(l=g.f[c.shift])?l.value:0;if(i==="month"&&v(c.date)){d.set({day:c.date},j);delete c.date}if(i==="year"&&v(c.month)){d.set({month:c.month,day:c.date},j);delete c.month;delete c.date}}if(c.sign&&(l=g.f[c.sign]))m*=l.value;if(v(c.weekday)){d.set({weekday:c.weekday},j);delete c.weekday}c[i]=
97 | (c[i]||0)+m}if(c.year_sign==="-")c.year*=-1;E.slice(1,4).each(function(z,H){var A=c[z.a],S=A%1;if(S){c[E[H].a]=(S*(z.a==="second"?1E3:60)).round();c[z.a]=A|0}});return k}});if(h)if(e)d.advance(c);else if(c.utc){d.resetTime();d.setUTC(c,j)}else d.set(c,j);else d=a?new s(a):new s;if(c&&c.edge){l=g.f[c.edge];E.slice(4).each(function(n){if(v(c[n.a])){i=n.a;return k}});if(i==="year")c.d="month";else if(i==="month"||i==="week")c.d="day";d[(l.value<0?"endOf":"beginningOf")+i.capitalize()]();l.value===-2&&
98 | d.resetTime()}}return{e:d,set:c}}
99 | function W(a,b,d,e){var g,f=N(e,j),h=p(/^[A-Z]/);if(a.isValid())if(Date[b])b=Date[b];else{if(q.isFunction(b)){g=T(a.millisecondsFromNow());b=b.apply(a,g.concat(f))}}else return"Invalid Date";if(!b&&!d)b=f.outputFormat;else if(!b&&d){g=g||T(a.millisecondsFromNow());if(g[1]===0){g[1]=1;g[0]=1}return f.r(g)}G.each(function(c){b=b.replace(p("\\{("+c.b+")(\\d)?\\}",c.i?"i":""),function(i,m,l){i=c.format(a,f,l||1,m);l=m.length;var n=m.match(/^(.)\1+$/);if(c.i){if(l===3)i=i.to(3);if(n||m.match(h))i=i.capitalize()}else if(n&&
100 | !c.text)i=(q.isNumber(i)?i.pad(l):i.toString()).last(l);return i})});return b}function ca(a,b,d){var e=V(b),g=0,f=b=0,h;if(d>0){b=f=d;h=j}if(!e.e.isValid())return k;if(e.set&&e.set.d){I.each(function(i){if(i.a===e.set.d)g=i.c(e.e,a-e.e)-1});if(e.set.edge||e.set.shift)e.e["beginningOf"+e.set.d.capitalize()]();if(!h&&e.set.sign&&e.set.d!="millisecond"){b=50;f=-50}}d=a.getTime();h=e.e.getTime();var c=h+g;if(e.set&&e.set.d=="week"&&(new Date(c+1)).getHours()!=0)c+=s.DSTOffset;return d>=h-b&&d<=c+f}
101 | function X(a,b,d,e,g){if(q.isNumber(b)&&g)b={milliseconds:b};else if(q.isNumber(b)){a.setTime(b);return a}if(b.date)b.day=b.date;if(!g&&b.day===void 0&&v(b.weekday)){a["set"+(e?"UTC":"")+"Weekday"](b.weekday);b.day=a["get"+(e?"UTC":"")+"Date"](void 0);delete b.weekday}E.each(function(f){if(v(b[f.a])||v(b[f.a+"s"])){b.d=f.a;return k}else if(d&&f.a!=="week"&&f.a!=="year")a["set"+(e?"UTC":"")+f.method](f.a==="day"?1:0)});I.each(function(f){var h=f.a;f=f.method;var c=v(b[h])?b[h]:b[h+"s"];if(c!==void 0){if(g){if(h===
102 | "week"){c=(b.day||0)+c*7;f="Date"}c=c*g+a["get"+f](void 0)}a["set"+(e?"UTC":"")+f](c);if(h==="month"){h=c;if(h<0)h+=12;h%12!=a.getMonth()&&a.setDate(0)}}});return a}function Y(a){a.addDays(4-(a.getDay()||7)).resetTime();return 1+(a.daysSince(a.clone().beginningOfYear())/7|0)}function T(a){var b,d=a.abs(),e=d,g=0;E.from(1).each(function(f,h){b=(d/f.c()*10).round()/10|0;if(b>=1){e=b;g=h+1}});return[e,g,a]}function Z(a){var b;b=q.isNumber(a[1])?U(a)[0]:a[0];return V(b,a[1]).e}
103 | function da(a,b){function d(){return(this*b).round()}function e(){return Z(arguments)[f](this)}function g(){return Z(arguments)[f](-this)}var f="add"+a.capitalize()+"s",h={};h[a]=d;h[a+"s"]=d;h[a+"Before"]=g;h[a+"sBefore"]=g;h[a+"Ago"]=g;h[a+"sAgo"]=g;h[a+"After"]=e;h[a+"sAfter"]=e;h[a+"FromNow"]=e;h[a+"sFromNow"]=e;t.extend(h)}
104 | function $(a){var b=new s(s.UTC(1999,11,31)),d={};if(!b[a]||b[a]()!=="1999-12-31T00:00:00.000Z"){d[a]=function(){return W(this.toUTC(),s.ISO8601_DATETIME)};s.extend(d,j)}}s.extend({create:function(){return Z(arguments)},now:function(){return(new s).getTime()},setLocale:function(a,b){var d=N(a,k,b);if(d){Date.currentLocale=a;L(d);return d}},getLocale:function(a){return N(a,j)},addFormat:function(a,b,d,e){M(a,b,d,e,"unshift")}},k,k);
105 | s.extend({set:function(){var a=U(arguments);return X(this,a[0],a[1])},setUTC:function(){var a=U(arguments);return X(this,a[0],a[1],j)},setWeekday:function(a){a===void 0||this.setDate(this.getDate()+a-this.getDay())},setUTCWeekday:function(a){a===void 0||this.setDate(this.getUTCDate()+a-this.getDay())},setWeek:function(a){if(a!==void 0){this.setMonth(0);this.setDate(a*7+1)}},setUTCWeek:function(a){if(a!==void 0){this.setMonth(0);this.setUTCDate(a*7+1)}},getWeek:function(){return Y(this)},getUTCWeek:function(){return Y(this.toUTC())},
106 | getUTCOffset:function(a){var b=this.g?0:this.getTimezoneOffset(),d=a===j?":":"";if(!b&&a)return"Z";return(-b/60).round().pad(2,j)+d+(b%60).pad(2)},toUTC:function(){if(this.g)return this;var a=this.clone().addMinutes(this.getTimezoneOffset());a.g=j;return a},isUTC:function(){return this.g||this.getTimezoneOffset()===0},advance:function(){var a=U(arguments);return X(this,a[0],k,k,1,j)},rewind:function(){var a=U(arguments);return X(this,a[0],k,k,-1)},isValid:function(){return!isNaN(this.getTime())},
107 | isAfter:function(a,b){return this.getTime()>s.create(a).getTime()-(b||0)},isBefore:function(a,b){return this.getTime()e},isLeapYear:function(){var a=this.getFullYear();return a%4===0&&a%100!==0||a%400===0},daysInMonth:function(){return 32-(new s(this.getFullYear(),this.getMonth(),32)).getDate()},format:function(a,
108 | b){return W(this,a,k,b)},relative:function(a,b){if(q.isString(a)){b=a;a=null}return W(this,a,j,b)},is:function(a,b){var d;if(q.isString(a)){a=a.trim().toLowerCase();switch(j){case a==="future":return this.getTime()>(new s).getTime();case a==="past":return this.getTime()<(new s).getTime();case a==="weekday":return this.getDay()>0&&this.getDay()<6;case a==="weekend":return this.getDay()===0||this.getDay()===6;case (d=u.weekdays.indexOf(a)%7)>-1:return this.getDay()===d;case (d=u.months.indexOf(a)%12)>
109 | -1:return this.getMonth()===d}}return ca(this,a,b)},resetTime:function(){return this.set({hour:0,minute:0,second:0,millisecond:0})},clone:function(){return new s(this.getTime())}});s.extend({iso:function(){return this.toISOString()},getWeekday:s.prototype.getDay,getUTCWeekday:s.prototype.getUTCDay});t.extend({duration:function(a){return Date.getLocale(a).duration(this)}});u=s.setLocale("en");
110 | (function(){var a={};I.each(function(b,d){function e(i,m){return((s.create(i,m).getTime()-this.getTime())/c).round()}function g(i,m){return((this.getTime()-s.create(i,m).getTime())/c).round()}var f=b.a,h=f.capitalize(),c=b.c();a[f+"sAgo"]=e;a[f+"sUntil"]=e;a[f+"sSince"]=g;a[f+"sFromNow"]=g;a["add"+h+"s"]=function(i){var m={};m[f]=i;return this.advance(m)};da(f,c);d<3&&["Last","This","Next"].each(function(i){a["is"+i+h]=function(){return this.is(i+" "+f)}});if(d<4){a["beginningOf"+h]=function(){var i=
111 | {};switch(f){case "year":i.year=this.getFullYear();break;case "month":i.month=this.getMonth();break;case "day":i.day=this.getDate();break;case "week":i.weekday=0}return this.set(i,j)};a["endOf"+h]=function(){var i={hours:23,minutes:59,seconds:59,milliseconds:999};switch(f){case "year":i.month=11;i.day=31;break;case "month":i.day=this.daysInMonth();break;case "week":i.weekday=6}return this.set(i,j)}}});s.extend(a)})();
112 | (function(){D=I.clone().removeAt(2);E=I.clone().reverse();var a="\\d{1,2}|"+u.months.join("|");F.each(function(b){M(b.src.replace(/\{month\}/,a)+(b.s===k?"":"\\s*(?:(?:t|at |\\s+)(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?)?"),b.to.concat(w),"en",b.h)});M("(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?",w)})();
113 | (function(){var a={},b=u.weekdays.slice(0,7),d=u.months.slice(0,12);["today","yesterday","tomorrow","weekday","weekend","future","past"].concat(b).concat(d).each(function(e){a["is"+e.capitalize()]=function(){return this.is(e)}});s.extend(a)})();$("toISOString");$("toJSON");
114 | s.extend({DSTOffset:((new s(2E3,6,1)).getTimezoneOffset()-(new s(2E3,0,1)).getTimezoneOffset())*60*1E3,INTERNATIONAL_TIME:"{h}:{mm}:{ss}",RFC1123:"{Dow}, {dd} {Mon} {yyyy} {HH}:{mm}:{ss} {tz}",RFC1036:"{Weekday}, {dd}-{Mon}-{yy} {HH}:{mm}:{ss} {tz}",ISO8601_DATE:"{yyyy}-{MM}-{dd}",ISO8601_DATETIME:"{yyyy}-{MM}-{dd}T{HH}:{mm}:{ss}.{fff}{isotz}"},k,k);})(this);
115 |
--------------------------------------------------------------------------------
/sugarjs/sugartest.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/zam/js/main.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anchetaWern/tutorials/5259e6864d7f5a0a02bbb1f8158dbac90ead065d/zam/js/main.js
--------------------------------------------------------------------------------
/zam/libs/twitteroauth/OAuth.php:
--------------------------------------------------------------------------------
1 | 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 | }
--------------------------------------------------------------------------------
/zam/libs/twitteroauth/twitteroauth.php:
--------------------------------------------------------------------------------
1 | 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 | }
--------------------------------------------------------------------------------
/zam/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 | tests/
17 |
18 |
19 |
--------------------------------------------------------------------------------
/zam/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | installation_housekeeping();
20 | update_option('zam_options', array(
21 | 'zam_twitter_id' => 'Wern_Ancheta'
22 | ));
23 | }
24 |
25 |
26 | public function tearDown() {
27 |
28 | }
29 |
30 | public function test_get_tweets(){
31 |
32 | $z = new Zam();
33 |
34 | $tweets = $z->get_tweets();
35 | $this->assertCount(11, $tweets);
36 | }
37 |
38 |
39 | }
40 | ?>
--------------------------------------------------------------------------------
/zam/zam-options.php:
--------------------------------------------------------------------------------
1 | options = get_option('zam_options');
9 | $this->register_settings_and_fields();
10 | }
11 |
12 | public static function add_menu(){
13 |
14 | add_menu_page(__('Zam', 'zam'), __('zam', 'zam'), 'manage_options', 'zam-options', array( 'zam_options', 'display_fields' ));
15 |
16 | add_submenu_page('zam-options', __('Settings', 'zam'), __('Settings', 'zam'), 'manage_options', 'zam-options', array( 'zam_options', 'display_fields' ));
17 | }
18 |
19 | public function register_settings_and_fields(){
20 |
21 | register_setting('zam_options', 'zam_options');
22 | add_settings_section('zam_options_main', __('Main Settings', 'zam'), array($this, 'zam_options_create'), __FILE__);
23 |
24 | $this->create_fields(
25 | __FILE__,
26 | $this,
27 | 'zam_options_main',
28 | array(
29 | array(
30 | 'id' => 'zam_twitter_id',
31 | 'label' => __('Twitter ID' , 'zam'),
32 | 'function' => 'display_twitter_id'
33 | )
34 | )
35 | );
36 | }
37 |
38 | public function zam_options_create() {
39 |
40 | }
41 |
42 | public function create_fields($file, $class, $section_id, $field_data){
43 | foreach($field_data as $field){
44 |
45 | add_settings_field($field['id'], $field['label'], array($class, $field['function']), $file, $section_id);
46 | }
47 | }
48 |
49 |
50 | public static function display_fields(){
51 | ?>
52 |
64 | options['zam_twitter_id'])) ? $this->options['zam_twitter_id'] : '';
69 | echo "";
70 | }
71 | }
--------------------------------------------------------------------------------
/zam/zam-tweets-widget.php:
--------------------------------------------------------------------------------
1 | __('A widget for displaying tweets', 'zam'))
15 | );
16 |
17 | }
18 |
19 | public function form($instance){
20 |
21 | $title = __('', 'zam');
22 | $tweets_to_show_range = range(3, 11);
23 | $tweets_to_show = 3;
24 |
25 | if(isset($instance['title'])){
26 | $title = esc_attr($instance['title']);
27 | }
28 |
29 | if(isset($instance['tweets_to_show'])){
30 | $tweets_to_show = esc_attr($instance['tweets_to_show']);
31 | }
32 | ?>
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
53 |
54 | get_tweets();
80 | ?>
81 |
93 | protocol = is_SSL() ? 'https://' : 'http://';
20 | $this->settings = get_option('zam_options');
21 | $this->twitter_id = (!empty($this->settings['zam_twitter_id'])) ? $this->settings['zam_twitter_id'] : '';
22 |
23 | add_action('admin_init', function(){
24 | new Zam_Options();
25 | });
26 |
27 | add_action('admin_menu', array($this, 'zam_admin_init'));
28 |
29 | add_action('widgets_init', function(){
30 | register_widget('zam_tweets_widget');
31 | });
32 |
33 | add_action('save_post', array($this, 'save_tweet'));
34 |
35 | add_shortcode('zam_tweets', array($this, 'shortcode_to_tweet'));
36 |
37 | add_action('activate_zam/zam.php', array($this, 'installation_housekeeping'));
38 |
39 | register_uninstall_hook(__FILE__, array('Zam', 'uninstall_housekeeping'));
40 |
41 | }
42 |
43 | public function zam_admin_init(){
44 | Zam_Options::add_menu();
45 | }
46 |
47 | public function get_tweets(){
48 |
49 | require_once 'libs/twitteroauth/twitteroauth.php';
50 |
51 | //access the twitter API
52 | $twitterConnection = new TwitterOAuth(
53 | 'f4rQ3QIsshrq4lKEtN4dWw', //consumer key
54 | 'JJucsiYamGuLVGGfYZDw9Uj5ipnNKkfWr3q4dUjis', //consumer secret
55 | '283769265-pC9ZVicCgfodW9pzWocgq0Z4a0WiP9MjAYHEHQX2', //access token
56 | 'BM6kNo8ESEfBRSTgjvatA9EazQlEID5RM9uj7E2Jb8' //access token secret
57 | );
58 |
59 | $twitterData = $twitterConnection->get(
60 | 'statuses/user_timeline',
61 | array(
62 | 'screen_name' => $this->twitter_id,
63 | 'count' => '11',
64 | 'exclude_replies' => true //exclude replies to a specific twitter user
65 | )
66 | );
67 |
68 | $tweet_text = array();
69 |
70 | //if the request was successful
71 | if($twitterConnection->http_code == 200){
72 | foreach($twitterData as $t){
73 |
74 | //wrap all the url's with anchor tags
75 | $text = preg_replace(
76 | "#((http|https|ftp)://(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|\"|'|:|\<|$|\.\s)#ie",
77 | "'$3$4'", $t->text
78 | );
79 |
80 | $tweet_text[] = $text;
81 | }
82 | }
83 |
84 | return $tweet_text;
85 |
86 | die();
87 | }
88 |
89 | public function save_tweet($post_id){
90 |
91 | global $wpdb;
92 |
93 | $random_index = rand(0, 10);
94 |
95 | $post = get_post($post_id);
96 | $post_title = $post->post_title;
97 | $post_content = $post->post_content;
98 | $post_type = $post->post_type;
99 |
100 | if(!wp_is_post_revision($post_id) && $post_type == 'post'){
101 |
102 | $pattern = '/\[zam_tweets page=([0-9])\]/'; //the general pattern for the shortcode
103 | preg_match($pattern, $post_content, $matches);
104 | if(!empty($matches)){
105 |
106 | $page = $matches[1]; //extract the page from the matches returned
107 |
108 | $result = wp_remote_get($this->protocol . "api.twitter.com/1/statuses/user_timeline.json?screen_name=" . $this->twitter_id . "&count=11&exclude_replies=true&page=" . $page);
109 |
110 | $tweets = json_decode($result['body']);
111 | $tweet = strip_tags($tweets[$random_index]->text);
112 |
113 | $tweets_table = $wpdb->prefix . 'zam_tweets';
114 |
115 | $wpdb->query("SELECT id FROM $tweets_table WHERE post_id = '$post_id'");
116 |
117 | if($wpdb->num_rows == 0){
118 | $wpdb->insert($tweets_table, array('post_id' => $post_id, 'tweet' => $tweet));
119 | }
120 |
121 |
122 |
123 | }
124 |
125 | }
126 |
127 | }
128 |
129 |
130 |
131 | public function shortcode_to_tweet($attrs){
132 |
133 | global $wpdb;
134 |
135 | $post_id = get_the_ID();
136 | $post_content = get_the_content();
137 |
138 | $pattern = '/\[zam_tweets page=([0-9])\]/';
139 | preg_match($pattern, $post_content, $matches);
140 |
141 | if(!empty($matches)){
142 |
143 | $tweets_table = $wpdb->prefix . 'zam_tweets';
144 | $result = $wpdb->get_var("SELECT tweet FROM $tweets_table WHERE post_id = '$post_id'");
145 | $content = $result;
146 | }
147 |
148 | return $content;
149 | }
150 |
151 |
152 | public function installation_housekeeping(){
153 |
154 | global $wpdb;
155 |
156 | $tweets_table = $wpdb->prefix . 'zam_tweets';
157 |
158 | $tweets_sql = "CREATE TABLE $tweets_table (
159 | id INT(10) NOT NULL AUTO_INCREMENT,
160 | post_id BIGINT(20) NOT NULL,
161 | tweet VARCHAR(160) NOT NULL,
162 | PRIMARY KEY id (id)
163 | );";
164 |
165 | require_once ABSPATH . 'wp-admin/includes/upgrade.php';
166 |
167 | dbDelta($tweets_sql);
168 | }
169 |
170 |
171 | public static function uninstall_housekeeping(){
172 | global $wpdb;
173 | $tweets_table = $wpdb->prefix . 'zam_tweets';
174 | $wpdb->query("DROP TABLE $tweets_table");
175 | delete_option('zam_options');
176 | }
177 |
178 |
179 | }
180 |
181 | $GLOBALS['zam'] = new Zam();
182 | ?>
--------------------------------------------------------------------------------