diff options
author | Charlie <root@www2.slamar.com> | 2010-12-13 16:34:44 -0600 |
---|---|---|
committer | Charlie <root@www2.slamar.com> | 2010-12-13 16:34:44 -0600 |
commit | 40b9d2ec6e162d8f8a236acb098bfdb4b0d9f56d (patch) | |
tree | b9eeb246c938b219c621d2b14e2b8e89755a8bdb | |
parent | 77311f6f0efcd3c8b28211ea12a47b75f149e86f (diff) | |
download | ampache-40b9d2ec6e162d8f8a236acb098bfdb4b0d9f56d.tar.gz ampache-40b9d2ec6e162d8f8a236acb098bfdb4b0d9f56d.tar.bz2 ampache-40b9d2ec6e162d8f8a236acb098bfdb4b0d9f56d.zip |
Initial Twitter
-rw-r--r-- | config/ampache.cfg.php | 634 | ||||
-rw-r--r-- | info.php | 1 | ||||
-rw-r--r-- | modules/twitter/Twitter-Icon.png | bin | 0 -> 26897 bytes | |||
-rw-r--r-- | modules/twitter/index.html | 11 | ||||
-rw-r--r-- | modules/twitter/killsession.php | 7 | ||||
-rw-r--r-- | modules/twitter/twitter_error.php | 1 | ||||
-rw-r--r-- | modules/twitter/twitter_login.php | 29 | ||||
-rw-r--r-- | modules/twitter/twitter_update.php | 39 | ||||
-rw-r--r-- | modules/twitter/twitter_update.php.bak | 34 | ||||
-rw-r--r-- | modules/twitter/twitter_works.php | 104 | ||||
-rw-r--r-- | modules/twitter/twitteroauth/OAuth.php | 874 | ||||
-rw-r--r-- | modules/twitter/twitteroauth/twitteroauth.php | 245 | ||||
-rw-r--r-- | templates/show_now_playing.inc.php | 3 |
13 files changed, 1981 insertions, 1 deletions
diff --git a/config/ampache.cfg.php b/config/ampache.cfg.php new file mode 100644 index 00000000..f27656ac --- /dev/null +++ b/config/ampache.cfg.php @@ -0,0 +1,634 @@ +;#<?php exit(); ?>## +;################### +; General Config # +;################### + +; This value is used to detect quickly +; if this config file is up to date +; this is compared against a value hard-coded +; into the init script +config_version = 11 + +;################### +; Path Vars # +;################### + +; The path to your ampache install +; Do not put a trailing / on this path +; For example if your site is located at http://localhost +; than you do not need to enter anything for the web_path +; if it is located at http://localhost/music you need to +; set web_path to /music +; DEFAULT: "" +web_path = "" + +;############################## +; Session and Login Variables # +;############################## + +; Hostname of your Database +; DEFAULT: localhost +database_hostname = "db.slamar.com" + +; Name of your ampache database +; DEFAULT: ampache +database_name = "ampachedev" + +; Username for your ampache database +; DEFAULT: "" +database_username = "ampache" + +; Password for your ampache database, this can not be blank +; this is a 'forced' security precaution, the default value +; will not work +; DEFAULT: "" +database_password = "password" + +; Length that a session will last expressed in seconds. Default is +; one hour. +; DEFAULT: 3600 +session_length = 3600 + +; Length that the session for a single streaming instance will last +; the default is two hours. With some clients, and long songs this can +; cause playback to stop, increase this value if you experience that +; DEFAULT: 7200 +stream_length = 7200 + +; This length defines how long a 'remember me' session and cookie will +; last, the default is 7200, same as length. It is up to the administrator +; of the box to increase this, for reference 86400 = 1 day +; 604800 = 1 week and 2419200 = 1 month +; DEFAULT: 86400 +remember_length = 86400 + +; Name of the Session/Cookie that will sent to the browser +; default should be fine +; DEFAULT: ampache +session_name = ampache + +; Lifetime of the Cookie, 0 == Forever (until browser close) , otherwise in terms of seconds +; If you want cookies to last past a browser close set this to a value in seconds. +; DEFAULT: 0 +session_cookielife = 0 + +; Is the cookie a "secure" cookie? This should only be set to 1 (true) if you are +; running a secure site (HTTPS). +; DEFAULT: 0 +session_cookiesecure = 0 + +; Auth Methods +; This defines which auth methods vauth will attempt +; to use and in which order, if auto_create isn't enabled +; The user must exist locally. Local method uses PHP's PAM Auth module +; DEFAULT: mysql +; VALUES: mysql,ldap,http,local +auth_methods = "mysql" + +; Logout redirection target +; Defaults to our own login.php, but we can override it here if, for instance, +; we want to redirect to an SSO provider instead. +; logout_redirect = "http://sso.example.com/logout" + +;##################### +; Program Settings # +;##################### + +; File Pattern +; This defines which file types Ampache will attempt to catalog +; You can specify any file extension you want in here separating them +; with a | +; DEFAULT: mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv +catalog_file_pattern = "mp3|mpc|m4p|m4a|mp4|aac|ogg|rm|wma|asf|flac|spx|ra|ape|shn|wv" + +; Video Pattern +; This defines which video file types Ampache will attempt to catalog +; You can specify any file extension you want in here seperating them with +; a | but ampache may not be able to parse them +; DEAFULT: avi|mpg|flv|m4v +catalog_video_pattern = "avi|mpg|flv|m4v" + +; Prefix Pattern +; This defines which prefix Ampache will ignore when importing tags from +; your music. You may add any prefix you want seperating them with a | +; DEFAULT: The|An|A|Die|Das|Ein|Eine|Les|Le|La +catalog_prefix_pattern = "The|An|A|Die|Das|Ein|Eine|Les|Le|La" + +; Use Access List +; Toggle this on if you want ampache to pay attention to the access list +; and only allow streaming/downloading/xml-rpc from known hosts xml-rpc +; will not work without this on. +; NOTE: Default Behavior is DENY FROM ALL +; DEFAULT: true +access_control = "true" + +; Require Session +; If this is set to true ampache will make sure that the URL passed when +; attempting to retrieve a song contains a valid Session ID This prevents +; others from guessing URL's. This setting is ignored if you have use_auth +; disabled. +; DEFAULT: true +require_session = "true" + +; Require LocalNet Session +; If this is set to true then ampache will require that a valid session +; is passed even on hosts defined in the Local Network ACL. This setting +; has no effect if access_control is not enabled +; DEFAULT: true +require_localnet_session = "true" + +; Multiple Logins +; Added by Vlet 07/25/07 +; When this setting is enabled a user may only be logged in from a single +; IP address at any one time, this is to prevent sharing of accounts +; DEFAULT: false +;prevent_multiple_logins = "false" + +; Downsample Remote +; If this is set to true and access control is on any users who are not +; coming from a defined 'network' ACL will be automatically downsampled +; regardless of their preferences. Requires access_control to be enabled +; DEFAULT: false +;downsample_remote = "false" + +; Track User IPs +; If this is enabled Ampache will log the IP of every completed login +; it will store user,ip,time at one row per login. The results are +; displayed in Admin --> Users +; DEFAULT: false +;track_user_ip = "false" + +; User IP Cardinality +; This defines how many days worth of IP history Ampache will track +; As it is one row per login on high volume sites you will want to +; clear it every now and then. +; DEFAULT: 42 days +;user_ip_cardinality = "42" + +; Use XML-RPC +; Allow XML-RPC connections, if you don't want _any_ possibility of your +; catalog being streamed from another location comment this out +; DEFAULT: false +;xml_rpc = "false" + +; Allow Zip Download +; This setting allows/disallows using zlib to zip up an entire +; playlist/album for download. Even if this is turned on you will +; still need to enabled downloading for the specific user you +; want to be able to use this function +; DEFAULT: false +;allow_zip_download = "false" + +; File Zip Download +; This settings tells Ampache to attempt to save the zip file +; to the filesystem instead of creating it in memory, you must +; also set file_zip_path in order for this to work +; DEFAULT: false +;file_zip_download = "false" + +; File Zip Path +; If File Zip Download is enabled this must be set to tell +; Ampache which directory to save the file to. Do not put a +; trailing slash or this will not work. +; DEFAULT: false +;file_zip_path = "false" + +; File Zip Comment +; This is an optional configuration option that adds a comment +; to your zip files, this only applies if you've got allow_zip_downloads +; DEFAULT: Ampache - Zip Batch Download +;file_zip_comment = "Ampache - Zip Batch Download" + +; This setting throttles a persons downloading to the specified +; bytes per second. This is not a 100% guaranteed function, and +; you should really use a server based rate limiter if you want +; to do this correctly. +; DEFAULT: off +; VALUES: any whole number (in bytes per second) +;throttle_download = 10 + +; This determines the tag order for all cataloged +; music. If none of the listed tags are found then +; ampache will default to the first tag format +; that was found. +; POSSIBLE VALUES: ape asf avi id3v1 id3v2 lyrics3 mpeg quicktime riff +; vorbiscomment +; DEFAULT: id3v2 id3v1 vorbiscomment quicktime ape asf avi mpeg riff +getid3_tag_order = "id3v2,id3v1,vorbiscomment,quicktime,ape,asf,avi,mpeg,riff" + +; This determines the order in which metadata sources are used (and in the +; case of plugins, checked) +; POSSIBLE VALUES (builtins): filename and getID3 +; POSSIBLE VALUES (plugins): MusicBrainz, plus any others you've installed. +; DEFAULT: getID3 filename +metadata_order = "getID3,filename" + +; Un comment if don't want ampache to follow symlinks +; DEFAULT: false +;no_symlinks = "false" + +; Use auth? +; If this is set to "Yes" ampache will require a valid +; Username and password. If this is set to false then ampache +; will not ask you for a username and password. false is only +; recommended for internal only instances +; DEFAULT true +use_auth = "true" + +; Default Auth Level +; If use_auth is set to false then this option is used +; to determine the permission level of the 'default' users +; default is administrator. This setting only takes affect +; if use_auth if false +; POSSIBLE VALUES: user, admin, manager, guest +; DEFAULT: admin +default_auth_level = "admin" + +; 5 Star Ratings +; This allows ratings for almost any object in ampache +; POSSIBLE VALUES: false true +; DEFAULT: true +ratings = "true" + +; Sociable +; This turns on / off all of the "social" features of ampache +; default is on, but if you don't care and just want music +; turn this off to disable all social features. +; DEFAULT: true +sociable = "true" + +; This options will turn on/off Demo Mode +; If Demo mode is on you can not play songs or update your catalog +; in other words.. leave this commented out +; DEFAULT: false +;demo_mode = "false" + +; Caching +; This turns the caching mechanisms on or off, due to a large number of +; problems with people with very large catalogs and low memory settings +; this is off by default as it does significantly increase the memory +; requirments on larger catalogs. If you have the memory this can create +; a 2-3x speed improvement. +; DEFAULT: false +;memory_cache = false + +; Memory Limit +; This defines the "Min" memory limit for PHP if your php.ini +; has a lower value set Ampache will set it up to this. If you +; set it below 16MB getid3() will not work! +; DEFAULT: 32 +;memory_limit = 32 + +; Album Art Preferred Filename +; Specify a filename to look for if you always give the same filename +; i.e. "folder.jpg" Ampache currently only supports jpg/gif and png +; Especially useful if you have a front and a back image in a folder +; comment out if ampache should search for any jpg,gif or png +; DEFAULT: folder.jpg +;album_art_preferred_filename = "folder.jpg" + +; Resize Images * Requires PHP-GD * +; Set this to true if you want Ampache to resize the Album +; art on the fly, this increases load time and CPU usage +; and also requires the PHP-GD library. This is very useful +; If you have high-quality album art and a small upload cap +; DEFAULT: false +;resize_images = "false" + +; Art Gather Order +; Simply arrange the following in the order you would like +; ampache to search. If you want to disable one of the search +; methods simply leave it out. DB should be left as the first +; method unless you want it to overwrite what's already in the +; database +; POSSIBLE VALUES: db tags folder amazon lastfm musicbrainz google +; DEFAULT: db,tags,folder,musicbrainz,lastfm,google +art_order = "db,tags,folder,musicbrainz,lastfm,google" + +; Amazon Developer Key +; These are needed in order to actually use the amazon album art +; Your public key is your 'Access Key ID' +; Your private key is your 'Secret Access Key' +; DEFAULT: false +;amazon_developer_public_key = "" +;amazon_developer_private_key = "" + +; Last.FM API Key +; Set this to your Last.FM api key to actually use Last.FM for +; recommendations. +;lastfm_api_key = "" + +; Amazon base urls +; An array of Amazon sites to search. +; NOTE: This will search each of these sites in turn so don't expect it +; to be lightning fast! +; It is strongly recommended that only one of these is selected at any +; one time +; POSSIBLE VALUES: +; http://webservices.amazon.com +; http://webservices.amazon.co.uk +; http://webservices.amazon.de +; http://webservices.amazon.co.jp +; http://webservices.amazon.fr +; http://webservices.amazon.ca +; Default: http://webservices.amazon.com +amazon_base_urls = "http://webservices.amazon.com" + +; max_amazon_results_pages +; The maximum number of results pages to pull from EACH amazon site +; NOTE: The art search pages through the results returned by your search +; up to this number of pages. As with the base_urls above, this is going +; to take more time, the more pages you ask it to process. +; Of course a good search will return only a few matches anyway. +; It is strongly recommended that you do _not_ change this value +; DEFAULT: 1 page (10 items) +max_amazon_results_pages = 1 + +; Debug +; If this is enabled Ampache will write debugging information to the log file +; DEFAULT: false +;debug = "false" + +; Debug Level +; This should always be set in conjunction with the +; debug option, it defines how prolific you want the +; debugging in ampache to be. values are 1-5. +; 1 == Errors only +; 2 == Error + Failures (login attempts etc.) +; 3 == ?? +; 4 == ?? (Profit!) +; 5 == Information (cataloging progress etc.) +; DEFAULT: 5 +debug_level = 5 + +; Path to Log File +; This defines where you want ampache to log events to +; this will only happen if debug is turned on. Do not +; include trailing slash. You will need to make sure that +; the specified directory exists and your HTTP server has +; write access. +; DEFAULT: NULL +;log_path = "/var/log/ampache" + +; Charset of generated HTML pages +; Default of UTF-8 should work for most people +; DEFAULT: UTF-8 +site_charset = UTF-8 + +; Locale Charset +; In some cases this has to be different +; in order for XHTML and other things to work +; This is disabled by default, enabled only +; if needed. It's specifically needed for Russian +; so that is the default +; DEFAULT: cp1251 +;lc_charset = cp1251 + +; Refresh Limit +; This defines the default refresh limit in seconds for +; pages with dynamic content, such as now playing +; DEFAULT: 60 +; Possible Values: Int > 5 +refresh_limit = "60" + +;######################################################### +; LDAP login info (optional) # +;######################################################### + +; This setting will silently create an ampache account +; for anyone who can login using ldap (or any other login +; extension). The default is to create new users as guests +; see auto_user config option if you would like to change this +; DEFAULT: false +;auto_create = "false" + +; LDAP filter string to use +; For OpenLDAP use "uid" +; For Microsoft Active Directory (MAD) use "sAMAccountName" +; DEFAULT: null +; ldap_filter = "sAMAccountName" + +; LDAP objectclass it's required so if you don't know use * +; OpanLDAP objectclass = "*" +; MAD objectclass = "organizationalPerson" +; DEFAULT null +;ldap_objectclass = "organizationalPerson" + +; if this is the case, fill these in here: +; DEFAULT: null +;ldap_username = "" +;ldap_password = "" + +; NOT YET IMPLEMENTED!! +; This option checks to see if the specified user is in +; a specific ldap group, allowing you to give access based +; on group membership +; DEFAULT: null +;ldap_require_group = "cn=yourgroup,ou=yourorg,dc=yoursubdomain,dc=yourdomain,dc=yourtld" + +; This is the search dn used to find your user, uid=username is added on to +; This string +; DEFAULT: null +;ldap_search_dn = "ou=People,dc=yoursubdomain,dc=yourdomain,dc=yourtld" + +; This is the address of your ldap server +; DEFAULT: null +;ldap_url = "" + +; Specify where in your ldap db the following fields are stored: +; (comment out if you don't have them) +; OpenLDAP: ldap_name_field = "cn" +; MAD ldap_name_field = "displayname" +; DEFAULT: [none] +;ldap_email_field = "mail" +;ldap_name_field = "cn" + +;######################################################### +; Public Registration settings, defaults to disabled # +;######################################################### + +; This setting turns on/off public registration. It is +; recommended you leave this off, as it will allow anyone to +; sign up for an account on your server. +; REMEMBER: don't forget to set the mail from address further down in the config. +; DEFAULT: false +;allow_public_registration = "false" + +; Require Captcha Text on Image confirmation +; Turning this on requires the user to correctly +; type in the letters in the image created by Captcha +; Default is off because its very hard to detect if it failed +; to draw, or they failed to enter it. +; DEFAULT: false +;captcha_public_reg = "false" + +; This setting turns on/off admin notification of registration. +; DEFAULT: false +;admin_notify_reg = "false" + +; This setting will allow all registrants/ldap/http users +; to be auto-approved as a user. By default, they will be +; added as a guest and must be promoted by the admin. +; POSSIBLE VALUES: guest, user, admin +; DEFAULT: guest +;auto_user = "guest" + +; This will display the user agreement when registering +; For agreement text, edit templates/user_agreement.php +; User will need to accept the agreement before they can register +; DEFAULT: false +;user_agreement = "false" + +;######################################################## +; These options control the dynamic down-sampling based # +; on current usage # +; *Note* Down-sampling must be enabled and working # +;######################################################## + +; Attempt to optimize bandwidth by dynamically down-sampling +; all connections from users to fit within a maximum bandwidth. +; The benefit is that it won't downsample more than it needs to. As it only +; adjusts the sample rate at the beginning of a song, it may take a few +; minutes to reset all connections to a lower rate. This won't never go higher +; than a user's sample rate and only applies to users who are set to +; the Downsample playback method +; DEFAULT: 576 +;max_bit_rate = 576 + +; If min_bit_rate is set then new streams will be denied if it would +; cause all streams to be down-sampled below this rate. +; DEFAULT: 48 +;min_bit_rate = 48 + +;###################################################### +; These are commands used to transcode non-streaming +; formats to the target file type for streaming. +; This can be useful in re-encoding file types that don't stream +; very well, or if your player doesn't support some file types. +; This is also the string used when 'downsampling' is selected +; as some people have complained its not bloody obvious, any programs +; referenced in the downsample commands must be installed manually and in +; the web server path, and executable by the web server +; REQUIRED variables +; transcode_TYPE = true/false ## True to force transcode regardless of prefs +; transcode_TYPE_target = TARGET_FILE_TYPE +; transcode_cmd_TYPE = TRANSCODE_COMMAND +; %FILE% = filename +; %OFFSET% = offset +; %SAMPLE% = sample rate +; %EOF% = end of file in min.sec + +; List of filetypes to transcode +transcode_m4a = true +transcode_m4a_target = mp3 +;transcode_flac = true +transcode_flac_target = mp3 +;transcode_mp3 = false +transcode_mp3_target = mp3 +;transcode_ogg = false +transcode_ogg_target = mp3 + +; These are the commands that will be run to transcode the file +transcode_cmd_flac = "flac -dc %FILE% | lame -b %SAMPLE% -S - - " +transcode_cmd_m4a = "faad -f 2 -w %FILE% | lame -r -b %SAMPLE% -S - -" +transcode_cmd_mp3 = "mp3splt -qnf %FILE% %OFFSET% %EOF% -o - | lame --mp3input -q 3 -b %SAMPLE% -S - -" +transcode_cmd_ogg = "oggsplt -qn %FILE% %OFFSET% %EOF% -o - | oggdec -Q -o - - | lame -S -q 3 -b %SAMPLE% -S - -" + +; Alternative command works better for some people +;transcode_cmd_m4a = "alac %FILE% | lame -h -b %SAMPLE% -S - -" +;transcode_cmd_ogg = "mp3splt -qn %FILE% %OFFSET% %EOF% -o - | oggdec -Q -o - - | lame -S -q 3 -b %SAMPLE% -S - -" +;transcode_cmd_flac = "flac -dc %FILE% | lame -rb %SAMPLE% -S - -" + +; This line seems to work better for windows, switch if needed +;transcode_cmd_mp3 = "lame -q 3 -b %SAMPLE% -S %FILE% - -" + +;###################################################### +; these options allow you to configure your rss-feed +; layout. rss exists of two parts, main and song main is the information about the feed +; song is the information in the feed. can be multiple items. +; use_rss = false (values true | false) +;DEFAULT: use_rss = true +use_rss = true +;##################################################### + +;############################# +; Proxy Settings (optional) # +;############################# +; If Ampache is behind an http proxy, specifiy the hostname or IP address +; port, proxyusername, and proxypassword here. +;DEFAULT: not in use +;proxy_host = "192.168.0.1" +;proxy_port = "8080" +;proxy_user = "" +;proxy_pass = "" + +;############################# +; Mail Settings # +;############################# + +;Method used to send mail +;POSSIBLE VALUES: smtp sendmail php +;DEFAULT: php +;mail_type = "php" + +;Mail domain. +;DEFAULT: example.com +;mail_domain = "example.com" + +;This will be combined with mail_domain and used as the source address for +;emails generated by Ampache. For example, setting this to 'me' will set the +;sender to 'me@example.com'. +;DEFAULT: info +;mail_user = "info" + +;A name to go with the email address. +;DEFAULT: Ampache +;mail_name = "Ampache" + +;How strictly email addresses should be checked. +;easy does a regex match, strict actually performs some SMTP transactions +;to see if we can send to this address. +;POSSIBLE VALUES: strict easy none +; DEFAULT: strict +;mail_check = "strict" + + +;############################ +; sendmail Settings # +;############################ + +;DEFAULT: /usr/sbin/sendmail +;sendmail_path = "/usr/sbin/sendmail" + +;############################# +; SMTP Settings # +;############################# + +;Mail server (hostname or IP address) +;DEFAULT: localhost +;mail_host = "localhost" + +; SMTP port +;DEFAULT: 25 +;mail_port = 25 + +;Secure SMTP +;POSSIBLE VALUES: ssl tls +;DEFAULT: none +;mail_secure_smtp = tls + +;Enable SMTP authentication +;DEFAULT: false +;mail_auth = true + +;SMTP Username +;your mail auth username. +;mail_auth_user = "" + +; SMTP Password +; your mail auth password. +;mail_auth_pass = "" + +; Twitter Keys +twitter_consumer_key = "tCCFlruiduHyUuC2vNQEyQ" +twitter_consumer_secret = "omRMNdRNktRIqxJVm2uTDyN5iDTUF6Q8eBoinTNgI" diff --git a/info.php b/info.php new file mode 100644 index 00000000..147cebcd --- /dev/null +++ b/info.php @@ -0,0 +1 @@ +<?php phpinfo(); ?> diff --git a/modules/twitter/Twitter-Icon.png b/modules/twitter/Twitter-Icon.png Binary files differnew file mode 100644 index 00000000..c7cdd55f --- /dev/null +++ b/modules/twitter/Twitter-Icon.png diff --git a/modules/twitter/index.html b/modules/twitter/index.html new file mode 100644 index 00000000..46ff1aa3 --- /dev/null +++ b/modules/twitter/index.html @@ -0,0 +1,11 @@ +<html> + <head> + <title>Twitter</title> + </head> + + <body> + <a href="twitter_login.php"><img src="Twitter-Icon.png" width="16" height="16"></a> + <br> + <a href="killsession.php">kill Session</a> + </body> +</html> diff --git a/modules/twitter/killsession.php b/modules/twitter/killsession.php new file mode 100644 index 00000000..a75eacf8 --- /dev/null +++ b/modules/twitter/killsession.php @@ -0,0 +1,7 @@ +<?php + + session_start(); + session_destroy(); +?> + +<a href="index.html">back</a> diff --git a/modules/twitter/twitter_error.php b/modules/twitter/twitter_error.php new file mode 100644 index 00000000..d2d98d6b --- /dev/null +++ b/modules/twitter/twitter_error.php @@ -0,0 +1 @@ +it no work diff --git a/modules/twitter/twitter_login.php b/modules/twitter/twitter_login.php new file mode 100644 index 00000000..2361584c --- /dev/null +++ b/modules/twitter/twitter_login.php @@ -0,0 +1,29 @@ +<?php + require_once '../../lib/init.php'; + require_once( Config::get('prefix') . "/modules/twitter/twitteroauth/twitteroauth.php"); + session_start(); + + if( isset($_SESSION['twitterusername']) ) { + header('Location: twitter_update.php'); + } else { + // The TwitterOAuth instance + $twitteroauth = new TwitterOAuth( Config::get('twitter_consumer_key') , Config::get('twitter_consumer_secret') ); + + // Requesting authentication tokens, the parameter is the URL we will be redirected to + $request_token = $twitteroauth->getRequestToken( Config::get('web_path') . '/modules/twitter/twitter_works.php'); + + // Saving them into the session + $_SESSION['oauth_token'] = $request_token['oauth_token']; + $_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; + + // If everything goes well.. + if( $twitteroauth->http_code == 200 ) { + // Let's generate the URL and redirect + $url = $twitteroauth->getAuthorizeURL($request_token['oauth_token']); + header('Location: '. $url); + echo "ok"; + } else { + die('Something wrong happened.'); + } + } +?> diff --git a/modules/twitter/twitter_update.php b/modules/twitter/twitter_update.php new file mode 100644 index 00000000..996d01d0 --- /dev/null +++ b/modules/twitter/twitter_update.php @@ -0,0 +1,39 @@ +<?php + require_once '../../lib/init.php'; + require_once( Config::get('prefix') . "/modules/twitter/twitteroauth/twitteroauth.php"); + session_start(); + + + if(!empty($_SESSION['twitterusername'])) { + $link = mysql_connect( Config::get('database_hostname'), Config::get('database_username'), Config::get('database_password') ); + mysql_select_db( Config::get('database_name') , $link) or die("Couldnt connect " . mysql_error() ); + + $nowplayingQuery = mysql_query("SELECT song.title,artist.name FROM song,now_playing,artist WHERE song.id = now_playing.object_id AND artist.id = song.artist"); + $nowplayingResults = mysql_fetch_array($nowplayingQuery) or die( mysql_error() ); + + $return = $nowplayingResults['title'] . " by " . $nowplayingResults['name']; + + mysql_select_db('test', $link) or die("Couldnt connect " . mysql_error() ); + + $query = mysql_query("SELECT * FROM users WHERE username = '" . $_SESSION['twitterusername'] . "'"); + $result = mysql_fetch_array($query) or die( mysql_error() ); + + mysql_close($link); + + $twitteroauth = new TwitterOAuth( Config::get('twitter_consumer_key'), Config::get('twitter_consumer_secret'), $result['oauth_token'], $result['oauth_secret']); + $user_info = $twitteroauth->get('account/verify'); + if( $user_info->error == 'Not found' ) { + $twitteroauth->post('statuses/update', array('status' => 'is rocking out to ' . $return)); + echo "updated"; + header('Location: ' . Config::get('web_path') ); + } + + echo "Hello " . $result['username']; + echo "<br> You are listening to " . $return; + echo "<br>"; + print_r($user_info); + } else { + echo "sessionusername: " . $_SESSION['twitterusername'] . "<br>"; + echo 'borked'; + } +?> diff --git a/modules/twitter/twitter_update.php.bak b/modules/twitter/twitter_update.php.bak new file mode 100644 index 00000000..36f34208 --- /dev/null +++ b/modules/twitter/twitter_update.php.bak @@ -0,0 +1,34 @@ +<?php + require("twitteroauth/twitteroauth.php"); + session_start(); + + $link = mysql_connect('db.slamar.com', 'ampache', 'generation'); + mysql_select_db('ampache', $link) or die("Couldnt connect " . mysql_error() ); + + $nowplayq = mysql_query("SELECT object_id FROM now_playing"); + $nowplayresult = mysql_fetch_array($nowplayq) or die( mysql_error() ); + + $songq = mysql_query("SELECT artist,title FROM song WHERE id = " . $nowplayresult['object_id']); + $songresult = mysql_fetch_array($songq) or die( mysql_error() ); + + $artistq = mysql_query("SELECT name FROM artist WHERE id = " . $songresult['artist'] ); + $artistresult = mysql_fetch_array($artistq) or die( mysql_error() ); + + $return = $songresult['title'] . " by " . $artistresult['name']; + + mysql_select_db('test', $link) or die("Couldnt connect " . mysql_error() ); + + $query = mysql_query("SELECT * FROM users WHERE username = 'CrashMann'"); + $result = mysql_fetch_array($query) or die( mysql_error() ); + + mysql_close($link); + + if(!empty($result['username'])) { + $twitteroauth = new TwitterOAuth('tCCFlruiduHyUuC2vNQEyQ', 'omRMNdRNktRIqxJVm2uTDyN5iDTUF6Q8eBoinTNgI', $result['oauth_token'], $result['oauth_secret']); +// $user_info = $twitteroauth->get('account/verify'); + $twitteroauth->post('statuses/update', array('status' => 'is listening to ' . $return)); + + echo "Hello " . $result['username']; + echo "<br> You are listening to " . $return; + } +?> diff --git a/modules/twitter/twitter_works.php b/modules/twitter/twitter_works.php new file mode 100644 index 00000000..0894a461 --- /dev/null +++ b/modules/twitter/twitter_works.php @@ -0,0 +1,104 @@ +<?php + require_once '../../lib/init.php'; + require_once( Config::get('prefix') . "/modules/twitter/twitteroauth/twitteroauth.php"); + + session_start(); + + if(!empty($_SESSION['twitterusername'])) { + header('Location: ' . Config::Get('web_path') . '/modules/twitter/twitter_update.php'); + } + + if(!empty($_GET['oauth_verifier']) && !empty($_SESSION['oauth_token']) && !empty($_SESSION['oauth_token_secret'])){ + + // Good to go + } else { + // Something's missing, go back to square 1 + header('Location: ' . Config::Get('web_path') . '/modules/twitter/twitter_login.php'); + } + + // TwitterOAuth instance, with two new parameters we got in twitter_login.php + $twitteroauth = new TwitterOAuth( Config::get('twitter_consumer_key'), Config::get('twitter_consumer_secret'), $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']); + + // Let's request the access token + $access_token = $twitteroauth->getAccessToken($_GET['oauth_verifier']); + + // Save it in a session var + $_SESSION['access_token'] = $access_token; + + // Let's get the user's info + $user_info = $twitteroauth->get('account/verify_credentials'); + + // Print user's info +// print_r($user_info); + + print "{$user_info->id}"; + echo '<br>'; + print "{$user_info->screen_name}"; + echo '<br>'; + print "access token:" . $access_token['oauth_token'] . "\n"; + echo '<br>'; + print "access token secret:" . $access_token['oauth_token_secret'] . "\n"; + echo '<br>'; + + // $twitteroauth->post('statuses/update', array('status' => 'Does it work?')); + + + if(isset($user_info->error)){ + + // Something's wrong, go back to square 1 + session_destroy(); +// header('Location: ' . Config::Get('web_path') . '/modules/twitter/twitter_error.php'); + echo "Session killed"; + } else { + + $link = mysql_connect(Config::get('database_hostname'), Config::get('database_username') , Config::get('database_password') ); + mysql_select_db('test', $link); + + // Let's find the user by its ID + $query = mysql_query("SELECT * FROM users WHERE oauth_provider = 'twitter' AND oauth_uid = ". $user_info->id); + $result = mysql_fetch_array($query); + + // If not, let's add it to the database + if(empty($result)){ + $query = mysql_query("INSERT INTO users (oauth_provider, + oauth_uid, + username, + oauth_token, + oauth_secret) + VALUES ('twitter', + {$user_info->id}, + '{$user_info->screen_name}', + '{$access_token['oauth_token']}', + '{$access_token['oauth_token_secret']} + ') + "); + + $query = mysql_query("SELECT * FROM users WHERE username = '" . $user_info->screen_name . "'" ); + $result = mysql_fetch_array($query); + echo "insert: "; + print_r($result); + echo "<br>"; + } else { + // Update the tokens + $query = mysql_query("UPDATE users SET oauth_token = '{$access_token['oauth_token']}', oauth_secret = '{$access_token['oauth_token_secret']}' WHERE oauth_provider = 'twitter' AND oauth_uid = {$user_info->id}"); + $query = mysql_query("SELECT * FROM users WHERE username = '" . $user_info->screen_name . "'"); + $result = mysql_fetch_array($query); + echo "update/select"; + print_r($result); + echo "<br>"; + } + + $_SESSION['id'] = $result['id']; + $_SESSION['twitterusername'] = $result['username']; + $_SESSION['oauth_uid'] = $result['oauth_uid']; + $_SESSION['oauth_provider'] = $result['oauth_provider']; + $_SESSION['oauth_token'] = $result['oauth_token']; + $_SESSION['oauth_secret'] = $result['oauth_secret']; + + mysql_close($link); + + header('Location: ' . Config::get('web_path') . '/modules/twiter/twitter_update.php'); + echo "session twitterusername: " . $_SESSION['twitterusername'] . "<br>"; + echo 'got here'; + } +?> diff --git a/modules/twitter/twitteroauth/OAuth.php b/modules/twitter/twitteroauth/OAuth.php new file mode 100644 index 00000000..67a94c47 --- /dev/null +++ b/modules/twitter/twitteroauth/OAuth.php @@ -0,0 +1,874 @@ +<?php +// vim: foldmethod=marker + +/* Generic exception class + */ +class OAuthException extends Exception { + // pass +} + +class OAuthConsumer { + public $key; + public $secret; + + function __construct($key, $secret, $callback_url=NULL) { + $this->key = $key; + $this->secret = $secret; + $this->callback_url = $callback_url; + } + + function __toString() { + return "OAuthConsumer[key=$this->key,secret=$this->secret]"; + } +} + +class OAuthToken { + // access tokens and request tokens + public $key; + public $secret; + + /** + * key = the token + * secret = the token secret + */ + function __construct($key, $secret) { + $this->key = $key; + $this->secret = $secret; + } + + /** + * generates the basic string serialization of a token that a server + * would respond to request_token and access_token calls with + */ + function to_string() { + return "oauth_token=" . + OAuthUtil::urlencode_rfc3986($this->key) . + "&oauth_token_secret=" . + OAuthUtil::urlencode_rfc3986($this->secret); + } + + function __toString() { + return $this->to_string(); + } +} + +/** + * A class for implementing a Signature Method + * See section 9 ("Signing Requests") in the spec + */ +abstract class OAuthSignatureMethod { + /** + * Needs to return the name of the Signature Method (ie HMAC-SHA1) + * @return string + */ + abstract public function get_name(); + + /** + * Build up the signature + * NOTE: The output of this function MUST NOT be urlencoded. + * the encoding is handled in OAuthRequest when the final + * request is serialized + * @param OAuthRequest $request + * @param OAuthConsumer $consumer + * @param OAuthToken $token + * @return string + */ + abstract public function build_signature($request, $consumer, $token); + + /** + * Verifies that a given signature is correct + * @param OAuthRequest $request + * @param OAuthConsumer $consumer + * @param OAuthToken $token + * @param string $signature + * @return bool + */ + public function check_signature($request, $consumer, $token, $signature) { + $built = $this->build_signature($request, $consumer, $token); + return $built == $signature; + } +} + +/** + * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] + * where the Signature Base String is the text and the key is the concatenated values (each first + * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' + * character (ASCII code 38) even if empty. + * - Chapter 9.2 ("HMAC-SHA1") + */ +class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { + function get_name() { + return "HMAC-SHA1"; + } + + public function build_signature($request, $consumer, $token) { + $base_string = $request->get_signature_base_string(); + $request->base_string = $base_string; + + $key_parts = array( + $consumer->secret, + ($token) ? $token->secret : "" + ); + + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); + $key = implode('&', $key_parts); + + return base64_encode(hash_hmac('sha1', $base_string, $key, true)); + } +} + +/** + * The PLAINTEXT method does not provide any security protection and SHOULD only be used + * over a secure channel such as HTTPS. It does not use the Signature Base String. + * - Chapter 9.4 ("PLAINTEXT") + */ +class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { + public function get_name() { + return "PLAINTEXT"; + } + + /** + * oauth_signature is set to the concatenated encoded values of the Consumer Secret and + * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is + * empty. The result MUST be encoded again. + * - Chapter 9.4.1 ("Generating Signatures") + * + * Please note that the second encoding MUST NOT happen in the SignatureMethod, as + * OAuthRequest handles this! + */ + public function build_signature($request, $consumer, $token) { + $key_parts = array( + $consumer->secret, + ($token) ? $token->secret : "" + ); + + $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); + $key = implode('&', $key_parts); + $request->base_string = $key; + + return $key; + } +} + +/** + * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in + * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for + * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a + * verified way to the Service Provider, in a manner which is beyond the scope of this + * specification. + * - Chapter 9.3 ("RSA-SHA1") + */ +abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { + public function get_name() { + return "RSA-SHA1"; + } + + // Up to the SP to implement this lookup of keys. Possible ideas are: + // (1) do a lookup in a table of trusted certs keyed off of consumer + // (2) fetch via http using a url provided by the requester + // (3) some sort of specific discovery code based on request + // + // Either way should return a string representation of the certificate + protected abstract function fetch_public_cert(&$request); + + // Up to the SP to implement this lookup of keys. Possible ideas are: + // (1) do a lookup in a table of trusted certs keyed off of consumer + // + // Either way should return a string representation of the certificate + protected abstract function fetch_private_cert(&$request); + + public function build_signature($request, $consumer, $token) { + $base_string = $request->get_signature_base_string(); + $request->base_string = $base_string; + + // Fetch the private key cert based on the request + $cert = $this->fetch_private_cert($request); + + // Pull the private key ID from the certificate + $privatekeyid = openssl_get_privatekey($cert); + + // Sign using the key + $ok = openssl_sign($base_string, $signature, $privatekeyid); + + // Release the key resource + openssl_free_key($privatekeyid); + + return base64_encode($signature); + } + + public function check_signature($request, $consumer, $token, $signature) { + $decoded_sig = base64_decode($signature); + + $base_string = $request->get_signature_base_string(); + + // Fetch the public key cert based on the request + $cert = $this->fetch_public_cert($request); + + // Pull the public key ID from the certificate + $publickeyid = openssl_get_publickey($cert); + + // Check the computed signature against the one passed in the query + $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); + + // Release the key resource + openssl_free_key($publickeyid); + + return $ok == 1; + } +} + +class OAuthRequest { + private $parameters; + private $http_method; + private $http_url; + // for debug purposes + public $base_string; + public static $version = '1.0'; + public static $POST_INPUT = 'php://input'; + + function __construct($http_method, $http_url, $parameters=NULL) { + @$parameters or $parameters = array(); + $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); + $this->parameters = $parameters; + $this->http_method = $http_method; + $this->http_url = $http_url; + } + + + /** + * attempt to build up a request from what was passed to the server + */ + public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { + $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") + ? 'http' + : 'https'; + @$http_url or $http_url = $scheme . + '://' . $_SERVER['HTTP_HOST'] . + ':' . + $_SERVER['SERVER_PORT'] . + $_SERVER['REQUEST_URI']; + @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; + + // We weren't handed any parameters, so let's find the ones relevant to + // this request. + // If you run XML-RPC or similar you should use this to provide your own + // parsed parameter-list + if (!$parameters) { + // Find request headers + $request_headers = OAuthUtil::get_headers(); + + // Parse the query-string to find GET parameters + $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); + + // It's a POST request of the proper content-type, so parse POST + // parameters and add those overriding any duplicates from GET + if ($http_method == "POST" + && @strstr($request_headers["Content-Type"], + "application/x-www-form-urlencoded") + ) { + $post_data = OAuthUtil::parse_parameters( + file_get_contents(self::$POST_INPUT) + ); + $parameters = array_merge($parameters, $post_data); + } + + // We have a Authorization-header with OAuth data. Parse the header + // and add those overriding any duplicates from GET or POST + if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { + $header_parameters = OAuthUtil::split_header( + $request_headers['Authorization'] + ); + $parameters = array_merge($parameters, $header_parameters); + } + + } + + return new OAuthRequest($http_method, $http_url, $parameters); + } + + /** + * pretty much a helper function to set up the request + */ + public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { + @$parameters or $parameters = array(); + $defaults = array("oauth_version" => OAuthRequest::$version, + "oauth_nonce" => OAuthRequest::generate_nonce(), + "oauth_timestamp" => OAuthRequest::generate_timestamp(), + "oauth_consumer_key" => $consumer->key); + if ($token) + $defaults['oauth_token'] = $token->key; + + $parameters = array_merge($defaults, $parameters); + + return new OAuthRequest($http_method, $http_url, $parameters); + } + + public function set_parameter($name, $value, $allow_duplicates = true) { + if ($allow_duplicates && isset($this->parameters[$name])) { + // We have already added parameter(s) with this name, so add to the list + if (is_scalar($this->parameters[$name])) { + // This is the first duplicate, so transform scalar (string) + // into an array so we can add the duplicates + $this->parameters[$name] = array($this->parameters[$name]); + } + + $this->parameters[$name][] = $value; + } else { + $this->parameters[$name] = $value; + } + } + + public function get_parameter($name) { + return isset($this->parameters[$name]) ? $this->parameters[$name] : null; + } + + public function get_parameters() { + return $this->parameters; + } + + public function unset_parameter($name) { + unset($this->parameters[$name]); + } + + /** + * The request parameters, sorted and concatenated into a normalized string. + * @return string + */ + public function get_signable_parameters() { + // Grab all parameters + $params = $this->parameters; + + // Remove oauth_signature if present + // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") + if (isset($params['oauth_signature'])) { + unset($params['oauth_signature']); + } + + return OAuthUtil::build_http_query($params); + } + + /** + * Returns the base string of this request + * + * The base string defined as the method, the url + * and the parameters (normalized), each urlencoded + * and the concated with &. + */ + public function get_signature_base_string() { + $parts = array( + $this->get_normalized_http_method(), + $this->get_normalized_http_url(), + $this->get_signable_parameters() + ); + + $parts = OAuthUtil::urlencode_rfc3986($parts); + + return implode('&', $parts); + } + + /** + * just uppercases the http method + */ + public function get_normalized_http_method() { + return strtoupper($this->http_method); + } + + /** + * parses the url and rebuilds it to be + * scheme://host/path + */ + public function get_normalized_http_url() { + $parts = parse_url($this->http_url); + + $port = @$parts['port']; + $scheme = $parts['scheme']; + $host = $parts['host']; + $path = @$parts['path']; + + $port or $port = ($scheme == 'https') ? '443' : '80'; + + if (($scheme == 'https' && $port != '443') + || ($scheme == 'http' && $port != '80')) { + $host = "$host:$port"; + } + return "$scheme://$host$path"; + } + + /** + * builds a url usable for a GET request + */ + public function to_url() { + $post_data = $this->to_postdata(); + $out = $this->get_normalized_http_url(); + if ($post_data) { + $out .= '?'.$post_data; + } + return $out; + } + + /** + * builds the data one would send in a POST request + */ + public function to_postdata() { + return OAuthUtil::build_http_query($this->parameters); + } + + /** + * builds the Authorization: header + */ + public function to_header($realm=null) { + $first = true; + if($realm) { + $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; + $first = false; + } else + $out = 'Authorization: OAuth'; + + $total = array(); + foreach ($this->parameters as $k => $v) { + if (substr($k, 0, 5) != "oauth") continue; + if (is_array($v)) { + throw new OAuthException('Arrays not supported in headers'); + } + $out .= ($first) ? ' ' : ','; + $out .= OAuthUtil::urlencode_rfc3986($k) . + '="' . + OAuthUtil::urlencode_rfc3986($v) . + '"'; + $first = false; + } + return $out; + } + + public function __toString() { + return $this->to_url(); + } + + + public function sign_request($signature_method, $consumer, $token) { + $this->set_parameter( + "oauth_signature_method", + $signature_method->get_name(), + false + ); + $signature = $this->build_signature($signature_method, $consumer, $token); + $this->set_parameter("oauth_signature", $signature, false); + } + + public function build_signature($signature_method, $consumer, $token) { + $signature = $signature_method->build_signature($this, $consumer, $token); + return $signature; + } + + /** + * util function: current timestamp + */ + private static function generate_timestamp() { + return time(); + } + + /** + * util function: current nonce + */ + private static function generate_nonce() { + $mt = microtime(); + $rand = mt_rand(); + + return md5($mt . $rand); // md5s look nicer than numbers + } +} + +class OAuthServer { + protected $timestamp_threshold = 300; // in seconds, five minutes + protected $version = '1.0'; // hi blaine + protected $signature_methods = array(); + + protected $data_store; + + function __construct($data_store) { + $this->data_store = $data_store; + } + + public function add_signature_method($signature_method) { + $this->signature_methods[$signature_method->get_name()] = + $signature_method; + } + + // high level functions + + /** + * process a request_token request + * returns the request token on success + */ + public function fetch_request_token(&$request) { + $this->get_version($request); + + $consumer = $this->get_consumer($request); + + // no token required for the initial token request + $token = NULL; + + $this->check_signature($request, $consumer, $token); + + // Rev A change + $callback = $request->get_parameter('oauth_callback'); + $new_token = $this->data_store->new_request_token($consumer, $callback); + + return $new_token; + } + + /** + * process an access_token request + * returns the access token on success + */ + public function fetch_access_token(&$request) { + $this->get_version($request); + + $consumer = $this->get_consumer($request); + + // requires authorized request token + $token = $this->get_token($request, $consumer, "request"); + + $this->check_signature($request, $consumer, $token); + + // Rev A change + $verifier = $request->get_parameter('oauth_verifier'); + $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); + + return $new_token; + } + + /** + * verify an api call, checks all the parameters + */ + public function verify_request(&$request) { + $this->get_version($request); + $consumer = $this->get_consumer($request); + $token = $this->get_token($request, $consumer, "access"); + $this->check_signature($request, $consumer, $token); + return array($consumer, $token); + } + + // Internals from here + /** + * version 1 + */ + private function get_version(&$request) { + $version = $request->get_parameter("oauth_version"); + if (!$version) { + // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. + // Chapter 7.0 ("Accessing Protected Ressources") + $version = '1.0'; + } + if ($version !== $this->version) { + throw new OAuthException("OAuth version '$version' not supported"); + } + return $version; + } + + /** + * figure out the signature with some defaults + */ + private function get_signature_method(&$request) { + $signature_method = + @$request->get_parameter("oauth_signature_method"); + + if (!$signature_method) { + // According to chapter 7 ("Accessing Protected Ressources") the signature-method + // parameter is required, and we can't just fallback to PLAINTEXT + throw new OAuthException('No signature method parameter. This parameter is required'); + } + + if (!in_array($signature_method, + array_keys($this->signature_methods))) { + throw new OAuthException( + "Signature method '$signature_method' not supported " . + "try one of the following: " . + implode(", ", array_keys($this->signature_methods)) + ); + } + return $this->signature_methods[$signature_method]; + } + + /** + * try to find the consumer for the provided request's consumer key + */ + private function get_consumer(&$request) { + $consumer_key = @$request->get_parameter("oauth_consumer_key"); + if (!$consumer_key) { + throw new OAuthException("Invalid consumer key"); + } + + $consumer = $this->data_store->lookup_consumer($consumer_key); + if (!$consumer) { + throw new OAuthException("Invalid consumer"); + } + + return $consumer; + } + + /** + * try to find the token for the provided request's token key + */ + private function get_token(&$request, $consumer, $token_type="access") { + $token_field = @$request->get_parameter('oauth_token'); + $token = $this->data_store->lookup_token( + $consumer, $token_type, $token_field + ); + if (!$token) { + throw new OAuthException("Invalid $token_type token: $token_field"); + } + return $token; + } + + /** + * all-in-one function to check the signature on a request + * should guess the signature method appropriately + */ + private function check_signature(&$request, $consumer, $token) { + // this should probably be in a different method + $timestamp = @$request->get_parameter('oauth_timestamp'); + $nonce = @$request->get_parameter('oauth_nonce'); + + $this->check_timestamp($timestamp); + $this->check_nonce($consumer, $token, $nonce, $timestamp); + + $signature_method = $this->get_signature_method($request); + + $signature = $request->get_parameter('oauth_signature'); + $valid_sig = $signature_method->check_signature( + $request, + $consumer, + $token, + $signature + ); + + if (!$valid_sig) { + throw new OAuthException("Invalid signature"); + } + } + + /** + * check that the timestamp is new enough + */ + private function check_timestamp($timestamp) { + if( ! $timestamp ) + throw new OAuthException( + 'Missing timestamp parameter. The parameter is required' + ); + + // verify that timestamp is recentish + $now = time(); + if (abs($now - $timestamp) > $this->timestamp_threshold) { + throw new OAuthException( + "Expired timestamp, yours $timestamp, ours $now" + ); + } + } + + /** + * check that the nonce is not repeated + */ + private function check_nonce($consumer, $token, $nonce, $timestamp) { + if( ! $nonce ) + throw new OAuthException( + 'Missing nonce parameter. The parameter is required' + ); + + // verify that the nonce is uniqueish + $found = $this->data_store->lookup_nonce( + $consumer, + $token, + $nonce, + $timestamp + ); + if ($found) { + throw new OAuthException("Nonce already used: $nonce"); + } + } + +} + +class OAuthDataStore { + function lookup_consumer($consumer_key) { + // implement me + } + + function lookup_token($consumer, $token_type, $token) { + // implement me + } + + function lookup_nonce($consumer, $token, $nonce, $timestamp) { + // implement me + } + + function new_request_token($consumer, $callback = null) { + // return a new token attached to this consumer + } + + function new_access_token($token, $consumer, $verifier = null) { + // return a new access token attached to this consumer + // for the user associated with this token if the request token + // is authorized + // should also invalidate the request token + } + +} + +class OAuthUtil { + public static function urlencode_rfc3986($input) { + if (is_array($input)) { + return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); + } else if (is_scalar($input)) { + return str_replace( + '+', + ' ', + str_replace('%7E', '~', rawurlencode($input)) + ); + } else { + return ''; + } +} + + + // This decode function isn't taking into consideration the above + // modifications to the encoding process. However, this method doesn't + // seem to be used anywhere so leaving it as is. + public static function urldecode_rfc3986($string) { + return urldecode($string); + } + + // Utility function for turning the Authorization: header into + // parameters, has to do some unescaping + // Can filter out any non-oauth parameters if needed (default behaviour) + public static function split_header($header, $only_allow_oauth_parameters = true) { + $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; + $offset = 0; + $params = array(); + while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { + $match = $matches[0]; + $header_name = $matches[2][0]; + $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; + if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { + $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); + } + $offset = $match[1] + strlen($match[0]); + } + + if (isset($params['realm'])) { + unset($params['realm']); + } + + return $params; + } + + // helper to try to sort out headers for people who aren't running apache + public static function get_headers() { + if (function_exists('apache_request_headers')) { + // we need this to get the actual Authorization: header + // because apache tends to tell us it doesn't exist + $headers = apache_request_headers(); + + // sanitize the output of apache_request_headers because + // we always want the keys to be Cased-Like-This and arh() + // returns the headers in the same case as they are in the + // request + $out = array(); + foreach( $headers AS $key => $value ) { + $key = str_replace( + " ", + "-", + ucwords(strtolower(str_replace("-", " ", $key))) + ); + $out[$key] = $value; + } + } else { + // otherwise we don't have apache and are just going to have to hope + // that $_SERVER actually contains what we need + $out = array(); + if( isset($_SERVER['CONTENT_TYPE']) ) + $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; + if( isset($_ENV['CONTENT_TYPE']) ) + $out['Content-Type'] = $_ENV['CONTENT_TYPE']; + + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) == "HTTP_") { + // this is chaos, basically it is just there to capitalize the first + // letter of every word that is not an initial HTTP and strip HTTP + // code from przemek + $key = str_replace( + " ", + "-", + ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) + ); + $out[$key] = $value; + } + } + } + return $out; + } + + // This function takes a input like a=b&a=c&d=e and returns the parsed + // parameters like this + // array('a' => array('b','c'), 'd' => 'e') + public static function parse_parameters( $input ) { + if (!isset($input) || !$input) return array(); + + $pairs = explode('&', $input); + + $parsed_parameters = array(); + foreach ($pairs as $pair) { + $split = explode('=', $pair, 2); + $parameter = OAuthUtil::urldecode_rfc3986($split[0]); + $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; + + if (isset($parsed_parameters[$parameter])) { + // We have already recieved parameter(s) with this name, so add to the list + // of parameters with this name + + if (is_scalar($parsed_parameters[$parameter])) { + // This is the first duplicate, so transform scalar (string) into an array + // so we can add the duplicates + $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); + } + + $parsed_parameters[$parameter][] = $value; + } else { + $parsed_parameters[$parameter] = $value; + } + } + return $parsed_parameters; + } + + public static function build_http_query($params) { + if (!$params) return ''; + + // Urlencode both keys and values + $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); + $values = OAuthUtil::urlencode_rfc3986(array_values($params)); + $params = array_combine($keys, $values); + + // Parameters are sorted by name, using lexicographical byte value ordering. + // Ref: Spec: 9.1.1 (1) + uksort($params, 'strcmp'); + + $pairs = array(); + foreach ($params as $parameter => $value) { + if (is_array($value)) { + // If two or more parameters share the same name, they are sorted by their value + // Ref: Spec: 9.1.1 (1) + natsort($value); + foreach ($value as $duplicate_value) { + $pairs[] = $parameter . '=' . $duplicate_value; + } + } else { + $pairs[] = $parameter . '=' . $value; + } + } + // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) + // Each name-value pair is separated by an '&' character (ASCII code 38) + return implode('&', $pairs); + } +} + +?> diff --git a/modules/twitter/twitteroauth/twitteroauth.php b/modules/twitter/twitteroauth/twitteroauth.php new file mode 100644 index 00000000..674308ae --- /dev/null +++ b/modules/twitter/twitteroauth/twitteroauth.php @@ -0,0 +1,245 @@ +<?php + +/* + * Abraham Williams (abraham@abrah.am) http://abrah.am + * + * The first PHP Library to support OAuth for Twitter's REST API. + */ + +/* Load OAuth lib. You can find it at http://oauth.net */ +require_once('OAuth.php'); + +/** + * Twitter OAuth class + */ +class TwitterOAuth { + /* Contains the last HTTP status code returned. */ + public $http_code; + /* Contains the last API call. */ + public $url; + /* Set up the API root URL. */ + public $host = "https://api.twitter.com/1/"; + /* Set timeout default. */ + public $timeout = 30; + /* Set connect timeout. */ + public $connecttimeout = 30; + /* Verify SSL Cert. */ + public $ssl_verifypeer = FALSE; + /* Respons format. */ + public $format = 'json'; + /* Decode returned json data. */ + public $decode_json = TRUE; + /* Contains the last HTTP headers returned. */ + public $http_info; + /* Set the useragnet. */ + public $useragent = 'TwitterOAuth v0.2.0-beta2'; + /* Immediately retry the API call if the response was not successful. */ + //public $retry = TRUE; + + + + + /** + * Set API URLS + */ + function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; } + function authenticateURL() { return 'https://twitter.com/oauth/authenticate'; } + function authorizeURL() { return 'https://twitter.com/oauth/authorize'; } + function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; } + + /** + * Debug helpers + */ + function lastStatusCode() { return $this->http_status; } + function lastAPICall() { return $this->last_api_call; } + + /** + * construct TwitterOAuth object + */ + function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) { + $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1(); + $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); + if (!empty($oauth_token) && !empty($oauth_token_secret)) { + $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret); + } else { + $this->token = NULL; + } + } + + + /** + * Get a request_token from Twitter + * + * @returns a key/value array containing oauth_token and oauth_token_secret + */ + function getRequestToken($oauth_callback = NULL) { + $parameters = array(); + if (!empty($oauth_callback)) { + $parameters['oauth_callback'] = $oauth_callback; + } + $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters); + $token = OAuthUtil::parse_parameters($request); + $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); + return $token; + } + + /** + * Get the authorize URL + * + * @returns a string + */ + function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) { + if (is_array($token)) { + $token = $token['oauth_token']; + } + if (empty($sign_in_with_twitter)) { + return $this->authorizeURL() . "?oauth_token={$token}"; + } else { + return $this->authenticateURL() . "?oauth_token={$token}"; + } + } + + /** + * Exchange request token and secret for an access token and + * secret, to sign API calls. + * + * @returns array("oauth_token" => "the-access-token", + * "oauth_token_secret" => "the-access-secret", + * "user_id" => "9436992", + * "screen_name" => "abraham") + */ + function getAccessToken($oauth_verifier = FALSE) { + $parameters = array(); + if (!empty($oauth_verifier)) { + $parameters['oauth_verifier'] = $oauth_verifier; + } + $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters); + $token = OAuthUtil::parse_parameters($request); + $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); + return $token; + } + + /** + * One time exchange of username and password for access token and secret. + * + * @returns array("oauth_token" => "the-access-token", + * "oauth_token_secret" => "the-access-secret", + * "user_id" => "9436992", + * "screen_name" => "abraham", + * "x_auth_expires" => "0") + */ + function getXAuthToken($username, $password) { + $parameters = array(); + $parameters['x_auth_username'] = $username; + $parameters['x_auth_password'] = $password; + $parameters['x_auth_mode'] = 'client_auth'; + $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters); + $token = OAuthUtil::parse_parameters($request); + $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); + return $token; + } + + /** + * GET wrapper for oAuthRequest. + */ + function get($url, $parameters = array()) { + $response = $this->oAuthRequest($url, 'GET', $parameters); + if ($this->format === 'json' && $this->decode_json) { + return json_decode($response); + } + return $response; + } + + /** + * POST wrapper for oAuthRequest. + */ + function post($url, $parameters = array()) { + $response = $this->oAuthRequest($url, 'POST', $parameters); + if ($this->format === 'json' && $this->decode_json) { + return json_decode($response); + } + return $response; + } + + /** + * DELETE wrapper for oAuthReqeust. + */ + function delete($url, $parameters = array()) { + $response = $this->oAuthRequest($url, 'DELETE', $parameters); + if ($this->format === 'json' && $this->decode_json) { + return json_decode($response); + } + return $response; + } + + /** + * Format and sign an OAuth / API request + */ + function oAuthRequest($url, $method, $parameters) { + if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) { + $url = "{$this->host}{$url}.{$this->format}"; + } + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters); + $request->sign_request($this->sha1_method, $this->consumer, $this->token); + switch ($method) { + case 'GET': + return $this->http($request->to_url(), 'GET'); + default: + return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata()); + } + } + + /** + * Make an HTTP request + * + * @return API results + */ + function http($url, $method, $postfields = NULL) { + $this->http_info = array(); + $ci = curl_init(); + /* Curl settings */ + curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent); + curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); + curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:')); + curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); + curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader')); + curl_setopt($ci, CURLOPT_HEADER, FALSE); + + switch ($method) { + case 'POST': + curl_setopt($ci, CURLOPT_POST, TRUE); + if (!empty($postfields)) { + curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); + } + break; + case 'DELETE': + curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE'); + if (!empty($postfields)) { + $url = "{$url}?{$postfields}"; + } + } + + curl_setopt($ci, CURLOPT_URL, $url); + $response = curl_exec($ci); + $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE); + $this->http_info = array_merge($this->http_info, curl_getinfo($ci)); + $this->url = $url; + curl_close ($ci); + return $response; + } + + /** + * Get the header info to store. + */ + function getHeader($ch, $header) { + $i = strpos($header, ':'); + if (!empty($i)) { + $key = str_replace('-', '_', strtolower(substr($header, 0, $i))); + $value = trim(substr($header, $i + 2)); + $this->http_header[$key] = $value; + } + return strlen($header); + } +} diff --git a/templates/show_now_playing.inc.php b/templates/show_now_playing.inc.php index 05b3f828..35e3d3f9 100644 --- a/templates/show_now_playing.inc.php +++ b/templates/show_now_playing.inc.php @@ -30,8 +30,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. if (count($results)) { $link = Config::get('use_rss') ? ' ' . AmpacheRSS::get_display('nowplaying') : ''; +$link2 = '<a href="' . Config::get('web_path') . '/modules/twitter/twitter_login.php"><img src="' . Config::get('web_path') . '/modules/twitter/Twitter-Icon.png" width="18" height="18"></a>'; ?> -<?php show_box_top(_('Now Playing') . $link); ?> +<?php show_box_top(_('Now Playing') . $link . $link2 ); ?> <?php foreach ($results as $item) { $media = $item['media']; |