Search Blog

Author: Joe Meyer
Date: January 2, 2014

Goal: Edit website in browser

Difficulty: Easy

Prerequisites: Browser with Javascript Enabled

What this tutorial will allow you to do is to edit any web page in your browser. Please keep in mind that this doesn't permanently change the page you are modifying, it only changes your local copy for that page load so as soon as you refresh all the changes you made will disappear. Nonetheless, it's the perfect bit of code for printing off that news article and substituting your best buddy's name and photo in and printing it out to show them for a good laugh.

  1. Visit the web page you wish to make changes to.
  2. In the URL / Address bar replace the contents of the current url with the following code snippit:
    javascript:document.body.contentEditable='true'; document.designMode='on'; void 0
  3. Edit until your heart's content

Author: Joe Meyer
Date: January 2, 2014

ASCII Values are 8 bit values (256 combinations) that are translated into characters. This is one major type of character encoding. Below I have compiled a list of ascii values in base 10 (decimal), base 8 (Octal), base 16 (hexadecimal), and base 2 (binary). This is a good reference as ASCII is widely used in many programming languages.

Dec OCT Hex Binary   Character
--- --- --  -------- -------------------------------
000 000 00  00000000 NUL (Null char.)
001 001 01  00000001 SOH (Start of Header)
002 002 02  00000010 STX (Start of Text)
003 003 03  00000011 ETX (End of Text)
004 004 04  00000100 EOT (End of Transmission)
005 005 05  00000101 ENQ (Enquiry)
006 006 06  00000110 ACK (Acknowledgment)
007 007 07  00000111 BEL (Bell)
008 010 08  00001000 BS (Backspace)
009 011 09  00001001 HT (Horizontal Tab)
010 012 0A  00001010 LF (Line Feed)
011 013 0B  00001011 VT (Vertical Tab)
012 014 0C  00001100 FF (Form Feed)
013 015 0D  00001101 CR (Carriage Return)
014 016 0E  00001110 SO (Shift Out)
015 017 0F  00001111 SI (Shift In)
016 020 10  00010000 DLE (Data Link Escape)
017 021 11  00010001 DC1 (XON)(Device Control 1)
018 022 12  00010010 DC2 (Device Control 2)
019 023 13  00010011 DC3 (XOFF)(Device Control 3)
020 024 14  00010100 DC4 (Device Control 4)
021 025 15  00010101 NAK (Negative Acknowledgement)
022 026 16  00010110 SYN (Synchronous Idle)
023 027 17  00010111 ETB (End of Trans. Block)
024 030 18  00011000 CAN (Cancel)
025 031 19  00011001 EM (End of Medium)
026 032 1A  00011010 SUB (Substitute)
027 033 1B  00011011 ESC (Escape)
028 034 1C  00011100 FS (File Separator)
029 035 1D  00011101 GS (Group Separator)
030 036 1E  00011110 RS (Request to Send)(Record Separator)
031 037 1F  00011111 US (Unit Separator)
032 040 20  00100000 SP (Space)
033 041 21  00100001 ! (exclamation mark)
034 042 22  00100010 " (double quote)
035 043 23  00100011 # (number sign)
036 044 24  00100100 $ (dollar sign)
037 045 25  00100101 % (percent)
038 046 26  00100110 & (ampersand)
039 047 27  00100111 ' (single quote)
040 050 28  00101000 ( (left opening parenthesis)
041 051 29  00101001 ) (right closing parenthesis)
042 052 2A  00101010 * (asterisk)
043 053 2B  00101011 + (plus)
044 054 2C  00101100 , (comma)
045 055 2D  00101101 - (minus or dash)
046 056 2E  00101110 . (dot)
047 057 2F  00101111 / (forward slash)
048 060 30  00110000 0
049 061 31  00110001 1
050 062 32  00110010 2
051 063 33  00110011 3
052 064 34  00110100 4
053 065 35  00110101 5
054 066 36  00110110 6
055 067 37  00110111 7
056 070 38  00111000 8
057 071 39  00111001 9
058 072 3A  00111010 : (colon)
059 073 3B  00111011 ; (semi-colon)
060 074 3C  00111100 < (less than sign)
061 075 3D  00111101 = (equal sign)
062 076 3E  00111110 > (greater than sign)
063 077 3F  00111111 ? (question mark)
064 100 40  01000000 @ (AT symbol)
065 101 41  01000001 A
066 102 42  01000010 B
067 103 43  01000011 C
068 104 44  01000100 D
069 105 45  01000101 E
070 106 46  01000110 F
071 107 47  01000111 G
072 110 48  01001000 H
073 111 49  01001001 I
074 112 4A  01001010 J
075 113 4B  01001011 K
076 114 4C  01001100 L
077 115 4D  01001101 M
078 116 4E  01001110 N
079 117 4F  01001111 O
080 120 50  01010000 P
081 121 51  01010001 Q
082 122 52  01010010 R
083 123 53  01010011 S
084 124 54  01010100 T
085 125 55  01010101 U
086 126 56  01010110 V
087 127 57  01010111 W
088 130 58  01011000 X
089 131 59  01011001 Y
090 132 5A  01011010 Z
091 133 5B  01011011 [ (left opening bracket)
092 134 5C  01011100 \ (back slash)
093 135 5D  01011101 ] (right closing bracket)
094 136 5E  01011110 ^ (caret cirumflex)
095 137 5F  01011111 _ (underscore)
096 140 60  01100000 `
097 141 61  01100001 a
098 142 62  01100010 b
099 143 63  01100011 c
100 144 64  01100100 d
101 145 65  01100101 e
102 146 66  01100110 f
103 147 67  01100111 g
104 150 68  01101000 h
105 151 69  01101001 i
106 152 6A  01101010 j
107 153 6B  01101011 k
108 154 6C  01101100 l
109 155 6D  01101101 m
110 156 6E  01101110 n
111 157 6F  01101111 o
112 160 70  01110000 p
113 161 71  01110001 q
114 162 72  01110010 r
115 163 73  01110011 s
116 164 74  01110100 t
117 165 75  01110101 u
118 166 76  01110110 v
119 167 77  01110111 w
120 170 78  01111000 x
121 171 79  01111001 y
122 172 7A  01111010 z
123 173 7B  01111011 { (left opening brace)
124 174 7C  01111100 | (vertical bar)
125 175 7D  01111101 } (right closing brace)
126 176 7E  01111110 ~ (tilde)
127 177 7F  01111111 DEL (delete)
128 200 80  10000000 €
129 201 81  10000001 
130 202 82  10000010 ‚
131 203 83  10000011 ƒ
132 204 84  10000100 „
133 205 85  10000101 …
134 206 86  10000110 †
135 207 87  10000111 ‡
136 210 88  10001000 ˆ
137 211 89  10001001 ‰
138 212 8A  10001010 Š
139 213 8B  10001011 ‹
140 214 8C  10001100 Œ
141 215 8D  10001101 
142 216 8E  10001110 Ž
143 217 8F  10001111 
144 220 90  10010000 
145 221 91  10010001 ‘
146 222 92  10010010 ’
147 223 93  10010011 “
148 224 94  10010100 ”
149 225 95  10010101 •
150 226 96  10010110 –
151 227 97  10010111 —
152 230 98  10011000 ˜
153 231 99  10011001 ™
154 232 9A  10011010 š
155 233 9B  10011011 ›
156 234 9C  10011100 œ
157 235 9D  10011101 
158 236 9E  10011110 ž
159 237 9F  10011111 Ÿ
160 240 A0  10100000 
161 241 A1  10100001 ¡
162 242 A2  10100010 ¢
163 243 A3  10100011 £
164 244 A4  10100100 ¤
165 245 A5  10100101 ¥
166 246 A6  10100110 ¦
167 247 A7  10100111 §
168 250 A8  10101000 ¨
169 251 A9  10101001 ©
170 252 AA  10101010 ª
171 253 AB  10101011 «
172 254 AC  10101100 ¬
173 255 AD  10101101 ­
174 256 AE  10101110 ®
175 257 AF  10101111 ¯
176 260 B0  10110000 °
177 261 B1  10110001 ±
178 262 B2  10110010 ²
179 263 B3  10110011 ³
180 264 B4  10110100 ´
181 265 B5  10110101 µ
182 266 B6  10110110 ¶
183 267 B7  10110111 ·
184 270 B8  10111000 ¸
185 271 B9  10111001 ¹
186 272 BA  10111010 º
187 273 BB  10111011 »
188 274 BC  10111100 ¼
189 275 BD  10111101 ½
190 276 BE  10111110 ¾
191 277 BF  10111111 ¿
192 300 C0  11000000 À
193 301 C1  11000001 Á
194 302 C2  11000010 Â
195 303 C3  11000011 Ã
196 304 C4  11000100 Ä
197 305 C5  11000101 Å
198 306 C6  11000110 Æ
199 307 C7  11000111 Ç
200 310 C8  11001000 È
201 311 C9  11001001 É
202 312 CA  11001010 Ê
203 313 CB  11001011 Ë
204 314 CC  11001100 Ì
205 315 CD  11001101 Í
206 316 CE  11001110 Î
207 317 CF  11001111 Ï
208 320 D0  11010000 Ð
209 321 D1  11010001 Ñ
210 322 D2  11010010 Ò
211 323 D3  11010011 Ó
212 324 D4  11010100 Ô
213 325 D5  11010101 Õ
214 326 D6  11010110 Ö
215 327 D7  11010111 ×
216 330 D8  11011000 Ø
217 331 D9  11011001 Ù
218 332 DA  11011010 Ú
219 333 DB  11011011 Û
220 334 DC  11011100 Ü
221 335 DD  11011101 Ý
222 336 DE  11011110 Þ
223 337 DF  11011111 ß
224 340 E0  11100000 à
225 341 E1  11100001 á
226 342 E2  11100010 â
227 343 E3  11100011 ã
228 344 E4  11100100 ä
229 345 E5  11100101 å
230 346 E6  11100110 æ
231 347 E7  11100111 ç
232 350 E8  11101000 è
233 351 E9  11101001 é
234 352 EA  11101010 ê
235 353 EB  11101011 ë
235 354 EC  11101100 ì
237 355 ED  11101101 í
238 356 EE  11101110 î
239 357 EF  11101111 ï
240 360 F0  11110000 ð
241 361 F1  11110001 ñ
242 362 F2  11110010 ò
243 363 F3  11110011 ó
244 364 F4  11110100 ô
245 365 F5  11110101 õ
246 366 F6  11110110 ö
247 367 F7  11110111 ÷
248 370 F8  11111000 ø
249 371 F9  11111001 ù
250 372 FA  11111010 ú
251 373 FB  11111011 û
252 374 FC  11111100 ü
253 375 FD  11111101 ý 
254 376 FE  11111110 þ
255 377 FF  11111111 ÿ 

Author: Joe Meyer
Date: January 2, 2014

Goal: Create a secure way to simply copy/move files from one linux machine to another

Difficulty: Medium

Prerequisites: Access to a Linux console

SSH Keys are extremely useful way of security your Linux server. It is often considered best practices to have servers which have an internet accessible ssh connection disallow password authentication and use ssh authentication only. This drastically decreases the chance that your server gets hacked by any sort of brute force method. It also is a great way to have two linux based server communicate with each other. Whether it be copying files between two Linux servers, or setting up a synchronization job, ssh keys are the way to go to automate and secure these processes. Below I will outline how to go about creating these ssh keys and using them.

Adding SSH Keys

  • Log in to the source machine that you eventually want to copy your files from
  • Run the following command from your home directory
    ssh-keygen -t rsa
  • When prompted for a file in which to save the key, you can either specify a file name or leave it blank for it to default into the id_rsa key file. Also, here you will be prompted for a passphrase. If you want to be able to ssh/scp/rsync without using a password (as is often the case for cron jobs) you should leave the passphrase blank. After it is generated it will spit back a key fingerprint and some other information.
  • Next we need to copy our public key to the destination server. This means you need to have an account that you know the username and password for on the destination server. We copy our key by running the following command:
    ssh-copy-id -i ./.ssh/id_rsa.pub username@destinationserver
    Note: id_rsa.pub is the name of your file you generated in step 2/3, username is the username of your account on the destination server, and destination server is the ip address or DNS A or CNAME record of your server.
  • You will likely be prompted about the authenticity of the host and it will ask you if you want to continue connecting. Type yes
    Note: For me I was not able to get by with just typing "y" I had to type out the full word. Also, if your home directory is not secure (IE if you have the permissions set to 775 or 777), you will need to modify the /etc/ssh/sshd_config file on your destination server and set "StrictModes No" so that this will work. If your security is set up properly this shouldn't be a problem.
  • You sould now be set up with your ssh key and now we get to show you what cool things you can do with this.

Using SCP (Secure Copy) and Shell via SSH

  • To run shell commands on your remote server from your "source" server you can use the following commands
    ssh <destinationserver> "command"
    Example: ssh server.exchangecore.com "ping google.com -n 8"
  • You can also put yourself onto the server if you want to run a series of commands by using:
    ssh <destinationserver>

    Example: ssh server.example.com
    Note: To return back to your "source" machine use the exit command
  • SCP is a very powerful tool when you need to move files from one server to another. While not as rubust as some other tools such as rsync, it still does the job just fine in many instances. SCP can be done by running the following command:
    scp <sourceFilePath> <desginationServer>:/<destinationFilePath>

    A really useful feature to scp is it's ability to pull files from the other server as well
    scp <serverToPullFrom>:/<sourceFilePath> <destinationFilePath>

And there you have a quick overview on how to set up ssh (which can also be used for rsync) and on how to use ssh to access the shell cli on your newly connected server, as well as a brief introduction to using scp to move some files. 

Author: Joe Meyer
Date: January 1, 2014

Goal: Selecting the top value for by group (such as highest date or largest value)

Difficulty: Easy

Prerequisites: Access to run SELECT queries on MySQL

Here is the data in our example table:

Table: Images

ID          Gallery          Submitted                  Description
-------     --------         -----------------          ------------------------
1           Cats             12-01-2012 00:00:12        This is my pretty kitty
2           Dogs             12-01-2012 03:00:12        Bowowow
3           Dogs             12-04-2012 05:00:12        Who let the dogs out
4           Cats             12-05-2012 01:00:12        MEOOOW
5           Birds            12-06-2012 01:00:12        Polly Wants a Cracker

Now in our example we want to find the last image submitted for each gallery.  Now normal Group By queries can get you the Gallery and Submitted field, unfortunately you cannot also retrieve the ID and description with these when using a group by. So in my query example below I join the table back to itself and find the largest submitted time in a group by using a left join, which will allow us to identify the largest records by finding the rows where the left join failed to join to anything that was bigger than itself.

SELECT i1.*
FROM Images AS i1 LEFT JOIN images AS i2
ON (i1.Gallery = i2.Gallery AND i1.Submitted < i2.Submitted)
WHERE i2.Submitted IS NULL;

Running the query above will get you the following results table:

ID          Gallery          Submitted                  Description
-------     --------        -----------------         ------------------------
3           Dogs             12-04-2012 05:00:12        Who let the dogs out
4           Cats             12-05-2012 01:00:12        MEOOOW
5           Birds            12-06-2012 01:00:12        Polly Wants a Cracker

And there you have it.  A simple and efficient way to get the largest record in a group. 

Author: Chris Hougard
Date: January 1, 2014

Goal: Using netstat to view information about connections

Difficulty: Easy

Prerequisites: Access to a Linux console

Lets start with the basics. The "netstat" command is quite useful for checking connections to your machine. If we wanted to see ALL of the connections (which i really recommend you don't do unless you're trying to debug something and then you should probably pipe it to a file) we could use the "netstat -a" command.

Using "netstat -a" will give you something sort of like this (this is a segment of my server):

tcp	 0	 0 app.mydomain.com:http	 93.184.216.119:16494	 SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 93.184.216.119:18733	 SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 93.184.216.119.dsl.mwe:64775 SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 93.184.216.119.threembb.:16490 SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 93.184.216.119:video-activmail SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 93.184.216.119:45025	 SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 93.184.216.119:dvl-activemail SYN_RECV
tcp	 0	 0 app.mydomain.com:http	 41-135-22-100.dsl.mwe:64774 SYN_RECV

As you can see it does name resolving for us and all that good stuff. Sometimes very hand but that's not what this is about. We want to get some solid numbers so we can take a broader perspective. To do this we can use the following command:

netstat -an | wc -l

This will show us a count of all connections that we presently have to our machine. But we can take this one step further even. Lets say you only wanted to see traffic comming across port 80 (standard http). We can grep our netstat then count it like so:

netstat -an | grep :80 | wc -l

Finally, lets take a look at the big picture in a category form. It is often extremely useful to see what those connections are doing, especially when you think you might just have tons of open connections that are idle and are trying to tweak your settings. It's been known to happen where you have a really busy web server for instance, and maybe it's running a lot of database connections to the same box, then stopping. That often causes things like the TIME_WAIT to pile up and a large number for any of these may be an indication that you need to adjust your tcp timeout settings.

netstat -ant | awk '{print $6}' | sort | uniq -c | sort -n
      1 CLOSING
      1 established
      1 FIN_WAIT2
      1 Foreign
      2 CLOSE_WAIT
      6 FIN_WAIT1
      7 LAST_ACK
      7 SYN_RECV
     37 ESTABLISHED
     44 LISTEN
    297 TIME_WAIT

So there you have it. A quick way to return counts on your connections in your linux environment. (Note the netstat command is standard on most operating systems, including windows, but you may need to use some other way to count your results)

Occasionally, when using netstat you may only care about ports that you are listening on. This is especially important if you are running a server that isn't behind a firewall because it helps you determine what you may be vulnerable to that you aren't aware of. using the netstat -l provides us with an excellent way to view this information.

root@nox [~]# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
tcp        0      0 *:mysql                     *:*                         LISTEN
tcp        0      0 *:submission                *:*                         LISTEN
tcp        0      0 *:pop3                      *:*                         LISTEN
tcp        0      0 localhost:783               *:*                         LISTEN

Another very common thing and powerful tool that netstat has built in is to show you network statistics in an overview fashion. If you're just trying to get a good idea about packet statistics then the netstat -s command may be what you're looking for. Here is some sample output. Keep in mind that netstat -s will show statistics broken down by protocol, so the fewer protocol stacks you are running the more compacted this summary will be.

netstat -s
Ip:
    139502653 total packets received
    28 with invalid addresses
    0 forwarded
    0 incoming packets discarded
    133312468 incoming packets delivered
    84570989 requests sent out
    366 outgoing packets dropped
    50 reassemblies required
    25 packets reassembled ok
    110 fragments received ok
    220 fragments created
Icmp:
    180285 ICMP messages received
    1586 input ICMP message failed.
    ICMP input histogram:
        destination unreachable: 9516
        timeout in transit: 331
        echo requests: 170151
        echo replies: 284
    172009 ICMP messages sent
    0 ICMP messages failed
    ICMP output histogram:
        destination unreachable: 1818
        echo request: 40
        echo replies: 170151
IcmpMsg:
        InType0: 284
        InType3: 9516
        InType8: 170151
        InType11: 331
        OutType0: 170151
        OutType3: 1818
        OutType8: 40
Tcp:
    1104118 active connections openings
    2918161 passive connection openings
    26607 failed connection attempts
    256788 connection resets received
    10 connections established
    128535136 segments received
    78146054 segments send out
    1645036 segments retransmited
    0 bad segments received.
    185776 resets sent
Udp:
    5125395 packets received
    1867 packets to unknown port received.
    0 packet receive errors
    5158639 packets sent
TcpExt:
    511 SYN cookies sent
    511 SYN cookies received
    12748 invalid SYN cookies received
    14894 resets received for embryonic SYN_RECV sockets
    159972 packets pruned from receive queue because of socket buffer overrun
    2 packets pruned from receive queue
    73 ICMP packets dropped because they were out-of-window
    1965839 TCP sockets finished time wait in fast timer
    78 time wait sockets recycled by time stamp
    36503 packets rejects in established connections because of timestamp
    2487605 delayed acks sent
    33477 delayed acks further delayed because of locked socket
    Quick ack mode was activated 45146 times
    233 times the listen queue of a socket overflowed
    233 SYNs to LISTEN sockets ignored
    9643039 packets directly queued to recvmsg prequeue.
    7969358 packets directly received from backlog
    3291115817 packets directly received from prequeue
    24087199 packets header predicted
    5532135 packets header predicted and directly queued to user
    30481401 acknowledgments not containing data received
    42935286 predicted acknowledgments
    814 times recovered from packet loss due to fast retransmit
    339835 times recovered from packet loss due to SACK data
    336 bad SACKs received
    Detected reordering 2070 times using FACK
    Detected reordering 854 times using SACK
    Detected reordering 10 times using reno fast retransmit
    Detected reordering 1840 times using time stamp
    3234 congestion windows fully recovered
    20175 congestion windows partially recovered using Hoe heuristic
    TCPDSACKUndo: 11509
    14757 congestion windows recovered after partial ack
    1004274 TCP data loss events
    TCPLostRetransmit: 54568
    129 timeouts after reno fast retransmit
    33120 timeouts after SACK recovery
    31346 timeouts in loss state
    885023 fast retransmits
    93299 forward retransmits
    337378 retransmits in slow start
    128472 other TCP timeouts
    TCPRenoRecoveryFail: 356
    35936 sack retransmits failed
    9 times receiver scheduled too late for direct processing
    57242284 packets collapsed in receive queue due to low socket buffer
    49286 DSACKs sent for old packets
    157 DSACKs sent for out of order packets
    95033 DSACKs received
    2091 DSACKs for out of order packets received
    39363 connections reset due to unexpected data
    35517 connections reset due to early user close
    12861 connections aborted due to timeout
    6 times unable to send RST due to no memory
    TCPSACKDiscard: 60
    TCPDSACKIgnoredOld: 2937
    TCPDSACKIgnoredNoUndo: 38596
    TCPSpuriousRTOs: 2925
    TCPSackShifted: 1905464
    TCPSackMerged: 2048679
    TCPSackShiftFallback: 995770
    TCPBacklogDrop: 41842
IpExt:
    InBcastPkts: 20
    InOctets: 60455654365
    OutOctets: 154094094438
    InBcastOctets: 6560

Another extremely useful tool for server administrators who are trying to track down processes that have run amuck is the netstat -p command. This returns the PID of the process that has the connection. It's also quite useful if you've got someone abusing a PID and you need to find out what IP it is so that you can get in touch with that individual or to block connections from that IP in the future. Here's some sample output from netstat -p.

netstat -p
tcp        0      0 localhost:56423  example.domain.com:https ESTABLISHED 27911/java
tcp        0     52 localhost:ssh    oh-76-76-76-76.dhcp.e:51653 ESTABLISHED 3344/sshd
tcp        0      0 localhost:imaps  76.sub-76-76-76.myvz:9258 ESTABLISHED 14501/dovecot/imap-

Author: Chris Hougard
Date: January 1, 2014

Goal: Navigating the Linux file system

Difficulty: Easy

Prerequisites: Access to a Linux console

One of the most common things a server administrator has to do is navigate through the operating system. While in many ways this is a very trivial task there are a few shortcuts that some may not know about.The cd command is by var the easiest way to navigate to your files.

To change directory you can use the following syntax:

[~]# cd [directory]

Take the scenario where you are sitting in /home/ and want to navigate into /home/joe you could run the following command:

[/home]# cd joe

Now lets say you are currently residing in /home/joe, but you want to switch to view the mysql logs on your server. Instead of going back to root then going up through the directories one at a time, you can specify that you want to start at the root by starting your [directory] with a / like so:

[/home/joe]# cd /var/lib/mysql/

Notice that since i proceeded var with the / the cd command knows that we are not going to /home/joe/var/lib/mysql but instead to /var/lib/mysql.

If you want to change directory into the directory above your current location you can use .. for the directory. In this example it will take you from /home/joe back to /home.

[/home/joe]# cd ..

Similarly if you wanted to go back up 2 directories you could use the following command:

[/home/joe]# cd ../../

If you want to change directory back to your home directory at any time you can use the command below. In this example I will be going from /var/lib/mysql to /home/joe since I am logged in as the user joe.

[/var/lib/mysql]# cd ~

Finally, one of the commands that I find myself using extremely frequently is the command to return / go back to your last directory you were working from. So for example, if I change directory from /var/lib/mysql to /etc, then want to go back to /var/lib/mysql I can use this command to go back one directory:

[/etc]# cd -

Author: Chris Hougard
Date: January 1, 2014

This code allows you to embed a Facebook gallery from a page directly on a website using Facebook's API. It requires jQuery and Fancybox.

To use place the following javascript and css on your website. Then place <div id="facebookPhotoGallery"></div> where you want the gallery to be. Replace PAGE ID HERE with the ID of your Facebook page.

JavaScript

(function($) {
    var History = window.History;
    jQuery.support.cors = true;
    jQuery.ajaxSetup({
        beforeSend: function() {
            $('.loader').show();
        },
        complete: function(){
            $('.loader').hide();
        }
    });
    function processState(state) {
        if('album' in state.data) {
            $.fancybox.close();
            facebookAlbumImages(state.data.album);
        } else if('image' in state.data) {
            // get the album id
            $.getJSON('https://graph.facebook.com/' + state.data.image, function(response) {
                var re = /a\.([0-9]+)\./g;
                facebookAlbumImages(re.exec(response.link)[1]);
            });
        } else {
            facebookAlbums(PAGE ID HERE);
        }
    }
    // Bind to StateChange Event
    History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
        var state = History.getState(); // Note: We are using History.getState() instead of event.state
        processState(state);
    });
    function facebookAlbumImages(albumID) {
        $.getJSON('https://graph.facebook.com/' + albumID + '/photos?callback=?', function(response) {
            var data = response.data;
            if(!('image' in History.getState().data)) {
                History.pushState({album:albumID}, null, "?album=" + albumID);
            }
            $("#facebookPhotoGallery").html("<div id='facebookImages'></div>");
            $.each(data, function(index, imageData) {
                var thumb = imageData.images[5];
                $("#facebookImages").append("<div class='facebookImgThumb " + imageData.id + "'><a href='" + imageData.source + "' title='' class='fancybox' rel='facebookGalleryImages'><i style='background-image: url(" + thumb.source + ")'></i></a></div>");
            });
        });
    }
    $(document).on("click", ".facebookImgThumb > a.fancybox", function() {
        var imageID = $(this).parent().attr("class").split(" ")[1];
        History.pushState({image:imageID}, null, "?image=" + imageID);
    });
    function facebookAlbums(oID) {
        $.getJSON('https://graph.facebook.com/' + oID + '/albums?callback=?', function(response) {
            console.log("working?");
            var data = response.data;
            $("#facebookPhotoGallery").html("<div id='facebookAlbums'></div>");
            $.each(data, function(index, val) {
                if('cover_photo' in val) {
                    $.getJSON('https://graph.facebook.com/' + val.cover_photo + '?callback=?', function(responsePicture) {
                        // calculate size
                        var image = responsePicture.images[5];
                        $("#facebookAlbums").append("<div class='facebookImgThumb " + val.id + "'><i style='background-image: url(" + image.source + ")'></i><p>" + val.name + "</p></div>");
                    });
                }
            });
        }).error(function(jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            });
        $(document).on("click", ".facebookImgThumb", function() {
            $(document).off("click", ".facebookImgThumb");
            var albumID = $(this).attr("class").split(" ")[1];
            History.pushState({album:albumID}, null, "?album=" + albumID);
        });
    }
    $(".fancybox").fancybox({
        openEffect: 'none',
        closeEffect: 'none',
        afterClose: function() {
            console.log("Going back!");
            History.back();
        }
    });
    processState(History.getState());
})(jQuery);

CSS

.facebookImgThumb i {
border: 2px solid #b0b0b0;
padding: 0;
margin: 0;
vertical-align: middle;
width: 149px;
height: 116px;
display: inline-block;
background-position: center 25%;
background-repeat: no-repeat;
}
.facebookImgThumb p {
vertical-align: bottom;
font-size: 0.85em;
}
.facebookImgThumb {
margin: 5px;
display: inline-block;
width: 151px;
}
.facebookImgThumb:hover {
cursor: pointer;
}
.loader{
display:none;
/*set the div in the bottom right corner*/
position:fixed;
bottom:8px;
right:8px;
width:31px;
height:31px;
/*give it some background and border*/
background:url(https://dl.dropbox.com/u/1017142/ajax-loader.gif) no-repeat;
}