I decided to start with the Mac logoff hook because it is something I really want to get done and many of the readings had pieces of the script I was going to write, so I just started putting them together.
The purpose of this script is to delete all of the users that are not the Administrator every time a Mac computer is logged off. At my place of work, we have five public Macs that are connected to AD, which creates a local user account every time someone logs in. Deleting user accounts is currently a manual process that could easily be scripted.
The first script I wrote was just to test that 'for file in *; do' would search directories as well as files. I used a simple echo on the folder I will eventually be working in (/users) to see if it worked. It did, so I moved on.
test1.sh:- #!/bin/bash
- cd /users
- for file in *; do
- echo "name is $file"
- done
Next, I wanted to see if the 'if...else' would work in the loop as I wrote it from pieces of examples I had seen. I changed the directory to a TEMP that I created with a bunch of folders and files in them so I would not ruin anything on my own computer. I named one folder Administrator to simulate the real situation. I had an 'exit' after the 'else' that prevented the loop from completing, so I took it out. The first time through, I only had an 'echo' in the 'else' statement to ensure it was only touching the files I wanted it to. Once that worked, I put 'rm -rf' in. All good.
test2.sh:- #!/bin/bash
- cd /TEMP
- for file in *; do
- if [ "$file" = Administrator ]
- then
- echo "Administrator account NOT Deleted"
- else
- rm -rf $file
- echo "$file Deleted"
- then
- fi
- done
Third, I decided to write all output to a .txt file in /Libraries/Log. If this is going to be a logoff hook, I will not be able to watch the echoes in the terminal window, so I need to know I am outputting them correctly. I again took out the deletion code so that the script ONLY echoes. I also added a date and timestamp at the beginning so in the future I can see what happened when. I also added a 'script completed' and then a blank line to make the log readable. I chose to append ">>" the file so that I could have a running log of all data. The script works from the command line.
test3.sh:- #!/bin/bash
- date >> /Library/Logs/acctDel.txt
- cd /TEMP
- for file in *; do
- if [ "$file" = Administrator ]
- then
- echo "Administrator account NOT Deleted" >>
/Library/Logs/acctDel.txt
- echo "Administrator account NOT Deleted" >>
- else
- echo "User $file Deleted" >> /Library/Logs/acctDel.txt
- then
- fi
- done
- echo "Script completed." >> /Library/Logs/acctDel.txt
- echo "" >> /Library/Logs/acctDel.txt
Fourth, I used the following websites to learn how to add a logoff hook to a mac: http://www.bombich.com/mactips/loginhooks.html and http://docs.info.apple.com/article.html?artnum=301446. I used this on my own mac to test the hook itself works.
Add LogoutHook:- sudo defaults write com.apple.loginwindow LogoutHook /Library/Scripts/MyScripts/test3.sh
The hook and script worked fine, so I added the deletion line back in and tested it again. Then with the help of this site: http://developer.apple.com/documentation/MacOSX/Conceptual/
BPSystemStartup/Articles/CustomLogin.html I removed the logout hook from my own machine.
- sudo defaults delete com.apple.loginwindow LoginHook
Attached is my script to be tested on the Macs at work: asmt1.sh The folder name has been changed back to /Users, and the 'rm -rf' line has been commented out until it has been tested. Once at work, I will run it from the command line on every Mac to ensure the adminstrator account is seen correctly by the script. Then I will save it to /Library/MyScripts, create the logout hook, logout, and ensure the log file has the correct output. Once I am satisfied that it works, I will un-comment the 'rm -rf' and let it rip.
Finally, I tested and modified the script for a few reasons. Firstly, I put the script itself in a folder that can ONLY be accessed by root, or any user would be able to modify the logout hook, which would be very bad. I logged in to root to do all of the work, so used the following command:
Add LogoutHook in Root:- defaults write com.apple.loginwindow LogoutHook /var/root/Library/Scripts/asmt1.sh
I added a few echo lines, some of which are to be removed once I un-comment the deletion lines, such as "Test Run". Others are just more info, such as "Script Completed". I also added a few lines to remove the contents of the /TEMP folder, which is where all files downloaded from the internet go. Following is the code of the adapted script, including lines commented out (and attached here asmt1a.sh):
asmt1a.sh:- #!/bin/bash
- echo "Test Run" >> /Library/Logs/acctDel.txt
- date >> /Library/Logs/acctDel.txt
- cd /Users
- for file in *; do
- if [ "$file" = administrator ]
- then
- echo "Administrator account NOT Deleted" >>
/Library/Logs/acctDel.txt
- echo "Administrator account NOT Deleted" >>
- else
- #rm -rf $file
- echo "User $file Deleted" >> /Library/Logs/acctDel.txt
- then
- fi
- done
- cd /TEMP
- #rm -rf *
- echo "TEMP folder emptied" >> /Library/Logs/acctDel.txt
- echo "Script completed." >> /Library/Logs/acctDel.txt
- echo "" >> /Library/Logs/acctDel.txt
After looking up the functions involved, I decided to do two small scripts for this assignment. The first script will force run the software updates on our macs every Friday in the middle of the night. This is much easier to implement than I thought it would be. The parts of it will be to write a short script to force software updates, then schedule it using launchd (which I found has mostly replaced cron on Mac OSX). It will have to run on root, as the software update function will only force an install from the root account.
Ok, back into testing this one. My first try was a bit of a disaster, but I have learned even more and am ready to go again. The script I wrote was absolutely simple as simple gets (also attached here):
sutest1.sh- #!/bin/bash
- softwareupdate -l
- echo "launch successful" >> /Library/Logs/SoftUpdate.txt
The -l tag is to list the updates. To implement the actual updates, the -i tag is for install, an additional -r tag is for required updates, and the -a tag is for all updates. After a test run on list, i will change it to -i -a.
The messy part of the implementation is the launchd application, which has replaced cron on Mac OS10.4 and up. I had to write a plist. Here is where I blame the mac developers website for being ambiguous. Moving on. Eventually I found that what I want to run should be in the /Library/LaunchDaemons folder (not the /System/Library/LaunchDaemons folder, which fried my computer). The Library LaunchDeamons are for periodic jobs as assigned by the administrator (me), but run in root. I copied and modified a plist from the mac developer site, but deleted it thoroughly when it broke my mac. So I copied a plist on my computer that was created for weekly maintenance and changed a few settings (linked here):
com.trial.weekly.plist- < ?xml version="1.0" encoding="UTF-8"? >
- < !DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" >
- < plist version="1.0" >
- < dict >
- < key > Label < /key >
- < string > com.trial.weekly < /string >
- < key > ProgramArguments < /key >
- < array >
- < string > /var/root/library/scripts/sutest1.sh < /string >
- < string > weekly < /string >
- < /array >
- < key > LowPriorityIO < /key >
- < true/ >
- < key > Nice < /key >
- < integer > 10 < /integer >
- < key > StartCalendarInterval < /key >
- < dict >
- < key > Hour < /key >
- < integer > 8 < /integer >
- < key > Minute < /key >
- < integer > 30 < /integer >
- < key > Weekday < /key >
- < integer > 5 < /integer >
- < /dict >
- < /dict >
- < /plist >
The label is the name of the file. The ProgramArguments is the script you want it to run. I again put the script in /var/root so that it could not be modified by anyone but root. The low priority IO is self explanatory, I left it as-is. The Nice level is like a priority of what should run first. I changed it to 10, the scale is -20 to 20, add the lower the number the higher the priority. I made it relatively high, as this is not very important to run. The StartCalendarInterval is the time that it should be run. I chose 8:30am on Fridays, but can change it to a time the lab is closed once it has tested ok.
After the mental scarring of frying my computer over assignment 2a, I moved on to complete 2b. This script is just a little one to replicate the action of copying the application support and preferences folders from the administrator account to the user template folder. This is to ensure that all new accounts look the same (and thanks to script 1 all users will be on new accounts) and start with the same customized settings. Since the script has to be run in root, it will be located in the root scripts folder created for assignment 1. My intent is to manually call the script when I need it, so it is basically only doing typing for me, but it will be used a lot, so I find it eminently worthwhile.
In copying the lines over from the Google Doc I currently reference, I made a few errors, so I got in a little bit of debugging. Firstly, the Google Doc was pre-formatted, so some of the characters did not translate and I had to find and replace them. Secondly, I must have deleted a backslash while fixing Firstly, so had to realize and fix that. Thirdly, I got to play around with double quotes, single quotes, and escaping spaces. There are four instances of a filename with a space in this script, so while trying to find Firstly and Secondly, I assumed one of these was giving me an error. The final script has escapes, which I noticed my terminal window uses when filling in filenames for me when I tab, so I figure it must like that best. The full script is below, and attached here.
userTempl.sh:- #!/bin/bash
- cd /users/administrator/library/preferences
- cp -R * /system/library/user\ template/english.lproj/library/preferences
- cd /users/administrator/library/application\ support
- cp -R * /system/library/user\ template/english.lproj/library/application\ support
I wanted to do a simple script first, and this one seemed simple, but I was wrong. I want to toggle the content of my notes page, so the content is manageable to read through. I want the default to be a list of the topics, and clicking on them will bring out the actual notes. I also want it to degrade gracefully, so the first function will hide the content on load (and browsers without Javascript will not hide anything) and the second function will toggle content on and off.
I want to site two pages I analyzed to get these functions working. First, I looked at my friend's code here (link removed) to see what she used, I used the .style.display='none' and 'block' from her code, as well as the idea of an if...else statement. Then, I used this site http://www.ozzu.com/ftopic39026.html to understand window.onload.
Step 1: First, I worked on getting the content to disappear on page load. I tried writing a function, then calling it in the body element as onload="hideId". That did not work, so I had to look around until I found window.onload="hideId", which lives in the script file and works just fine. The function I first wrote had two separate lines for the bash and javascript ids. I changed this much later, so will explain when I get there. I also realized that I had to create new divs if I wanted to hide and recall only certain sections, so I named them after the topics of the notes. This is what worked at step 1:
step1:- window.onload = hideId
- function hideId()
- {document.getElementById('bash').style.display='none'
- document.getElementById('javascript').style.display='none'}
Step 2: Once I got the divs to hide on page load, I moved on to making them toggle on and off. First, I made them toggle on by creating a function and only using it on the bash id. Then I decided that all of this specific scripting was a waste, so I made the function(x), and called out the ids in the span onclick="toggle(x)" where x is the div I was trying to toggle (bash or javascript).
step 2:- function toggle(x)
- {document.getElementById(x).style.display='block'}
Step 3: Then I realized that I would need the if...else statement my friend used if I wanted to be able to toggle back and forth. I wanted the else part to be to show the content (it has more possibilities to be true if something goes wrong), so I assigned the if statement to hide the content.
Step 4: Lastly, I changed the first function (hideId) to use an array, so It would be easy for me to add ids for future topics and not have to worry about typing it multiple times or writing out new lines of code. I also made small formatting changes towards the end. I changed the color of the topics to blue (so you would know there is something different about them), and I added a > next to the topic names, also trying to signify that you need to click on it. I also tested the script with javascript turned off on my browser, to ensure good degradation.
test1.sh:- window.onload = hideId
- function hideId()
- {var topics = new Array("bash", "javascript")
- for (y in topics)
- {document.getElementById(topics[y]).style.display='none'}}
- function toggle(x)
- {if(document.getElementById(x).style.display=='block')
- {document.getElementById(x).style.display='none'}
- else
- {document.getElementById(x).style.display='block'}}
This script is in effect on my notes page: Notes, and is linked here.
Other things I would like to do to make this all pretty is to change the topic id to a link to itself, so people would know it is clickable. Also, to make the tiny little triangle graphics and have them change from sideways to down appropriately.
I decided to try a script to switch the background dependent upon the available screen height or width. If the real estate of the screen is less than 1024X640, I want the background to have no image to ease the loading process of the site. In any oher situation, I want the background to load normally.
I figured out that I wanted a simple if statement, with no else. I also wanted the if statement to be triggered if the width is less than 1024 OR the height is less than 640. While I understood the syntax of the || to mean OR, it took me a while to get the right combination of parentheses to make it work.
I also realized that again I wanted the script to begin on page load, so I used the same onload function that I did last time: window.onload function()
I wanted the result of the if to change the background image to none if true. The syntax for that one was also a doozy, as it took me a while to figure out how to call the body, but it was a simple as using the term body (which I tried only after a lot of other things failed to work...). I also had background set to none, which wiped out my background color choice, so I changed it to backgroundImage (thanks to my Web Design textbook for telling me how to change background-image to backgroundImage).
My writing process here is somewhat backward. My actual testing process was to write something, fix it and move on. I put an alert into the result and changed my screen resolution to test whether I was doing absolutely everything wrong. That led me to comment out the document statement and the second half of the if statement. Which led to my figuring out how to correctly parentheses and space the if statement. Then I threw in a bunch of different terms to test the document statement. I swapped background for color (an attribute I was sure of) and #fff. I changed the document statement until I could see a change in the site. Then I swapped back to background and did not like the results, so used backgroundImage.
It has tested out on my Mac with Firefox. The w3schools website claims that the screen.availHeight and Width will work on IE as well, but I still have to test it out. Also, the .style should be cross-browser compatible (according to the Web Design text).
The site I used to test it out is here. The script is linked here. The code follows.
test2.js- window.onload = size
- function size()
- {if((screen.availHeight<640) || (screen.availWidth<1024))
- {document.body.style.backgroundImage = 'none';
- //alert('screen too small');
- }}
I decided to do a series of pages for one form, since that is something we are trying to work out for another project (but it looks like we will not use it, so I guess that just makes me curious). It seems using session is the best way to ensure data is not erased before the form is completed.
I split the form in question into 7 pages. Then I set the session using session_start at the beginning of each page before the header include (yep, I sure did try to put it somewhere else regardless of what my text told me to do. didn't work, but my curiosity is abated).
I defined each variable passed from the previous page as a session variable. I placed this chunk of php code just before the form on each page so that I could then echo both the passed variable and the session variable to ensure both are working ok.
session variables- < ? php
- $ _SESSION[ 'myname' ] = $ myname ;
- $ _SESSION[ 'email' ] = $ email ;
- $ _SESSION[ 'homework' ] = $ homework ;
- $ _SESSION[ 'hwonline' ] = $ hwonline ;
- $ _SESSION[ 'permission' ] = $ permission ;
- echo "
- < p > $ _SESSION[myname] $ myname $ _SESSION[email] $ email $ _SESSION[homework] $ homework $ _SESSION[hwonline] $ hwonline $ _SESSION[permission] $ permission < / p > " ;
- ? >
I ran into a bit of stupidity when I tried to run this off of my personal computer as a server. My computer would not store the variables (and I should have remembered that) so I spent quite a while spinning my wheels trying to figure that one out. Once I moved the files over to a real server the coding became simple to understand, and yet extremely time consuming due to the huge size of the form.
Once I had the variables passing to session variables on each page ok, I wanted to reset the session and the session variables any time someone uses the first page of the form. So I added in session_unset and session_destroy to remove all data from the session and close it down before someone tries to begin the form anew. Then I tested it.
unset and destroy- < ? php
- session_start();
- session_unset();
- session_destroy();
- include ('header.php');
- ? >
I also decided to add a 'Back' button to all of the middle pages (the first page can not use one, and the final page has already submitted all of the data) and to unset all session data for that page. I used the input button to create the button itself, and added a little javascript pirated from many places online to get the button to move back one page. Then I unset specifically those variables that would be created on that page. (Note that the javascript may not degrade gracefully, I can put some brainpower into that later.)
button- < input type = " button " value = " Back " onClick = " javascript:history.go(-1) " / >
unset
- < ? php
- session_start ( ) ;
- unset ( $ _SESSION[ 'title1' ], $ _SESSION[ 'author1' ], $ _SESSION[ 'book1' ], $ _SESSION[ 'bibliog1' ], $ _SESSION[ 'origin' ], $ _SESSION[ 'country' ], $ _SESSION[ 'time' ] ) ;
- include ( 'header.php' ) ;
- ? >
Lastly, I created an email to myself with all of the variables listed in it. Then I tested out every field in the form to ensure it passed and emailed correctly.
email- < ? php
- $ to="me@gmail.com";
- $ subject="an email from your INLS992test webform";
- $ message="Results of the webform:
- Name=$ _SESSION[myname]
- Email=$ _SESSION[email]
- etc...
- VideoPermission=$ _SESSION[vidPermiss]";
- $ headers="From: $ email";
- mail($ to,$ subject,$ message,$ headers);
- ? >
As the amount of code used is quite large, I did not post it here, I have only pulled small samples. The form is working here. Note that there is no validation whatsoever, I figure I can add that in for my next assignment. Source code is found here.
This week I wanted to do a little form validation and data cleaning. I of course spun in circles at the beginning, because I was not sure what to do, but towards the end it was just enjoyable debugging.
I began by creating an array of all of the variables in the form. If someone hijacks the address of the form, they will have to keep all of the variables exactly as I have created them. As the variable names themselves are hidden, the form becomes very hard to hack in this manner (especially with the length of the form). If the variables do not match exactly to mine, the form does absolutely nothing. (all totally negated by the fact that I am showing my source for the assignment)
I created an array named allowed and listed every single variable in it. I then created an array out of the post variable names by using array_keys on the post variable. Then I created an if statement so that the rest of the code only executes if the two array sets are exactly identical.
variable matching- $ allowed = array( 'title1' , 'author1', 'book1' , 'bibliog1' , 'origin' , 'country' , 'chara1' , 'emoC1' , 'emoA1' , 'emoA2' , 'emoA3' , 'time' , 'scenes' , 'synopsis' , 'flavor' , 'risks' , 'ageGroup' , 'devChar1' , 'devChar2' , 'devChar3' , 'howRel1' , 'howRel2' , 'howRel3' , 'title2' , 'author2' , 'book2' , 'bibliog2' , 'title3' , 'author3' , 'book3' , 'bibliog3' , 'compare' , 'vidPermiss' ) ;
- $ form = array _ keys ( $ _ POST ) ;
- if ( $ form === $ allowed ){
- / / execute further code }
I of course managed to have some problems with this step. It seems if neither of the radio buttons of the video question are selected, then the video variable did not pass at all. To put a temporary fix on this, I gave the radios a default with the checked option, with the hope of investigating this further in my spare time...
Next I wanted to do more than I ended up doing. I tried to make a foreach loop work with the variables to create error messages if a variable was not filled in. I eventually gave up on this idea when 1. it would not work 2. I already knew I wanted my error messages to be in more english than a loop could give me 3. not all of the variables were required. (although, I repeatedly used the foreach loop with the arrays to echo and debug with great success)
PS The fields that are not required are 'title of book/collection', 'country', and 'rhymes, special phrases, flavor'. Sometime in the future I will go back in to the form and put in cute little stars on everything else.
Basically I had three different types of fields. 1. Text input, required. 2. Text input, not required. 3. Drop-downs and radios. Each had its own problems.
'Text input, required' are all in the format of: if the field is empty, then echo asking for data. If not empty, then clean up the data using htmlentities so that someone can not inject code into a field and have it run on my server. When the data is cleaned, it is renamed with a clean suffix to notate its state. All future use of this data will be with the clean variable. All I did was echo it to prove it works, but I could do much more. My challenge here was that I used is_null in the if statement. That did not work. I also tried if the variable equals ''. Which did not work because I had the syntax wrong. I ended up using empty() because it worked.
Text field that is required- if ( empty ( $ title1 ) ) {
- echo " < p > Please fill in Title < / p > " ; }
- else {
- $ clean_title1 = htmlentities ( $ title1 ) ;
- echo " < p > Title is $ clean_title1 < / p > " ; }
'Text input, not required' did not have to have the echo asking for more info. So I changed the if empty statement to an if not empty statement and just had it clean the data and echo it. So if one of these is empty, nothing happens with that variable. This was the easiest one to debug. My problem here was that I was using a few things in the if statement or-ed together to see what worked. Once I figured out the one that did work, the others made things stop working, so I got rid of them.
Text field that is NOT required- if ( ! empty ( $ book1 ) ) {
- $ clean_book1 = htmlentities ( $ book1 ) ;
- echo " < p > Book is $ clean_book1 < / p > " ; }
Drop Downs and radio buttons created a bunch of errors. All of these were required, so they also had echo requests for more data. All of these had specific values for no data, 'none', so the if statement was different again. This time I used if the variable is equal to the string none, then echo for more info happens. Again, I do not want data that I have not specified going into this field, so I created an array of the options. I then checked the variable against the array, and if it is in the array, the data is considered cleaned. One problem was that I forgot to use = = instead of = in the if statement, messing up the form and giving me no output. Another problem was that I did not know a comma was required in the in_array (var, array) statement. I eventually found it!
Drop Downs and Radios- if ( $ origin = = 'none' ) {
- echo " < p > Please Select Geographic Origin < / p > " ; }
- else {
- $ origin_options = array ( 'Africa', 'Asia', 'Europe', 'LAm', 'MidEast', 'NatAm', 'NoAm', 'Oceania' ) ;
- if ( in_array ( $ origin, $ origin_options ) ) {
- $ clean_origin = ( $ origin ) ;
- echo " < p > Origin is $ clean_origin < / p > " ; } }
Since the code is so long again, I made a bunch of clerical errors and had to debug those as well. Nothing too time consuming, though. you may also notice that I chose to do this on one long form and not the chunked-up session form that I used last assignment. I did this to make my life easier. The code is long as-is, it would have taken even longer to write and figure out on multiple pages. The code is in effect on this page. The source is here.
Well, I tried to be fantastic and load MySQL onto my laptop. I did. It had problems connecting. Then I removed it and compiled it from source. It still had errors. After a few days of trying to figure it all out (seems Leopard has some required workarounds), I eventually deleted MySQL from my laptop because I was having some (non-related) problems. And then used the MySQL database that I requested from the school for this assignment anyway.
So I learned a few commands from my textbook to interface with MySQL on the command line and played around a bit. I added only one row of data to the tables from the command line because I wanted to build a form that would populate it. I created one row just to ensure I had set things up right.
(some commands I used and want to note: mysql -h -u -p, use Database;, create table Table ();, describe Table;, insert into Table values (,,); select Field from Table;.)
I changed my mind at the last minute and decided to make two tables instead of one. One table seems like a complete waste of a relational database. Not that I joined them or anything cool, but they could be used in tandem. I created a users table with fields of username, email, and student. The second table is named stories and consisted of an auto_increment primary key, title, author, book, and username. The username can be used as a foreign key to relate the two.
I had to do a little creative editing of my previous forms to get the one used for this assignment.
Once I had my fun tables set up and my form in shape, I could start my php. I used a lot of the same security as last assignment. All variables are in an array, and must match those returned or it will not process. All select or radio values must also match with arrays. All other post data must be cleaned with htmlentities before it goes anywhere. I got to use the email filter that I had hoped to use in assignment 6, which was exciting. It worked on my laptop as a server because I have php5, but stopped working on the school server, as that is php4. I tried using a regular expression to replace it (copied from friend), but was having problems with it and did not want to linger too much on this, as my assignment will take long enough without debugging a regular expression.
Per my textbook (I will admit thoroughly that I started off following the textbook closely for this assignment. It had very good explanations of the syntax to use both in mysql and php. Then I began mixing things up, and it no longer looks like anything found in the book, but I began with pure textbook.) I checked to see if magicquotes was set to ON on the school server. It was, so in order to use the mysql_real_escape_string (which is recommended to avoid sql injection attacks), I had to strip the slashes from the variables to avoid errors. The error I had here was trying to put this before I opened the connection to mysql. While it seems obvious to me now that you can not use mysql functions without calling mysql, it was very confusing at the time. Thank you php.net.
SQL data cleaning- if ( get _ magic _ quotes _ gpc ( ) ){
- $ clean _ title = stripslashes ( $ clean _ title ) ; }
- $ clean _ title = mysql _ real _ escape _ string ( $ clean _ title ) ;
Per my textbook again, I put all of my db login data in an include, to make it harder to hack, then called it all using variables. I also used the exact wording from the book to open the connection, select the db, and query the db. All of that is in the source file and my textbook, so I do not feel the need to repeat it here (especially since I was copying).
Originally I created code to insert data into the tables. I made two queries, one for each table. Each query inserted data to the table. It worked quite happily. Oddly enough I had far more trouble with getting data FROM the db, which I will discuss later.
Query for insert to db table- $ query1 = " insert into users values ( ' $ clean _ username ' , ' $ clean _ email ' , $ clean _ student ) " ;
- $ result1 = mysql _ query ( $ query1 ) ;
- if ( ! $ result1 ) {
- die ( " < p > Could not query1 the database : < / p > " . mysql _ error ( ) ) ; }
- else {
- echo " < p > User added < / p > " ; }
I ran this a few times over from the web form I created and was happy to see that it was populating data. I originally wanted to query the db to show the data that was populating as an output but later changed my mind. It caused errors at this point, so set it aside to make sure to ask whether it would work in php4. Running the data also made me realize that because username must be unique, it was blocking me when I tried to submit more than one story per username. That was not logical, so I decided to run a query and compare.
I will bounce into my problems with mysql_fetch_array here. I quite diligently copied the syntax from the text. It did not work. Then I made sure to find out if the syntax was the same for php4. It was. There were actually two things that held me back here. 1. I put a semicolon at the end of the while line, preventing the loop from looping. 2. I did not understand what the loop was doing exactly. I thought it was making an array out of the column I selected. But no my friend. It creates an array for each row of data. So if I select one column, it makes an array for each instance. The for loop runs a query on one row every time it loops. Thanks to http://www.tizag.com/mysqlTutorial/mysqlfetcharray.php for explaining this thoroughly. This was the one place my book fell short. Once I really understood what the query was doing, I wrote a neat little loop to move the data into the array I was looking for.
Select query and fetch loop- $ query0 = " select username from users " ;
- while ( $ array0 = mysql _ fetch _ array ( $ result0 , MYSQL _ ASSOC ) ) {
- echo $ array0 [ ' username ' ] ;
- $ newarray [ ] = $ array0 [ ' username ' ] ; }
On to the username issue. I decided to compare the username to the nice little array I just made by using the in_array function that I used in assignment 6. If the username already exists, then only the data for the stories table is entered. If the username does not exist yet, then data is entered into both tables. It all worked quite nicely once I ironed out my problems with the fetching data.
I decided not to output the data that was just input, because I fulfilled my requirement to select query the db with the username loop.
A note: I decided to nest the heck out of my if statements. My textbook did not do this, and I understand why: if the mysql functions kick up an error, the code stops, therefore everything after it can really only happen if the mysql statements are true. Yet for some reason my brain wanted me to nest. So I did. It's not wrong, just different...
In a real world, I would also make a loop to check that the same book and username combos were not happening. And I would put in validation of required fields, etc. And probably a bunch of other things.
The form can be found here and the source is here.
I had a lot of trouble with this assignment because I kept thinking of more efficient code in php for everything. It certainly seems like a lot of code for a little functionality. So I decided to go against my norm and try for something small and boring. Amazingly, this did not equate with easy. It also occurs to me that this unit would have been easier if I had done it right after JavaScript, but I suppose it is better for my failing memory to review things.
So I tried something out of The Ajax Bible with a little twist. I decided to use Ajax to check usernames against the database I created for assignment 7. I used code from the book for most of the js and severely trimmed down versions of the form and php from assignment 7.
The form began as an input box and a button. I eventually got rid of the button in lieu of something more exciting, such as onchange for the input field (which only works right now with a tab away or an enter...things to ponder later in life).
Form- < div id="oneleft" >
- < p > Please type in a Username < br / > and hit enter < /p >
- < p > < input id="uname" type="text" name="username" onchange="getData( 'ajaxPost.php', 'oneright', document.getElementById('uname').value )" / > < /p >
- < /div >
- < div id="oneright" >
- < p > text here < /p >
- < /div >
The Ajax was mostly taken form my textbook, which is probably why I was so alarmed when it would not work.
Javascript- var XMLHttpRequestObject = false;
- if (window.XMLHttpRequest) {
- XMLHttpRequestObject = new XMLHttpRequest(); }
- else if (window.ActiveXObject) {
- XMLHttpRequestObject = new ActiveXObject ("Microsoft.XMLHTTP"); }
- function getData(dataSource, divID, data) {
- if (XMLHttpRequestObject) {
- var obj = document.getElementById(divID);
- XMLHttpRequestObject.open( "POST", dataSource );
- XMLHttpRequestObject.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
- XMLHttpRequestObject.onreadystatechange = function() {
- if ( (XMLHttpRequestObject.readyState == 4) && (XMLHttpRequestObject.status == 200) ) {
- obj.innerHTML = XMLHttpRequestObject.responseText; } }
- if ( (XMLHttpRequestObject.readyState == 4) && (XMLHttpRequestObject.status == 200) ) {
- XMLHttpRequestObject.send("username=" + data); }
- else {
- var obj = document.getElementByID(divID);
- obj.innerHTML = "Ajax not supported"; } }
- if (XMLHttpRequestObject) {
The two problems I ran into were that 1. I used getElementByID instead of Id (thanks to Philip for spotting that one) and 2. I did not quite understand how to call the input from the text box (also thanks to Philip for correcting my ways there). I had a quite a bit of a problem debugging after I caught most of my tiny errors by plain scrutiny, but then I remembered Firefox can help. The book suggests using the Error Console in Firefox, and that made life much easier (echoing was not helping much).
The php is the same as the previous assignment minus query1 and query2, and it does not input to the database, it only queries.
It now occurs to me that this is actually a pretty cool example just because it has elements of Ajax, JavaScript, PHP, and MySQL in the code. Hmm.
If I get the chance tonight, I hope to install a third party Ajax tool (since it seems that is the majority of the Ajax use out there) and make sure I understand enough to make it work well.
The form is in use here, the script is linked here and the php source is here.
For this assignment, I have been wanting to create a slideshow in Flash. Kinda dumb, since you can do it in Ajax, but I figured it was a good place to start. As I went along, there were a lot of other things I wanted to try out, but there is only so much time in the day. I will have to table those things for later.
I downloaded a free trial of Flash for this assignment and mostly read the helpdocs which were a snore, but the videos linked into the helpdocs were fabulous.
I already have a set of 66 pictures I use on my portfolio which I imported into the Library. I fudged about with centering the images, and re-sizing the canvas to match the image size of 400X400px.
Originally, I pulled random images from the 66 and started slapping them together. Later, I decided to have a handful of flash galleries, so I organized the images into subject sets. I have future plans to create a show for each set, but for this assignment I finished the set named 'other', meaning they did not fit into the other sets. It was a good place to start because the images were varied and it was the smallest set.
I stumbled upon the Transition Menu Item and used it for all of the transitions. I changed the timing on them and eventually made them overlap. The timing of the whole set took time for me to figure out, not being very familiar with creating video.
I also spent a lot of time on cutting and pasting, removing frames, and modifying Keyframes (which is where you can tell pieces to start or stop).
Once I got a the movie to run the way I wanted it inside Flash, I figured out how to Publish the movie to a format I could use on the web: SWF. It also outputs a Javascript to determine what kind of Flsh player the client has, as well as an HTML page. I copied the relevant parts out of the HTML file into my php file, and left the js and swf as-is.
Once I had the show up and running, at a rate that did not offend me (and I had friends with PC try it), I decided to add one little bit of ActionScript. I realized that it would be better for me if I could spend an entire week on ActionScript alone, but the semester runs out. I did a lot of online research and found little help.
I ended up using an example from my book to get me started. I then pulled the functions out to the top of the script, which was somehow easier for me to parse (in my own brain). I tried using the frame as the object that the event was tied to, but this threw errors, so I reverted back to creating a symbol the size of the whole frame and calling it a button (which is what ALL of the online tutorials help with, buttons). That actually worked quite well upon testing.
The point of the ActionScript is to have the slideshow pause when the mouse is over it, then return to playing when the mouse is removed. Pretty simple...if you know ActionScript. myBackg is the name of the button. addEventListener is ActionScript 3's way of listening for an event to happen.
ActionScript- function mouseStop ( evt : MouseEvent ) : void {
- stop ( ) ; }
- function mouseGo ( evt : MouseEvent ) : void {
- play ( ) ; }
- myBackg . addEventListener ( MouseEvent . MOUSE_OVER , mouseStop ) ;
- myBackg . addEventListener ( MouseEvent . MOUSE_OUT , mouseGo ) ;
I wondered if the ActionScript would spit out in the js file or alter the html in any way. It didn't. It is built into the swf file.
The movie is in use here: http://staceylunden.com/photos.php. I did not write any of the code associated with the Flash file, so it is not included here.